Asterisk - The Open Source Telephony Project GIT-master-c7a8271
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->sig == SIG_FXOLS || p->sig == SIG_FXOKS || p->sig == SIG_FXOGS) {
9372 struct analog_pvt *analog_p = p->sig_pvt;
9373 if (analog_p->callwaitingdeluxepending) {
9374 unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), analog_p->flashtime);
9375 if (mssinceflash >= 1000) {
9376 /* Timer expired: the user hasn't yet selected an option. Take the default action and get on with it. */
9377 /* Note: If in the future Advanced Call Waiting Deluxe (*76) is supported, then as part of the
9378 * dialing code, we'll need to automatically invoke the preselected behavior about 2-3 seconds after
9379 * the call waiting begins (this allows for the SAS, CAS, and CWCID spill to be sent first).
9380 */
9381 analog_p->callwaitingdeluxepending = 0;
9382 analog_callwaiting_deluxe(analog_p, 0);
9383 }
9385 /* The user shouldn't hear anything after hook flashing, until a decision is made, by the user or when the timer expires. */
9386 ast_debug(5, "Dropping frame since Call Waiting Deluxe pending on %s\n", ast_channel_name(ast));
9387 return 0;
9388 }
9389 }
9390
9391 if (p->dialing) {
9393 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9394 ast_channel_name(ast));
9395 return 0;
9396 }
9397 if (!p->owner) {
9399 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9400 ast_channel_name(ast));
9401 return 0;
9402 }
9403 if (p->cidspill) {
9405 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9406 ast_channel_name(ast));
9407 return 0;
9408 }
9409
9411 if (!p->subs[idx].linear) {
9412 p->subs[idx].linear = 1;
9413 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9414 if (res)
9415 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
9416 }
9417 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
9420 /* x-law already */
9421 if (p->subs[idx].linear) {
9422 p->subs[idx].linear = 0;
9423 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9424 if (res)
9425 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
9426 }
9427 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
9428 } else {
9430 ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
9432 return -1;
9433 }
9435 if (res < 0) {
9436 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
9437 return -1;
9438 }
9439 return 0;
9440}
9441
9442static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
9443{
9444 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9445 int res=-1;
9446 int idx;
9447 int func = DAHDI_FLASH;
9448
9449 ast_mutex_lock(&p->lock);
9450 ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
9451 switch (p->sig) {
9452#if defined(HAVE_PRI)
9454 res = sig_pri_indicate(p->sig_pvt, chan, condition, data, datalen);
9456 return res;
9457#endif /* defined(HAVE_PRI) */
9458#if defined(HAVE_SS7)
9459 case SIG_SS7:
9460 res = sig_ss7_indicate(p->sig_pvt, chan, condition, data, datalen);
9462 return res;
9463#endif /* defined(HAVE_SS7) */
9464 default:
9465 break;
9466 }
9467#ifdef HAVE_OPENR2
9468 if (p->mfcr2 && !p->mfcr2_call_accepted) {
9470 /* if this is an R2 call and the call is not yet accepted, we don't want the
9471 tone indications to mess up with the MF tones */
9472 return 0;
9473 }
9474#endif
9475 idx = dahdi_get_index(chan, p, 0);
9476 if (idx == SUB_REAL) {
9477 switch (condition) {
9478 case AST_CONTROL_BUSY:
9479 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
9480 break;
9482 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
9483
9484 if (ast_channel_state(chan) != AST_STATE_UP) {
9485 if ((ast_channel_state(chan) != AST_STATE_RING) ||
9486 ((p->sig != SIG_FXSKS) &&
9487 (p->sig != SIG_FXSLS) &&
9488 (p->sig != SIG_FXSGS))) {
9489 /* We're playing audible ringback tone on the channel,
9490 * so set state to AST_STATE_RING, not AST_STATE_RINGING. */
9492 }
9493 }
9494 break;
9496 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan));
9497 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9498 res = 0;
9499 break;
9501 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan));
9502 /* don't continue in ast_indicate */
9503 res = 0;
9504 break;
9506 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan));
9507 /* don't continue in ast_indicate */
9508 res = 0;
9509 break;
9511 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9512 switch (ast_channel_hangupcause(chan)) {
9515 case 0:/* Cause has not been set. */
9516 /* Supply a more appropriate cause. */
9518 break;
9519 default:
9520 break;
9521 }
9522 break;
9523 case AST_CONTROL_HOLD:
9524 ast_moh_start(chan, data, p->mohinterpret);
9525 break;
9526 case AST_CONTROL_UNHOLD:
9527 ast_moh_stop(chan);
9528 break;
9530 if (p->radio)
9531 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
9532 res = 0;
9533 break;
9535 if (p->radio)
9536 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
9537 res = 0;
9538 break;
9539 case AST_CONTROL_FLASH:
9540 /* flash hookswitch */
9541 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
9542 /* Clear out the dial buffer */
9543 p->dop.dialstr[0] = '\0';
9544 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
9545 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
9546 ast_channel_name(chan), strerror(errno));
9547 } else
9548 res = 0;
9549 } else
9550 res = 0;
9551 break;
9553 res = 0;
9554 break;
9555 case -1:
9556 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
9557 break;
9558 }
9559 } else {
9560 res = 0;
9561 }
9563 return res;
9564}
9565
9566#if defined(HAVE_PRI)
9567static struct ast_str *create_channel_name(struct dahdi_pvt *i, int is_outgoing, char *address)
9568#else
9569static struct ast_str *create_channel_name(struct dahdi_pvt *i)
9570#endif /* defined(HAVE_PRI) */
9571{
9572 struct ast_str *chan_name;
9573 int x, y;
9574
9575 /* Create the new channel name tail. */
9576 if (!(chan_name = ast_str_create(32))) {
9577 return NULL;
9578 }
9579 if (i->channel == CHAN_PSEUDO) {
9580 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
9581#if defined(HAVE_PRI)
9582 } else if (i->pri) {
9583 ast_mutex_lock(&i->pri->lock);
9584 y = ++i->pri->new_chan_seq;
9585 if (is_outgoing) {
9586 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, address, (unsigned)y);
9587 address[0] = '\0';
9588 } else if (ast_strlen_zero(i->cid_subaddr)) {
9589 /* Put in caller-id number only since there is no subaddress. */
9590 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, i->cid_num, (unsigned)y);
9591 } else {
9592 /* Put in caller-id number and subaddress. */
9593 ast_str_set(&chan_name, 0, "i%d/%s:%s-%x", i->pri->span, i->cid_num,
9594 i->cid_subaddr, (unsigned)y);
9595 }
9596 ast_mutex_unlock(&i->pri->lock);
9597#endif /* defined(HAVE_PRI) */
9598 } else {
9599 y = 1;
9600 do {
9601 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
9602 for (x = 0; x < 3; ++x) {
9603 if (i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name),
9604 ast_channel_name(i->subs[x].owner) + 6)) {
9605 break;
9606 }
9607 }
9608 ++y;
9609 } while (x < 3);
9610 }
9611 return chan_name;
9612}
9613
9614static 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)
9615{
9616 struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
9617
9619
9620 return new_channel;
9621}
9622
9623static 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)
9624{
9625 struct ast_channel *tmp;
9626 struct ast_format_cap *caps;
9627 struct ast_format *deflaw;
9628 int x;
9629 int features;
9630 struct ast_str *chan_name;
9631 struct ast_variable *v;
9632 char *dashptr;
9633 char device_name[AST_CHANNEL_NAME];
9634
9635 if (i->subs[idx].owner) {
9636 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
9637 return NULL;
9638 }
9639
9640#if defined(HAVE_PRI)
9641 /*
9642 * The dnid has been stuffed with the called-number[:subaddress]
9643 * by dahdi_request() for outgoing calls.
9644 */
9645 chan_name = create_channel_name(i, i->outgoing, i->dnid);
9646#else
9647 chan_name = create_channel_name(i);
9648#endif /* defined(HAVE_PRI) */
9649 if (!chan_name) {
9650 return NULL;
9651 }
9652
9654 if (!caps) {
9655 ast_free(chan_name);
9656 return NULL;
9657 }
9658
9659 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));
9660 ast_free(chan_name);
9661 if (!tmp) {
9662 ao2_ref(caps, -1);
9663 return NULL;
9664 }
9665
9667
9668 if (callid) {
9669 ast_channel_callid_set(tmp, callid);
9670 }
9671
9673#if defined(HAVE_PRI)
9674 if (i->pri) {
9676 }
9677#endif /* defined(HAVE_PRI) */
9679 if (law) {
9680 i->law = law;
9681 if (law == DAHDI_LAW_ALAW) {
9682 deflaw = ast_format_alaw;
9683 } else {
9684 deflaw = ast_format_ulaw;
9685 }
9686 } else {
9687 switch (i->sig) {
9689 /* Make sure companding law is known. */
9690 i->law = (i->law_default == DAHDI_LAW_ALAW)
9691 ? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
9692 break;
9693 default:
9694 i->law = i->law_default;
9695 break;
9696 }
9697 if (i->law_default == DAHDI_LAW_ALAW) {
9698 deflaw = ast_format_alaw;
9699 } else {
9700 deflaw = ast_format_ulaw;
9701 }
9702 }
9703 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
9704 ast_format_cap_append(caps, deflaw, 0);
9706 ao2_ref(caps, -1);
9707 /* Start out assuming ulaw since it's smaller :) */
9708 ast_channel_set_rawreadformat(tmp, deflaw);
9709 ast_channel_set_readformat(tmp, deflaw);
9710 ast_channel_set_rawwriteformat(tmp, deflaw);
9711 ast_channel_set_writeformat(tmp, deflaw);
9712 i->subs[idx].linear = 0;
9713 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
9714 features = 0;
9715 if (idx == SUB_REAL) {
9716 if (i->busydetect && CANBUSYDETECT(i))
9717 features |= DSP_FEATURE_BUSY_DETECT;
9719 features |= DSP_FEATURE_CALL_PROGRESS;
9721 features |= DSP_FEATURE_WAITDIALTONE;
9722 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
9724 features |= DSP_FEATURE_FAX_DETECT;
9725 }
9726 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
9727 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
9728 i->hardwaredtmf = 0;
9729 features |= DSP_FEATURE_DIGIT_DETECT;
9730 } else if (NEED_MFDETECT(i)) {
9731 i->hardwaredtmf = 1;
9732 features |= DSP_FEATURE_DIGIT_DETECT;
9733 }
9734 }
9735 if (features) {
9736 if (i->dsp) {
9737 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp));
9738 } else {
9739 if (i->channel != CHAN_PSEUDO)
9740 i->dsp = ast_dsp_new();
9741 else
9742 i->dsp = NULL;
9743 if (i->dsp) {
9744 i->dsp_features = features;
9745#if defined(HAVE_PRI) || defined(HAVE_SS7)
9746 /* We cannot do progress detection until receive PROGRESS message */
9747 if (i->outgoing && (dahdi_sig_pri_lib_handles(i->sig) || (i->sig == SIG_SS7))) {
9748 /* Remember requested DSP features, don't treat
9749 talking as ANSWER */
9750 i->dsp_features = features & ~DSP_PROGRESS_TALK;
9751 features = 0;
9752 }
9753#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9754 ast_dsp_set_features(i->dsp, features);
9758 if (i->busydetect && CANBUSYDETECT(i)) {
9761 }
9762 }
9763 }
9764 }
9765
9767
9768 if (state == AST_STATE_RING)
9769 ast_channel_rings_set(tmp, 1);
9771 if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
9772 /* Only FXO signalled stuff can be picked up */
9777 }
9778 if (!ast_strlen_zero(i->parkinglot))
9779 ast_channel_parkinglot_set(tmp, i->parkinglot);
9780 if (!ast_strlen_zero(i->language))
9781 ast_channel_language_set(tmp, i->language);
9782 if (!i->owner)
9783 i->owner = tmp;
9785 ast_channel_accountcode_set(tmp, i->accountcode);
9786 if (i->amaflags)
9788 i->subs[idx].owner = tmp;
9790 if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
9791 ast_channel_call_forward_set(tmp, i->call_forward);
9792 }
9793 /* If we've been told "no ADSI" then enforce it */
9794 if (!i->adsi)
9796 if (!ast_strlen_zero(i->exten))
9798 if (!ast_strlen_zero(i->rdnis)) {
9801 }
9802 if (!ast_strlen_zero(i->dnid)) {
9804 }
9805
9806 /* Don't use ast_set_callerid() here because it will
9807 * generate a needless NewCallerID event */
9808#if defined(HAVE_PRI) || defined(HAVE_SS7)
9809 if (!ast_strlen_zero(i->cid_ani)) {
9811 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
9812 } else if (!ast_strlen_zero(i->cid_num)) {
9815 }
9816#else
9817 if (!ast_strlen_zero(i->cid_num)) {
9820 }
9821#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9825 ast_channel_caller(tmp)->ani2 = i->cid_ani2;
9827 /* clear the fake event in case we posted one before we had ast_channel */
9828 i->fake_event = 0;
9829 /* Assure there is no confmute on this channel */
9830 dahdi_confmute(i, 0);
9831 i->muting = 0;
9832 /* Configure the new channel jb */
9834
9835 /* Set initial device state */
9836 ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name));
9837 dashptr = strrchr(device_name, '-');
9838 if (dashptr) {
9839 *dashptr = '\0';
9840 }
9843
9844 for (v = i->vars ; v ; v = v->next)
9846
9848
9849 ast_channel_unlock(tmp);
9850
9852
9854 if (startpbx) {
9855#ifdef HAVE_OPENR2
9856 if (i->mfcr2call) {
9857 pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
9858 }
9859#endif
9860 if (ast_pbx_start(tmp)) {
9861 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
9862 ast_hangup(tmp);
9863 return NULL;
9864 }
9865 }
9866 return tmp;
9867}
9868
9869
9870static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
9871{
9872 char c;
9873
9874 *str = 0; /* start with empty output buffer */
9875 for (;;)
9876 {
9877 /* Wait for the first digit (up to specified ms). */
9878 c = ast_waitfordigit(chan, ms);
9879 /* if timeout, hangup or error, return as such */
9880 if (c < 1)
9881 return c;
9882 *str++ = c;
9883 *str = 0;
9884 if (strchr(term, c))
9885 return 1;
9886 }
9887}
9888
9889static int dahdi_wink(struct dahdi_pvt *p, int idx)
9890{
9891 int j;
9892 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
9893 for (;;)
9894 {
9895 /* set bits of interest */
9896 j = DAHDI_IOMUX_SIGEVENT;
9897 /* wait for some happening */
9898 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
9899 /* exit loop if we have it */
9900 if (j & DAHDI_IOMUX_SIGEVENT) break;
9901 }
9902 /* get the event info */
9903 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
9904 return 0;
9905}
9906
9907static void publish_dnd_state(int channel, const char *status)
9908{
9909 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
9910 RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
9911 if (!dahdichan) {
9912 return;
9913 }
9914
9915 ast_str_set(&dahdichan, 0, "%d", channel);
9916
9917 body = ast_json_pack("{s: s, s: s}",
9918 "DAHDIChannel", ast_str_buffer(dahdichan),
9919 "Status", status);
9920 if (!body) {
9921 return;
9922 }
9923
9925}
9926
9927/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9928 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9929 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9930 *
9931 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9932 * DAHDI channel). Use this to enable or disable it.
9933 *
9934 * \bug the use of the word "channel" for those dahdichans is really confusing.
9935 */
9936static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
9937{
9938 if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
9939 return analog_dnd(dahdichan->sig_pvt, flag);
9940 }
9941
9942 if (flag == -1) {
9943 return dahdichan->dnd;
9944 }
9945
9946 /* Do not disturb */
9947 dahdichan->dnd = flag;
9948 ast_verb(3, "%s DND on channel %d\n",
9949 flag? "Enabled" : "Disabled",
9950 dahdichan->channel);
9951 publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
9952 return 0;
9953}
9954
9955static int canmatch_featurecode(const char *pickupexten, const char *exten)
9956{
9957 int extlen = strlen(exten);
9958
9959 if (!extlen) {
9960 return 1;
9961 }
9962
9963 if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
9964 return 1;
9965 }
9966 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9967 if (exten[0] == '*' && extlen < 3) {
9968 if (extlen == 1) {
9969 return 1;
9970 }
9971 /* "*0" should be processed before it gets here */
9972 switch (exten[1]) {
9973 case '6':
9974 case '7':
9975 case '8':
9976 return 1;
9977 }
9978 }
9979 return 0;
9980}
9981
9982static void *analog_ss_thread(void *data)
9983{
9984 struct ast_channel *chan = data;
9985 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9986 char exten[AST_MAX_EXTENSION] = "";
9987 char exten2[AST_MAX_EXTENSION] = "";
9988 unsigned char buf[256];
9989 char dtmfcid[300];
9990 char dtmfbuf[300];
9991 struct callerid_state *cs = NULL;
9992 char *name = NULL, *number = NULL;
9993 int distMatches;
9994 int curRingData[3];
9995 int receivedRingT;
9996 int counter1;
9997 int counter;
9998 int samples = 0;
9999 struct ast_smdi_md_message *smdi_msg = NULL;
10000 int flags = 0;
10001 int i;
10002 int timeout;
10003 int getforward = 0;
10004 char *s1, *s2;
10005 int len = 0;
10006 int res;
10007 int idx;
10008 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
10009 const char *pickupexten;
10010
10014 /* in the bizarre case where the channel has become a zombie before we
10015 even get started here, abort safely
10016 */
10017 if (!p) {
10018 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
10019 ast_hangup(chan);
10020 goto quit;
10021 }
10022 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
10023 idx = dahdi_get_index(chan, p, 1);
10024 if (idx < 0) {
10025 ast_log(LOG_WARNING, "Huh?\n");
10026 ast_hangup(chan);
10027 goto quit;
10028 }
10029
10030 ast_channel_lock(chan);
10031 pickup_cfg = ast_get_chan_features_pickup_config(chan);
10032 if (!pickup_cfg) {
10033 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
10034 pickupexten = "";
10035 } else {
10036 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
10037 }
10038 ast_channel_unlock(chan);
10039
10040 if (p->dsp)
10042 switch (p->sig) {
10043 case SIG_FEATD:
10044 case SIG_FEATDMF:
10045 case SIG_FEATDMF_TA:
10046 case SIG_E911:
10047 case SIG_FGC_CAMAMF:
10048 case SIG_FEATB:
10049 case SIG_EMWINK:
10050 case SIG_SF_FEATD:
10051 case SIG_SF_FEATDMF:
10052 case SIG_SF_FEATB:
10053 case SIG_SFWINK:
10054 if (dahdi_wink(p, idx))
10055 goto quit;
10056 /* Fall through */
10057 case SIG_EM:
10058 case SIG_EM_E1:
10059 case SIG_SF:
10060 case SIG_FGC_CAMA:
10061 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10062 if (p->dsp)
10064 /* set digit mode appropriately */
10065 if (p->dsp) {
10066 if (NEED_MFDETECT(p))
10068 else
10070 }
10071 memset(dtmfbuf, 0, sizeof(dtmfbuf));
10072 /* Wait for the first digit only if immediate=no */
10073 if (!p->immediate)
10074 /* Wait for the first digit (up to 5 seconds). */
10075 res = ast_waitfordigit(chan, 5000);
10076 else
10077 res = 0;
10078 if (res > 0) {
10079 /* save first char */
10080 dtmfbuf[0] = res;
10081 switch (p->sig) {
10082 case SIG_FEATD:
10083 case SIG_SF_FEATD:
10084 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10085 if (res > 0)
10086 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10087 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10088 break;
10089 case SIG_FEATDMF_TA:
10090 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10091 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10092 if (dahdi_wink(p, idx)) goto quit;
10093 dtmfbuf[0] = 0;
10094 /* Wait for the first digit (up to 5 seconds). */
10095 res = ast_waitfordigit(chan, 5000);
10096 if (res <= 0) break;
10097 dtmfbuf[0] = res;
10098 /* fall through intentionally */
10099 case SIG_FEATDMF:
10100 case SIG_E911:
10101 case SIG_FGC_CAMAMF:
10102 case SIG_SF_FEATDMF:
10103 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10104 /* if international caca, do it again to get real ANO */
10105 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
10106 {
10107 if (dahdi_wink(p, idx)) goto quit;
10108 dtmfbuf[0] = 0;
10109 /* Wait for the first digit (up to 5 seconds). */
10110 res = ast_waitfordigit(chan, 5000);
10111 if (res <= 0) break;
10112 dtmfbuf[0] = res;
10113 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10114 }
10115 if (res > 0) {
10116 /* if E911, take off hook */
10117 if (p->sig == SIG_E911)
10118 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10119 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
10120 }
10121 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10122 break;
10123 case SIG_FEATB:
10124 case SIG_SF_FEATB:
10125 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10126 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10127 break;
10128 case SIG_EMWINK:
10129 /* if we received a '*', we are actually receiving Feature Group D
10130 dial syntax, so use that mode; otherwise, fall through to normal
10131 mode
10132 */
10133 if (res == '*') {
10134 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10135 if (res > 0)
10136 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10137 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10138 break;
10139 }
10140 default:
10141 /* If we got the first digit, get the rest */
10142 len = 1;
10143 dtmfbuf[len] = '\0';
10144 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10145 if (ast_exists_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10146 timeout = p->matchdigit_timeout;
10147 } else {
10148 timeout = p->interdigit_timeout;
10149 }
10150 res = ast_waitfordigit(chan, timeout);
10151 if (res < 0) {
10152 ast_debug(1, "waitfordigit returned < 0...\n");
10153 ast_hangup(chan);
10154 goto quit;
10155 } else if (res) {
10156 dtmfbuf[len++] = res;
10157 dtmfbuf[len] = '\0';
10158 } else {
10159 break;
10160 }
10161 }
10162 break;
10163 }
10164 }
10165 if (res == -1) {
10166 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
10167 ast_hangup(chan);
10168 goto quit;
10169 } else if (res < 0) {
10170 ast_debug(1, "Got hung up before digits finished\n");
10171 ast_hangup(chan);
10172 goto quit;
10173 }
10174
10175 if (p->sig == SIG_FGC_CAMA) {
10176 char anibuf[100];
10177
10178 if (ast_safe_sleep(chan,1000) == -1) {
10179 ast_hangup(chan);
10180 goto quit;
10181 }
10182 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10184 res = my_getsigstr(chan, anibuf, "#", 10000);
10185 if ((res > 0) && (strlen(anibuf) > 2)) {
10186 if (anibuf[strlen(anibuf) - 1] == '#')
10187 anibuf[strlen(anibuf) - 1] = 0;
10188 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
10189 }
10191 }
10192
10193 ast_copy_string(exten, dtmfbuf, sizeof(exten));
10194 if (ast_strlen_zero(exten))
10195 ast_copy_string(exten, "s", sizeof(exten));
10196 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
10197 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10198 if (exten[0] == '*') {
10199 char *stringp=NULL;
10200 ast_copy_string(exten2, exten, sizeof(exten2));
10201 /* Parse out extension and callerid */
10202 stringp=exten2 +1;
10203 s1 = strsep(&stringp, "*");
10204 s2 = strsep(&stringp, "*");
10205 if (s2) {
10206 if (!ast_strlen_zero(p->cid_num))
10207 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10208 else
10209 ast_set_callerid(chan, s1, NULL, s1);
10210 ast_copy_string(exten, s2, sizeof(exten));
10211 } else
10212 ast_copy_string(exten, s1, sizeof(exten));
10213 } else if (p->sig == SIG_FEATD)
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_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
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) {
10225 if (!ast_strlen_zero(p->cid_num))
10226 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10227 else
10228 if (*(s1 + 2))
10229 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
10230 ast_copy_string(exten, s2 + 1, sizeof(exten));
10231 } else
10232 ast_copy_string(exten, s1 + 2, sizeof(exten));
10233 } else
10234 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10235 }
10236 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
10237 if (exten[0] == '*') {
10238 char *stringp=NULL;
10239 ast_copy_string(exten2, exten, sizeof(exten2));
10240 /* Parse out extension and callerid */
10241 stringp=exten2 +1;
10242 s1 = strsep(&stringp, "#");
10243 s2 = strsep(&stringp, "#");
10244 if (s2 && (*(s2 + 1) == '0')) {
10245 if (*(s2 + 2))
10246 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
10247 }
10248 if (s1) ast_copy_string(exten, s1, sizeof(exten));
10249 else ast_copy_string(exten, "911", sizeof(exten));
10250 } else
10251 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
10252 }
10253 if (p->sig == SIG_FEATB) {
10254 if (exten[0] == '*') {
10255 char *stringp=NULL;
10256 ast_copy_string(exten2, exten, sizeof(exten2));
10257 /* Parse out extension and callerid */
10258 stringp=exten2 +1;
10259 s1 = strsep(&stringp, "#");
10260 ast_copy_string(exten, exten2 + 1, sizeof(exten));
10261 } else
10262 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
10263 }
10264 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10265 dahdi_wink(p, idx);
10266 /* some switches require a minimum guard time between
10267 the last FGD wink and something that answers
10268 immediately. This ensures it */
10269 if (ast_safe_sleep(chan, 100)) {
10270 ast_hangup(chan);
10271 goto quit;
10272 }
10273 }
10274 dahdi_ec_enable(p);
10275 if (NEED_MFDETECT(p)) {
10276 if (p->dsp) {
10277 if (!p->hardwaredtmf)
10279 else {
10280 ast_dsp_free(p->dsp);
10281 p->dsp = NULL;
10282 }
10283 }
10284 }
10285
10286 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
10287 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10288 ast_channel_exten_set(chan, exten);
10289 if (p->dsp) ast_dsp_digitreset(p->dsp);
10290 res = ast_pbx_run(chan);
10291 if (res) {
10292 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10293 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10294 }
10295 goto quit;
10296 } else {
10297 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, ast_channel_context(chan));
10298 sleep(2);
10299 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
10300 if (res < 0)
10301 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
10302 else
10303 sleep(1);
10304 res = ast_streamfile(chan, "ss-noservice", ast_channel_language(chan));
10305 if (res >= 0)
10306 ast_waitstream(chan, "");
10307 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10308 ast_hangup(chan);
10309 goto quit;
10310 }
10311 break;
10312 case SIG_FXOLS:
10313 case SIG_FXOGS:
10314 case SIG_FXOKS:
10315 /* Read the first digit */
10316 timeout = p->firstdigit_timeout;
10317 /* If starting a threeway call, never timeout on the first digit so someone
10318 can use flash-hook as a "hold" feature */
10319 if (p->subs[SUB_THREEWAY].owner)
10320 timeout = INT_MAX;
10321 while (len < AST_MAX_EXTENSION-1) {
10322 int is_exten_parking = 0;
10323
10324 /* Read digit unless it's supposed to be immediate, in which case the
10325 only answer is 's' */
10326 if (p->immediate)
10327 res = 's';
10328 else
10329 res = ast_waitfordigit(chan, timeout);
10330 timeout = 0;
10331 if (res < 0) {
10332 ast_debug(1, "waitfordigit returned < 0...\n");
10333 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10334 ast_hangup(chan);
10335 goto quit;
10336 } else if (res) {
10337 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
10338 exten[len++]=res;
10339 exten[len] = '\0';
10340 }
10341 if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
10342 tone_zone_play_tone(p->subs[idx].dfd, -1);
10343 } else {
10344 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10345 }
10347 is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
10348 }
10349 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
10350 if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
10351 if (getforward) {
10352 /* Record this as the forwarding extension */
10353 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
10354 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
10355 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10356 if (res)
10357 break;
10358 usleep(500000);
10359 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10360 sleep(1);
10361 memset(exten, 0, sizeof(exten));
10362 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10363 len = 0;
10364 getforward = 0;
10365 } else {
10366 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10367 ast_channel_lock(chan);
10368 ast_channel_exten_set(chan, exten);
10369 if (!ast_strlen_zero(p->cid_num)) {
10370 if (!p->hidecallerid)
10371 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10372 else
10373 ast_set_callerid(chan, NULL, NULL, p->cid_num);
10374 }
10375 if (!ast_strlen_zero(p->cid_name)) {
10376 if (!p->hidecallerid)
10377 ast_set_callerid(chan, NULL, p->cid_name, NULL);
10378 }
10380 ast_channel_unlock(chan);
10381 dahdi_ec_enable(p);
10382 res = ast_pbx_run(chan);
10383 if (res) {
10384 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10385 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10386 }
10387 goto quit;
10388 }
10389 } else {
10390 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10391 so just set the timeout to matchdigit_timeout and wait some more */
10392 timeout = p->matchdigit_timeout;
10393 }
10394 } else if (res == 0) {
10395 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10396 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10397 dahdi_wait_event(p->subs[idx].dfd);
10398 ast_hangup(chan);
10399 goto quit;
10400 } else if (p->callwaiting && !strcmp(exten, "*70")) {
10401 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
10402 /* Disable call waiting if enabled */
10403 p->callwaiting = 0;
10404 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10405 if (res) {
10406 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10407 ast_channel_name(chan), strerror(errno));
10408 }
10409 len = 0;
10410 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
10411 memset(exten, 0, sizeof(exten));
10412 timeout = p->firstdigit_timeout;
10413
10414 } else if (!strcmp(exten, pickupexten)) {
10415 /* Scan all channels and see if there are any
10416 * ringing channels that have call groups
10417 * that equal this channels pickup group
10418 */
10419 if (idx == SUB_REAL) {
10420 /* Switch us from Third call to Call Wait */
10421 if (p->subs[SUB_THREEWAY].owner) {
10422 /* If you make a threeway call and the *8# a call, it should actually
10423 look like a callwait */
10427 }
10428 dahdi_ec_enable(p);
10429 if (ast_pickup_call(chan)) {
10430 ast_debug(1, "No call pickup possible...\n");
10431 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10432 dahdi_wait_event(p->subs[idx].dfd);
10433 }
10434 ast_hangup(chan);
10435 goto quit;
10436 } else {
10437 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
10438 ast_hangup(chan);
10439 goto quit;
10440 }
10441
10442 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
10443 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
10444 /* Disable Caller*ID if enabled */
10445 p->hidecallerid = 1;
10450 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10451 if (res) {
10452 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10453 ast_channel_name(chan), strerror(errno));
10454 }
10455 len = 0;
10456 memset(exten, 0, sizeof(exten));
10457 timeout = p->firstdigit_timeout;
10458 } else if (p->callreturn && !strcmp(exten, "*69")) {
10459 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10460 break;
10461 } else if (!strcmp(exten, "*78")) {
10462 dahdi_dnd(p, 1);
10463 /* Do not disturb */
10464 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10465 getforward = 0;
10466 memset(exten, 0, sizeof(exten));
10467 len = 0;
10468 } else if (!strcmp(exten, "*79")) {
10469 dahdi_dnd(p, 0);
10470 /* Do not disturb */
10471 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10472 getforward = 0;
10473 memset(exten, 0, sizeof(exten));
10474 len = 0;
10475 } else if (p->cancallforward && !strcmp(exten, "*72")) {
10476 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10477 getforward = 1;
10478 memset(exten, 0, sizeof(exten));
10479 len = 0;
10480 } else if (p->cancallforward && !strcmp(exten, "*73")) {
10481 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
10482 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10483 memset(p->call_forward, 0, sizeof(p->call_forward));
10484 getforward = 0;
10485 memset(exten, 0, sizeof(exten));
10486 len = 0;
10487 } else if ((p->transfer || p->canpark) && is_exten_parking
10488 && p->subs[SUB_THREEWAY].owner) {
10489 struct ast_bridge_channel *bridge_channel;
10490
10491 /*
10492 * This is a three way call, the main call being a real channel,
10493 * and we're parking the first call.
10494 */
10498 if (bridge_channel) {
10499 if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
10500 /*
10501 * Swap things around between the three-way and real call so we
10502 * can hear where the channel got parked.
10503 */
10504 ast_mutex_lock(&p->lock);
10505 p->owner = p->subs[SUB_THREEWAY].owner;
10508
10509 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
10511 ao2_ref(bridge_channel, -1);
10512 goto quit;
10513 }
10514 ao2_ref(bridge_channel, -1);
10515 }
10516 break;
10517 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
10518 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
10519 /* Enable Caller*ID if enabled */
10520 p->hidecallerid = 0;
10522 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10523 if (res) {
10524 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10525 ast_channel_name(chan), strerror(errno));
10526 }
10527 len = 0;
10528 memset(exten, 0, sizeof(exten));
10529 timeout = p->firstdigit_timeout;
10530 } else if (!strcmp(exten, "*0")) {
10531 struct ast_channel *nbridge =
10533 struct dahdi_pvt *pbridge = NULL;
10534 RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
10535
10536 /* set up the private struct of the bridged one, if any */
10537 if (nbridge && bridged) {
10538 pbridge = ast_channel_tech_pvt(bridged);
10539 }
10540 if (nbridge && pbridge &&
10541 (ast_channel_tech(nbridge) == &dahdi_tech) &&
10542 (ast_channel_tech(bridged) == &dahdi_tech) &&
10543 ISTRUNK(pbridge)) {
10544 int func = DAHDI_FLASH;
10545 /* Clear out the dial buffer */
10546 p->dop.dialstr[0] = '\0';
10547 /* flash hookswitch */
10548 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
10549 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
10550 ast_channel_name(nbridge), strerror(errno));
10551 }
10554 p->owner = p->subs[SUB_REAL].owner;
10556 ast_hangup(chan);
10557 goto quit;
10558 } else {
10559 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10560 dahdi_wait_event(p->subs[idx].dfd);
10561 tone_zone_play_tone(p->subs[idx].dfd, -1);
10564 p->owner = p->subs[SUB_REAL].owner;
10565 ast_hangup(chan);
10566 goto quit;
10567 }
10568 } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
10569 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
10570 && !canmatch_featurecode(pickupexten, exten)) {
10571 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
10572 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
10573 ast_channel_context(chan));
10574 break;
10575 }
10576 if (!timeout)
10577 timeout = p->interdigit_timeout;
10579 tone_zone_play_tone(p->subs[idx].dfd, -1);
10580 }
10581 break;
10582 case SIG_FXSLS:
10583 case SIG_FXSGS:
10584 case SIG_FXSKS:
10585 /* check for SMDI messages */
10586 if (p->use_smdi && p->smdi_iface) {
10588
10589 if (smdi_msg != NULL) {
10590 ast_channel_exten_set(chan, smdi_msg->fwd_st);
10591
10592 if (smdi_msg->type == 'B')
10593 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
10594 else if (smdi_msg->type == 'N')
10595 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
10596
10597 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan));
10598 } else {
10599 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
10600 }
10601 }
10602
10603 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
10604 number = smdi_msg->calling_st;
10605
10606 /* If we want caller id, we're in a prering state due to a polarity reversal
10607 * and we're set to use a polarity reversal to trigger the start of caller id,
10608 * grab the caller id and wait for ringing to start... */
10609 } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
10611 /* If set to use DTMF CID signalling, listen for DTMF */
10612 if (p->cid_signalling == CID_SIG_DTMF) {
10613 int k = 0;
10614 int off_ms;
10615 struct timeval start = ast_tvnow();
10616 int ms;
10617 cs = NULL;
10618 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
10619 dahdi_setlinear(p->subs[idx].dfd, 0);
10620 /*
10621 * We are the only party interested in the Rx stream since
10622 * we have not answered yet. We don't need or even want DTMF
10623 * emulation. The DTMF digits can come so fast that emulation
10624 * can drop some of them.
10625 */
10626 ast_channel_lock(chan);
10628 ast_channel_unlock(chan);
10629 off_ms = 4000;/* This is a typical OFF time between rings. */
10630 for (;;) {
10631 struct ast_frame *f;
10632
10633 ms = ast_remaining_ms(start, off_ms);
10634 res = ast_waitfor(chan, ms);
10635 if (res <= 0) {
10636 /*
10637 * We do not need to restore the dahdi_setlinear()
10638 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10639 * are hanging up the channel.
10640 */
10641 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10642 "Exiting simple switch\n");
10643 ast_hangup(chan);
10644 goto quit;
10645 }
10646 f = ast_read(chan);
10647 if (!f)
10648 break;
10649 if (f->frametype == AST_FRAME_DTMF) {
10650 if (k < ARRAY_LEN(dtmfbuf) - 1) {
10651 dtmfbuf[k++] = f->subclass.integer;
10652 }
10653 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10654 start = ast_tvnow();
10655 }
10656 ast_frfree(f);
10657 if (ast_channel_state(chan) == AST_STATE_RING ||
10659 break; /* Got ring */
10660 }
10661 ast_channel_lock(chan);
10663 ast_channel_unlock(chan);
10664 dtmfbuf[k] = '\0';
10665 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10666 /* Got cid and ring. */
10667 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
10668 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10669 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid, flags);
10670 /* If first byte is NULL, we have no cid */
10671 if (!ast_strlen_zero(dtmfcid))
10672 number = dtmfcid;
10673 else
10674 number = NULL;
10675 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10676 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
10678 if (cs) {
10679 int off_ms;
10680 struct timeval start;
10681 int ms;
10682 samples = 0;
10683#if 1
10684 bump_gains(p);
10685#endif
10686 /* Take out of linear mode for Caller*ID processing */
10687 dahdi_setlinear(p->subs[idx].dfd, 0);
10688
10689 /* First we wait and listen for the Caller*ID */
10690 for (;;) {
10691 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10692 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10693 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10694 callerid_free(cs);
10695 ast_hangup(chan);
10696 goto quit;
10697 }
10698 if (i & DAHDI_IOMUX_SIGEVENT) {
10699 res = dahdi_get_event(p->subs[idx].dfd);
10700 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10701 if (res == DAHDI_EVENT_NOALARM) {
10702 p->inalarm = 0;
10703 }
10704
10705 if (p->cid_signalling == CID_SIG_V23_JP) {
10706 if (res == DAHDI_EVENT_RINGBEGIN) {
10707 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10708 usleep(1);
10709 }
10710 } else {
10711 res = 0;
10712 break;
10713 }
10714 } else if (i & DAHDI_IOMUX_READ) {
10715 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10716 if (res < 0) {
10717 if (errno != ELAST) {
10718 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10719 callerid_free(cs);
10720 ast_hangup(chan);
10721 goto quit;
10722 }
10723 break;
10724 }
10725 samples += res;
10726
10727 if (p->cid_signalling == CID_SIG_V23_JP) {
10728 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
10729 } else {
10730 res = callerid_feed(cs, buf, res, AST_LAW(p));
10731 }
10732 if (res < 0) {
10733 /*
10734 * The previous diagnostic message output likely
10735 * explains why it failed.
10736 */
10738 "Failed to decode CallerID on channel '%s'\n",
10739 ast_channel_name(chan));
10740 break;
10741 } else if (res)
10742 break;
10743 else if (samples > (8000 * 10))
10744 break;
10745 }
10746 }
10747 if (res == 1) {
10748 callerid_get(cs, &name, &number, &flags);
10749 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
10750 }
10751
10752 if (p->cid_signalling == CID_SIG_V23_JP) {
10753 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
10754 usleep(1);
10755 }
10756
10757 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10758 start = ast_tvnow();
10759 off_ms = 4000;/* This is a typical OFF time between rings. */
10760 for (;;) {
10761 struct ast_frame *f;
10762
10763 ms = ast_remaining_ms(start, off_ms);
10764 res = ast_waitfor(chan, ms);
10765 if (res <= 0) {
10766 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
10767 "Exiting simple switch\n");
10768 ast_hangup(chan);
10769 goto quit;
10770 }
10771 if (!(f = ast_read(chan))) {
10772 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
10773 ast_hangup(chan);
10774 goto quit;
10775 }
10776 ast_frfree(f);
10777 if (ast_channel_state(chan) == AST_STATE_RING ||
10779 break; /* Got ring */
10780 }
10781
10782 /* We must have a ring by now, so, if configured, lets try to listen for
10783 * distinctive ringing */
10785 len = 0;
10786 distMatches = 0;
10787 /* Clear the current ring data array so we don't have old data in it. */
10788 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10789 curRingData[receivedRingT] = 0;
10790 receivedRingT = 0;
10791 counter = 0;
10792 counter1 = 0;
10793 /* Check to see if context is what it should be, if not set to be. */
10794 if (strcmp(p->context,p->defcontext) != 0) {
10795 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10797 }
10798
10799 for (;;) {
10800 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10801 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10802 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10803 callerid_free(cs);
10804 ast_hangup(chan);
10805 goto quit;
10806 }
10807 if (i & DAHDI_IOMUX_SIGEVENT) {
10808 res = dahdi_get_event(p->subs[idx].dfd);
10809 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10810 if (res == DAHDI_EVENT_NOALARM) {
10811 p->inalarm = 0;
10812 }
10813 res = 0;
10814 /* Let us detect distinctive ring */
10815
10816 curRingData[receivedRingT] = p->ringt;
10817
10818 if (p->ringt < p->ringt_base/2)
10819 break;
10820 /* Increment the ringT counter so we can match it against
10821 values in chan_dahdi.conf for distinctive ring */
10822 if (++receivedRingT == ARRAY_LEN(curRingData))
10823 break;
10824 } else if (i & DAHDI_IOMUX_READ) {
10825 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10826 if (res < 0) {
10827 if (errno != ELAST) {
10828 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10829 callerid_free(cs);
10830 ast_hangup(chan);
10831 goto quit;
10832 }
10833 break;
10834 }
10835 if (p->ringt > 0) {
10836 if (!(--p->ringt)) {
10837 res = -1;
10838 break;
10839 }
10840 }
10841 }
10842 }
10843 /* this only shows up if you have n of the dring patterns filled in */
10844 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
10845 for (counter = 0; counter < 3; counter++) {
10846 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10847 channel */
10848 distMatches = 0;
10849 for (counter1 = 0; counter1 < 3; counter1++) {
10850 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
10851 if (p->drings.ringnum[counter].ring[counter1] == -1) {
10852 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10853 curRingData[counter1]);
10854 distMatches++;
10855 } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
10856 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
10857 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10858 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
10859 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
10860 distMatches++;
10861 }
10862 }
10863
10864 if (distMatches == 3) {
10865 /* The ring matches, set the context to whatever is for distinctive ring.. */
10866 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
10868 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
10869 break;
10870 }
10871 }
10872 }
10873 /* Restore linear mode (if appropriate) for Caller*ID processing */
10874 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10875#if 1
10876 restore_gains(p);
10877#endif
10878 } else
10879 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
10880 } else {
10881 ast_log(LOG_WARNING, "Channel %s in prering "
10882 "state, but I have nothing to do. "
10883 "Terminating simple switch, should be "
10884 "restarted by the actual ring.\n",
10885 ast_channel_name(chan));
10886 ast_hangup(chan);
10887 goto quit;
10888 }
10889 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
10890 if (p->cid_signalling == CID_SIG_DTMF) {
10891 int k = 0;
10892 int off_ms;
10893 struct timeval start;
10894 int ms;
10895 cs = NULL;
10896 dahdi_setlinear(p->subs[idx].dfd, 0);
10897 off_ms = 2000;
10898 start = ast_tvnow();
10899 for (;;) {
10900 struct ast_frame *f;
10901
10902 ms = ast_remaining_ms(start, off_ms);
10903 res = ast_waitfor(chan, ms);
10904 if (res <= 0) {
10905 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10906 "Exiting simple switch\n");
10907 ast_hangup(chan);
10908 goto quit;
10909 }
10910 f = ast_read(chan);
10911 if (!f) {
10912 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10913 ast_hangup(chan);
10914 goto quit;
10915 }
10916 if (f->frametype == AST_FRAME_DTMF) {
10917 dtmfbuf[k++] = f->subclass.integer;
10918 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10919 start = ast_tvnow();
10920 }
10921 ast_frfree(f);
10922
10923 if (p->ringt_base == p->ringt)
10924 break;
10925 }
10926 dtmfbuf[k] = '\0';
10927 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10928 /* Got cid and ring. */
10929 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10930 ast_debug(1, "CID is '%s', flags %d\n",
10931 dtmfcid, flags);
10932 /* If first byte is NULL, we have no cid */
10933 if (!ast_strlen_zero(dtmfcid))
10934 number = dtmfcid;
10935 else
10936 number = NULL;
10937 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10938 } else {
10939 /* FSK Bell202 callerID */
10941 if (cs) {
10942#if 1
10943 bump_gains(p);
10944#endif
10945 samples = 0;
10946 len = 0;
10947 distMatches = 0;
10948 /* Clear the current ring data array so we don't have old data in it. */
10949 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10950 curRingData[receivedRingT] = 0;
10951 receivedRingT = 0;
10952 counter = 0;
10953 counter1 = 0;
10954 /* Check to see if context is what it should be, if not set to be. */
10955 if (strcmp(p->context,p->defcontext) != 0) {
10956 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10958 }
10959
10960 /* Take out of linear mode for Caller*ID processing */
10961 dahdi_setlinear(p->subs[idx].dfd, 0);
10962 for (;;) {
10963 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10964 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10965 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10966 callerid_free(cs);
10967 ast_hangup(chan);
10968 goto quit;
10969 }
10970 if (i & DAHDI_IOMUX_SIGEVENT) {
10971 res = dahdi_get_event(p->subs[idx].dfd);
10972 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10973 if (res == DAHDI_EVENT_NOALARM) {
10974 p->inalarm = 0;
10975 }
10976 /* If we get a PR event, they hung up while processing calerid */
10977 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
10978 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
10980 callerid_free(cs);
10981 ast_hangup(chan);
10982 goto quit;
10983 }
10984 res = 0;
10985 /* Let us detect callerid when the telco uses distinctive ring */
10986
10987 curRingData[receivedRingT] = p->ringt;
10988
10989 if (p->ringt < p->ringt_base/2)
10990 break;
10991 /* Increment the ringT counter so we can match it against
10992 values in chan_dahdi.conf for distinctive ring */
10993 if (++receivedRingT == ARRAY_LEN(curRingData))
10994 break;
10995 } else if (i & DAHDI_IOMUX_READ) {
10996 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10997 if (res < 0) {
10998 if (errno != ELAST) {
10999 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11000 callerid_free(cs);
11001 ast_hangup(chan);
11002 goto quit;
11003 }
11004 break;
11005 }
11006 if (p->ringt > 0) {
11007 if (!(--p->ringt)) {
11008 res = -1;
11009 break;
11010 }
11011 }
11012 samples += res;
11013 res = callerid_feed(cs, buf, res, AST_LAW(p));
11014 if (res < 0) {
11015 /*
11016 * The previous diagnostic message output likely
11017 * explains why it failed.
11018 */
11020 "Failed to decode CallerID on channel '%s'\n",
11021 ast_channel_name(chan));
11022 break;
11023 } else if (res)
11024 break;
11025 else if (samples > (8000 * 10))
11026 break;
11027 }
11028 }
11029 if (res == 1) {
11030 callerid_get(cs, &name, &number, &flags);
11031 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
11032 }
11033 if (distinctiveringaftercid == 1) {
11034 /* Clear the current ring data array so we don't have old data in it. */
11035 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
11036 curRingData[receivedRingT] = 0;
11037 }
11038 receivedRingT = 0;
11039 ast_verb(3, "Detecting post-CID distinctive ring\n");
11040 for (;;) {
11041 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11042 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
11043 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11044 callerid_free(cs);
11045 ast_hangup(chan);
11046 goto quit;
11047 }
11048 if (i & DAHDI_IOMUX_SIGEVENT) {
11049 res = dahdi_get_event(p->subs[idx].dfd);
11050 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
11051 if (res == DAHDI_EVENT_NOALARM) {
11052 p->inalarm = 0;
11053 }
11054 res = 0;
11055 /* Let us detect callerid when the telco uses distinctive ring */
11056
11057 curRingData[receivedRingT] = p->ringt;
11058
11059 if (p->ringt < p->ringt_base/2)
11060 break;
11061 /* Increment the ringT counter so we can match it against
11062 values in chan_dahdi.conf for distinctive ring */
11063 if (++receivedRingT == ARRAY_LEN(curRingData))
11064 break;
11065 } else if (i & DAHDI_IOMUX_READ) {
11066 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11067 if (res < 0) {
11068 if (errno != ELAST) {
11069 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11070 callerid_free(cs);
11071 ast_hangup(chan);
11072 goto quit;
11073 }
11074 break;
11075 }
11076 if (p->ringt > 0) {
11077 if (!(--p->ringt)) {
11078 res = -1;
11079 break;
11080 }
11081 }
11082 }
11083 }
11084 }
11086 /* this only shows up if you have n of the dring patterns filled in */
11087 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
11088
11089 for (counter = 0; counter < 3; counter++) {
11090 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
11091 channel */
11092 /* this only shows up if you have n of the dring patterns filled in */
11093 ast_verb(3, "Checking %d,%d,%d\n",
11094 p->drings.ringnum[counter].ring[0],
11095 p->drings.ringnum[counter].ring[1],
11096 p->drings.ringnum[counter].ring[2]);
11097 distMatches = 0;
11098 for (counter1 = 0; counter1 < 3; counter1++) {
11099 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
11100 if (p->drings.ringnum[counter].ring[counter1] == -1) {
11101 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
11102 curRingData[counter1]);
11103 distMatches++;
11104 }
11105 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
11106 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
11107 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
11108 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
11109 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
11110 distMatches++;
11111 }
11112 }
11113 if (distMatches == 3) {
11114 /* The ring matches, set the context to whatever is for distinctive ring.. */
11115 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
11117 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
11118 break;
11119 }
11120 }
11121 }
11122 /* Restore linear mode (if appropriate) for Caller*ID processing */
11123 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
11124#if 1
11125 restore_gains(p);
11126#endif
11127 if (res < 0) {
11128 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
11129 }
11130 } else
11131 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
11132 }
11133 } else
11134 cs = NULL;
11135
11136 if (number)
11139
11140 ao2_cleanup(smdi_msg);
11141
11142 if (cs)
11143 callerid_free(cs);
11144
11145 my_handle_notify_message(chan, p, flags, -1);
11146
11147 ast_channel_lock(chan);
11149 ast_channel_rings_set(chan, 1);
11150 ast_channel_unlock(chan);
11151 p->ringt = p->ringt_base;
11152 res = ast_pbx_run(chan);
11153 if (res) {
11154 ast_hangup(chan);
11155 ast_log(LOG_WARNING, "PBX exited non-zero\n");
11156 }
11157 goto quit;
11158 default:
11159 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
11160 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11161 if (res < 0)
11162 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11163 }
11164 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11165 if (res < 0)
11166 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11167 ast_hangup(chan);
11168quit:
11173 return NULL;
11174}
11175
11178 unsigned char buf[READ_SIZE];
11179 size_t len;
11180};
11181
11182static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
11183{
11184 int x;
11185 int sum = 0;
11186
11187 if (!len)
11188 return 0;
11189
11190 for (x = 0; x < len; x++)
11191 sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
11192
11193 return sum / len;
11194}
11195
11196static void *mwi_thread(void *data)
11197{
11198 struct mwi_thread_data *mtd = data;
11199 struct callerid_state *cs;
11200 pthread_t threadid;
11201 int samples = 0;
11202 char *name, *number;
11203 int flags;
11204 int i, res;
11205 unsigned int spill_done = 0;
11206 int spill_result = -1;
11207
11208 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
11209 goto quit_no_clean;
11210 }
11211
11212 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
11213
11214 bump_gains(mtd->pvt);
11215
11216 for (;;) {
11217 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11218 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
11219 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11220 goto quit;
11221 }
11222
11223 if (i & DAHDI_IOMUX_SIGEVENT) {
11224 struct ast_channel *chan;
11225 ast_callid callid = 0;
11226 int callid_created;
11227
11228 /* If we get an event, screen out events that we do not act on.
11229 * Otherwise, cancel and go to the simple switch to let it deal with it.
11230 */
11231 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
11232
11233 switch (res) {
11234 case DAHDI_EVENT_NEONMWI_ACTIVE:
11235 case DAHDI_EVENT_NEONMWI_INACTIVE:
11236 case DAHDI_EVENT_NONE:
11237 case DAHDI_EVENT_BITSCHANGED:
11238 break;
11239 case DAHDI_EVENT_NOALARM:
11240 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11241 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11242
11243 analog_p->inalarm = 0;
11244 }
11245 mtd->pvt->inalarm = 0;
11247 break;
11248 case DAHDI_EVENT_ALARM:
11249 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11250 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11251
11252 analog_p->inalarm = 1;
11253 }
11254 mtd->pvt->inalarm = 1;
11255 res = get_alarms(mtd->pvt);
11256 handle_alarms(mtd->pvt, res);
11257 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11258 default:
11259 callid_created = ast_callid_threadstorage_auto(&callid);
11260 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
11261 callerid_free(cs);
11262
11263 restore_gains(mtd->pvt);
11264 mtd->pvt->ringt = mtd->pvt->ringt_base;
11265
11266 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
11267 int result;
11268
11269 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11271 } else {
11273 }
11274 if (result) {
11275 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
11276 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11277 if (res < 0)
11278 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
11279 ast_hangup(chan);
11280 }
11281 } else {
11282 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
11283 }
11284
11285 ast_callid_threadstorage_auto_clean(callid, callid_created);
11286 goto quit_no_clean;
11287 }
11288 } else if (i & DAHDI_IOMUX_READ) {
11289 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
11290 if (errno != ELAST) {
11291 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11292 goto quit;
11293 }
11294 break;
11295 }
11296 samples += res;
11297 if (!spill_done) {
11298 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
11299 /*
11300 * The previous diagnostic message output likely
11301 * explains why it failed.
11302 */
11303 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
11304 break;
11305 } else if (spill_result) {
11306 spill_done = 1;
11307 }
11308 } else {
11309 /* keep reading data until the energy level drops below the threshold
11310 so we don't get another 'trigger' on the remaining carrier signal
11311 */
11312 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
11313 break;
11314 }
11315 if (samples > (8000 * 4)) /*Termination case - time to give up*/
11316 break;
11317 }
11318 }
11319
11320 if (spill_result == 1) {
11321 callerid_get(cs, &name, &number, &flags);
11322 if (flags & CID_MSGWAITING) {
11323 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
11324 notify_message(mtd->pvt->mailbox, 1);
11325 } else if (flags & CID_NOMSGWAITING) {
11326 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
11327 notify_message(mtd->pvt->mailbox, 0);
11328 } else {
11329 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
11330 }
11331 }
11332
11333
11334quit:
11335 callerid_free(cs);
11336
11337 restore_gains(mtd->pvt);
11338
11339quit_no_clean:
11340 mtd->pvt->mwimonitoractive = 0;
11341 ast_free(mtd);
11342
11343 return NULL;
11344}
11345
11346/*
11347* The following three functions (mwi_send_init, mwi_send_process_buffer,
11348* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11349* that are sent out via FXS port on voicemail state change. The execution of
11350* the mwi send is state driven and can either generate a ring pulse prior to
11351* sending the fsk spill or simply send an fsk spill.
11352*/
11353static int mwi_send_init(struct dahdi_pvt * pvt)
11354{
11355 int x;
11356
11357#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11358 /* Determine how this spill is to be sent */
11359 if (pvt->mwisend_rpas) {
11361 pvt->mwisendactive = 1;
11362 } else if (pvt->mwisend_fsk) {
11364 pvt->mwisendactive = 1;
11365 } else {
11366 pvt->mwisendactive = 0;
11367 return 0;
11368 }
11369#else
11370 if (mwisend_rpas) {
11372 } else {
11374 }
11375 pvt->mwisendactive = 1;
11376#endif
11377
11378 if (pvt->cidspill) {
11379 ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n");
11380 ast_free(pvt->cidspill);
11381 pvt->cidspill = NULL;
11382 pvt->cidpos = 0;
11383 pvt->cidlen = 0;
11384 }
11386 if (!pvt->cidspill) {
11387 pvt->mwisendactive = 0;
11388 return -1;
11389 }
11390 x = DAHDI_FLUSH_BOTH;
11391 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
11392 x = 3000;
11393 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
11394#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11395 if (pvt->mwisend_fsk) {
11396#endif
11398 CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
11399 pvt->cidpos = 0;
11400#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11401 }
11402#endif
11403 return 0;
11404}
11405
11406static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
11407{
11408 struct timeval now;
11409 int res;
11410
11411 /* sanity check to catch if this had been interrupted previously
11412 * i.e. state says there is more to do but there is no spill allocated
11413 */
11414 if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
11416 } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
11417 /* Normal processing -- Perform mwi send action */
11418 switch ( pvt->mwisend_data.mwisend_current) {
11419 case MWI_SEND_SA:
11420 /* Send the Ring Pulse Signal Alert */
11421 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
11422 if (res) {
11423 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
11424 goto quit;
11425 }
11426 res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
11428 break;
11429 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
11430 break;
11431 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
11432#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11433 if (pvt->mwisend_fsk) {
11434#endif
11435 gettimeofday(&now, NULL);
11436 if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
11438 }
11439#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11440 } else { /* support for mwisendtype=nofsk */
11442 }
11443#endif
11444 break;
11445 case MWI_SEND_SPILL:
11446 /* We read some number of bytes. Write an equal amount of data */
11447 if (0 < num_read) {
11448 if (num_read > pvt->cidlen - pvt->cidpos) {
11449 num_read = pvt->cidlen - pvt->cidpos;
11450 }
11451 res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
11452 if (res > 0) {
11453 pvt->cidpos += res;
11454 if (pvt->cidpos >= pvt->cidlen) {
11456 }
11457 } else {
11458 ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno));
11459 goto quit;
11460 }
11461 }
11462 break;
11463 case MWI_SEND_CLEANUP:
11464 /* For now, do nothing */
11466 break;
11467 default:
11468 /* Should not get here, punt*/
11469 goto quit;
11470 }
11471 }
11472
11474 if (pvt->cidspill) {
11475 ast_free(pvt->cidspill);
11476 pvt->cidspill = NULL;
11477 pvt->cidpos = 0;
11478 pvt->cidlen = 0;
11479 }
11480 pvt->mwisendactive = 0;
11481 }
11482 return 0;
11483quit:
11484 if (pvt->cidspill) {
11485 ast_free(pvt->cidspill);
11486 pvt->cidspill = NULL;
11487 pvt->cidpos = 0;
11488 pvt->cidlen = 0;
11489 }
11490 pvt->mwisendactive = 0;
11491 return -1;
11492}
11493
11494static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
11495{
11496 int handled = 0;
11497
11499 switch (event) {
11500 case DAHDI_EVENT_RINGEROFF:
11502 handled = 1;
11503
11504 if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
11505 ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
11506 ast_free(pvt->cidspill);
11507 pvt->cidspill = NULL;
11509 pvt->mwisendactive = 0;
11510 } else {
11512 gettimeofday(&pvt->mwisend_data.pause, NULL);
11513 }
11514 }
11515 break;
11516 /* Going off hook, I need to punt this spill */
11517 case DAHDI_EVENT_RINGOFFHOOK:
11518 if (pvt->cidspill) {
11519 ast_free(pvt->cidspill);
11520 pvt->cidspill = NULL;
11521 pvt->cidpos = 0;
11522 pvt->cidlen = 0;
11523 }
11525 pvt->mwisendactive = 0;
11526 break;
11527 case DAHDI_EVENT_RINGERON:
11528 case DAHDI_EVENT_HOOKCOMPLETE:
11529 break;
11530 default:
11531 break;
11532 }
11533 }
11534 return handled;
11535}
11536
11537/* destroy a range DAHDI channels, identified by their number */
11538static void dahdi_destroy_channel_range(int start, int end)
11539{
11540 struct dahdi_pvt *cur;
11541 struct dahdi_pvt *next;
11542 int destroyed_first = 0;
11543 int destroyed_last = 0;
11544
11546 ast_debug(1, "range: %d-%d\n", start, end);
11547 for (cur = iflist; cur; cur = next) {
11548 next = cur->next;
11549 if (cur->channel >= start && cur->channel <= end) {
11550 int x = DAHDI_FLASH;
11551
11552 if (cur->channel > destroyed_last) {
11553 destroyed_last = cur->channel;
11554 }
11555 if (destroyed_first < 1 || cur->channel < destroyed_first) {
11556 destroyed_first = cur->channel;
11557 }
11558 ast_debug(3, "Destroying %d\n", cur->channel);
11559 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11560 ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11561
11562 destroy_channel(cur, 1);
11564 }
11565 }
11567 if (destroyed_first > start || destroyed_last < end) {
11568 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11569 start, end, destroyed_first, destroyed_last);
11570 }
11571}
11572
11573#ifdef HAVE_OPENR2
11574static void dahdi_r2_destroy_nodev(void)
11575{
11576 struct r2link_entry *cur;
11577 AST_LIST_LOCK(&nodev_r2links);
11578 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
11579 int i;
11580 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
11581 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
11582 for (i = 0; i < r2->numchans; i++) {
11583 int channel;
11584 struct dahdi_pvt *pvt = r2->pvts[i];
11585 if (!pvt) {
11586 continue;
11587 }
11588 channel = pvt->channel;
11589 ast_debug(3, "About to destroy B-channel %d.\n", channel);
11591 }
11592 ast_debug(3, "Destroying R2 link\n");
11593 AST_LIST_REMOVE(&nodev_r2links, cur, list);
11594 if (r2->r2master != AST_PTHREADT_NULL) {
11595 pthread_cancel(r2->r2master);
11596 pthread_join(r2->r2master, NULL);
11597 r2->r2master = AST_PTHREADT_NULL;
11598 openr2_context_delete(r2->protocol_context);
11599 }
11600 ast_free(cur);
11601 }
11603 AST_LIST_UNLOCK(&nodev_r2links);
11604}
11605#endif
11606
11607static int setup_dahdi(int reload);
11608static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
11609
11610/*!
11611 * \internal
11612 * \brief create a range of new DAHDI channels
11613 *
11614 * \param start first channel in the range
11615 * \param end last channel in the range
11616 *
11617 * \retval RESULT_SUCCESS on success.
11618 * \retval RESULT_FAILURE on error.
11619 */
11620static int dahdi_create_channel_range(int start, int end)
11621{
11622 struct dahdi_pvt *cur;
11623 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
11624 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
11626 int ret = RESULT_FAILURE; /* be pessimistic */
11627
11628 ast_debug(1, "channel range caps: %d - %d\n", start, end);
11630 for (cur = iflist; cur; cur = cur->next) {
11631 if (cur->channel >= start && cur->channel <= end) {
11633 "channel range %d-%d is occupied\n",
11634 start, end);
11635 goto out;
11636 }
11637 }
11638#ifdef HAVE_PRI
11639 {
11640 int i, x;
11641 for (x = 0; x < NUM_SPANS; x++) {
11642 struct dahdi_pri *pri = pris + x;
11643
11644 if (!pris[x].pri.pvts[0]) {
11645 break;
11646 }
11647 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
11648 int channo = pri->dchannels[i];
11649
11650 if (!channo) {
11651 break;
11652 }
11653 if (!pri->pri.fds[i]) {
11654 break;
11655 }
11656 if (channo >= start && channo <= end) {
11658 "channel range %d-%d is occupied by span %d\n",
11659 start, end, x + 1);
11660 goto out;
11661 }
11662 }
11663 }
11664 }
11665#endif
11666 if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
11667 !conf.chan.cc_params) {
11668 goto out;
11669 }
11670 default_conf.wanted_channels_start = start;
11671 base_conf.wanted_channels_start = start;
11672 conf.wanted_channels_start = start;
11673 default_conf.wanted_channels_end = end;
11674 base_conf.wanted_channels_end = end;
11675 conf.wanted_channels_end = end;
11676 if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
11677 ret = RESULT_SUCCESS;
11678 }
11679out:
11682 ast_cc_config_params_destroy(conf.chan.cc_params);
11684 return ret;
11685}
11686
11687
11688static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
11689{
11690 int res;
11691 pthread_t threadid;
11692 struct ast_channel *chan;
11693 ast_callid callid = 0;
11694 int callid_created;
11695
11696 /* Handle an event on a given channel for the monitor thread. */
11697
11698 switch (event) {
11699 case DAHDI_EVENT_NONE:
11700 case DAHDI_EVENT_BITSCHANGED:
11701 break;
11702 case DAHDI_EVENT_WINKFLASH:
11703 case DAHDI_EVENT_RINGOFFHOOK:
11704 if (i->inalarm) break;
11705 if (i->radio) break;
11706 /* Got a ring/answer. What kind of channel are we? */
11707 switch (i->sig) {
11708 case SIG_FXOLS:
11709 case SIG_FXOGS:
11710 case SIG_FXOKS:
11711 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11712 if (res && (errno == EBUSY)) {
11713 break;
11714 }
11715
11716 callid_created = ast_callid_threadstorage_auto(&callid);
11717
11718 /* Cancel VMWI spill */
11719 ast_free(i->cidspill);
11720 i->cidspill = NULL;
11722
11723 if (i->immediate) {
11724 dahdi_ec_enable(i);
11725 /* The channel is immediately up. Start right away */
11726 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
11727 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
11728 if (!chan) {
11729 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
11730 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11731 if (res < 0)
11732 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11733 }
11734 } else {
11735 /* Check for callerid, digits, etc */
11736 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
11737 if (chan) {
11738 if (has_voicemail(i))
11739 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
11740 else
11741 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
11742 if (res < 0)
11743 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
11744 if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11745 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11746 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11747 if (res < 0)
11748 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11749 ast_hangup(chan);
11750 }
11751 } else
11752 ast_log(LOG_WARNING, "Unable to create channel\n");
11753 }
11754
11756 break;
11757 case SIG_FXSLS:
11758 case SIG_FXSGS:
11759 case SIG_FXSKS:
11760 i->ringt = i->ringt_base;
11761 /* Fall through */
11762 case SIG_EMWINK:
11763 case SIG_FEATD:
11764 case SIG_FEATDMF:
11765 case SIG_FEATDMF_TA:
11766 case SIG_E911:
11767 case SIG_FGC_CAMA:
11768 case SIG_FGC_CAMAMF:
11769 case SIG_FEATB:
11770 case SIG_EM:
11771 case SIG_EM_E1:
11772 case SIG_SFWINK:
11773 case SIG_SF_FEATD:
11774 case SIG_SF_FEATDMF:
11775 case SIG_SF_FEATB:
11776 case SIG_SF:
11777 /* Check for callerid, digits, etc */
11778 callid_created = ast_callid_threadstorage_auto(&callid);
11779 if (i->cid_start == CID_START_POLARITY_IN) {
11780 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11781 } else {
11782 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
11783 }
11784
11785 if (!chan) {
11786 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11787 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11788 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11789 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11790 if (res < 0) {
11791 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11792 }
11793 ast_hangup(chan);
11794 }
11795
11797 break;
11798 default:
11799 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11800 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11801 if (res < 0)
11802 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11803 return NULL;
11804 }
11805 break;
11806 case DAHDI_EVENT_NOALARM:
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 = 0;
11822 break;
11823 }
11825 break;
11826 case DAHDI_EVENT_ALARM:
11827 switch (i->sig) {
11828#if defined(HAVE_PRI)
11830 ast_mutex_lock(&i->lock);
11833 break;
11834#endif /* defined(HAVE_PRI) */
11835#if defined(HAVE_SS7)
11836 case SIG_SS7:
11838 break;
11839#endif /* defined(HAVE_SS7) */
11840 default:
11841 i->inalarm = 1;
11842 break;
11843 }
11844 res = get_alarms(i);
11845 handle_alarms(i, res);
11846 /* fall thru intentionally */
11847 case DAHDI_EVENT_ONHOOK:
11848 if (i->radio)
11849 break;
11850 /* Back on hook. Hang up. */
11851 switch (i->sig) {
11852 case SIG_FXOLS:
11853 case SIG_FXOGS:
11854 case SIG_FEATD:
11855 case SIG_FEATDMF:
11856 case SIG_FEATDMF_TA:
11857 case SIG_E911:
11858 case SIG_FGC_CAMA:
11859 case SIG_FGC_CAMAMF:
11860 case SIG_FEATB:
11861 case SIG_EM:
11862 case SIG_EM_E1:
11863 case SIG_EMWINK:
11864 case SIG_SF_FEATD:
11865 case SIG_SF_FEATDMF:
11866 case SIG_SF_FEATB:
11867 case SIG_SF:
11868 case SIG_SFWINK:
11869 case SIG_FXSLS:
11870 case SIG_FXSGS:
11871 case SIG_FXSKS:
11872 case SIG_FXOKS:
11874 /* Diddle the battery for the zhone */
11875#ifdef ZHONE_HACK
11876 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11877 usleep(1);
11878#endif
11879 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11880 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
11881 break;
11882 case SIG_SS7:
11885 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11886 break;
11887 default:
11888 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11889 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11890 return NULL;
11891 }
11892 break;
11893 case DAHDI_EVENT_POLARITY:
11894 switch (i->sig) {
11895 case SIG_FXSLS:
11896 case SIG_FXSKS:
11897 case SIG_FXSGS:
11898 /* We have already got a PR before the channel was
11899 created, but it wasn't handled. We need polarity
11900 to be REV for remote hangup detection to work.
11901 At least in Spain */
11902 callid_created = ast_callid_threadstorage_auto(&callid);
11907 ast_verb(2, "Starting post polarity "
11908 "CID detection on channel %d\n",
11909 i->channel);
11910 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11911 if (!chan) {
11912 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11913 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11914 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11915 ast_hangup(chan);
11916 }
11917 }
11919 break;
11920 default:
11921 ast_log(LOG_WARNING, "handle_init_event detected "
11922 "polarity reversal on non-FXO (SIG_FXS) "
11923 "interface %d\n", i->channel);
11924 }
11925 break;
11926 case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
11928 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11929 i->channel);
11930 return i;
11931 case DAHDI_EVENT_NEONMWI_ACTIVE:
11932 if (i->mwimonitor_neon) {
11933 notify_message(i->mailbox, 1);
11934 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
11935 }
11936 break;
11937 case DAHDI_EVENT_NEONMWI_INACTIVE:
11938 if (i->mwimonitor_neon) {
11939 notify_message(i->mailbox, 0);
11940 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
11941 }
11942 break;
11943 }
11944 return NULL;
11945}
11946
11947static void monitor_pfds_clean(void *arg) {
11948 struct pollfd **pfds = arg;
11949 ast_free(*pfds);
11950}
11951
11952static void *do_monitor(void *data)
11953{
11954 int count, res, res2, spoint, pollres=0;
11955 struct dahdi_pvt *i;
11956 struct dahdi_pvt *last = NULL;
11957 struct dahdi_pvt *doomed;
11958 time_t thispass = 0, lastpass = 0;
11959 int found;
11960 char buf[1024];
11961 struct pollfd *pfds=NULL;
11962 int lastalloc = -1;
11963 /* This thread monitors all the frame relay interfaces which are not yet in use
11964 (and thus do not have a separate thread) indefinitely */
11965 /* From here on out, we die whenever asked */
11966#if 0
11967 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
11968 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
11969 return NULL;
11970 }
11971 ast_debug(1, "Monitor starting...\n");
11972#endif
11973 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11974
11975 pthread_cleanup_push(monitor_pfds_clean, &pfds);
11976 for (;;) {
11977 /* Lock the interface list */
11979 if (!pfds || (lastalloc != ifcount)) {
11980 if (pfds) {
11981 ast_free(pfds);
11982 pfds = NULL;
11983 }
11984 if (ifcount) {
11985 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
11987 return NULL;
11988 }
11989 }
11990 lastalloc = ifcount;
11991 }
11992 /* Build the stuff we're going to poll on, that is the socket of every
11993 dahdi_pvt that does not have an associated owner channel */
11994 count = 0;
11995 for (i = iflist; i; i = i->next) {
11996 ast_mutex_lock(&i->lock);
11997 if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
11998 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
11999 struct analog_pvt *p = i->sig_pvt;
12000
12001 if (!p) {
12002 ast_log(LOG_ERROR, "No sig_pvt?\n");
12003 } else if (!p->owner && !p->subs[SUB_REAL].owner) {
12004 /* This needs to be watched, as it lacks an owner */
12005 pfds[count].fd = i->subs[SUB_REAL].dfd;
12006 pfds[count].events = POLLPRI;
12007 pfds[count].revents = 0;
12008 /* Message waiting or r2 channels also get watched for reading */
12009 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12010 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12011 pfds[count].events |= POLLIN;
12012 }
12013 count++;
12014 }
12015 } else {
12016 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
12017 /* This needs to be watched, as it lacks an owner */
12018 pfds[count].fd = i->subs[SUB_REAL].dfd;
12019 pfds[count].events = POLLPRI;
12020 pfds[count].revents = 0;
12021 /* If we are monitoring for VMWI or sending CID, we need to
12022 read from the channel as well */
12023 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12024 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12025 pfds[count].events |= POLLIN;
12026 }
12027 count++;
12028 }
12029 }
12030 }
12032 }
12033 /* Okay, now that we know what to do, release the interface lock */
12035
12036 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
12037 pthread_testcancel();
12038 /* Wait at least a second for something to happen */
12039 res = poll(pfds, count, 1000);
12040 pthread_testcancel();
12041 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
12042
12043 /* Okay, poll has finished. Let's see what happened. */
12044 if (res < 0) {
12045 if ((errno != EAGAIN) && (errno != EINTR))
12046 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
12047 continue;
12048 }
12049 /* Alright, lock the interface list again, and let's look and see what has
12050 happened */
12052 found = 0;
12053 spoint = 0;
12054 lastpass = thispass;
12055 thispass = time(NULL);
12056 doomed = NULL;
12057 for (i = iflist;; i = i->next) {
12058 if (doomed) {
12060 doomed = NULL;
12061 }
12062 if (!i) {
12063 break;
12064 }
12065
12066 if (thispass != lastpass) {
12067 if (!found && ((i == last) || ((i == iflist) && !last))) {
12068 last = i;
12069 if (last) {
12070 struct analog_pvt *analog_p = last->sig_pvt;
12071 /* Only allow MWI to be initiated on a quiescent fxs port */
12072 if (analog_p
12073 && !last->mwisendactive
12074 && (last->sig & __DAHDI_SIG_FXO)
12075 && !analog_p->fxsoffhookstate
12076 && !last->owner
12077 && (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
12078 && !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
12079 && (thispass - analog_p->onhooktime > 3)
12080 /* In some cases, all of the above checks will pass even if the line is really off-hook.
12081 * This last check will give the right answer 100% of the time, but is relatively
12082 * "expensive" (it requires an ioctl), so it is last to avoid unnecessary system calls. */
12083 && !my_is_off_hook(last)) {
12084 res = has_voicemail(last);
12085 if (analog_p->msgstate != res) {
12086 /* Set driver resources for signalling VMWI */
12087 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
12088 if (res2) {
12089 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
12090 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
12091 }
12092 /* If enabled for FSK spill then initiate it */
12093 ast_debug(5, "Initiating MWI FSK spill on channel %d\n", last->channel);
12094 if (mwi_send_init(last)) {
12095 ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
12096 }
12097 analog_p->msgstate = res;
12098 found ++;
12099 }
12100 }
12101 last = last->next;
12102 }
12103 }
12104 }
12105 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
12106 if (i->radio && !i->owner)
12107 {
12108 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12109 if (res)
12110 {
12111 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
12112 /* Don't hold iflock while handling init events */
12114 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12116 else
12117 doomed = handle_init_event(i, res);
12119 }
12120 continue;
12121 }
12122 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
12123 if (pollres & POLLIN) {
12124 if (i->owner || i->subs[SUB_REAL].owner) {
12125#ifdef HAVE_PRI
12126 if (!i->pri)
12127#endif
12128 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
12129 continue;
12130 }
12132 ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
12133 continue;
12134 }
12135 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
12136 if (res > 0) {
12137 if (i->mwimonitor_fsk) {
12138 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
12139 pthread_attr_t attr;
12140 pthread_t threadid;
12141 struct mwi_thread_data *mtd;
12142
12143 pthread_attr_init(&attr);
12144 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
12145
12146 ast_debug(1, "Maybe some MWI on port %d!\n", i->channel);
12147 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
12148 mtd->pvt = i;
12149 memcpy(mtd->buf, buf, res);
12150 mtd->len = res;
12151 i->mwimonitoractive = 1;
12152 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
12153 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
12154 i->mwimonitoractive = 0;
12155 ast_free(mtd);
12156 }
12157 }
12158 }
12159 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
12160 } else if (i->cid_start == CID_START_DTMF_NOALERT) {
12161 int energy;
12162 struct timeval now;
12163 /* State machine dtmfcid_holdoff_state allows for the line to settle
12164 * before checking again for dtmf energy. Presently waits for 500 mS before checking again
12165 */
12166 if (1 == i->dtmfcid_holdoff_state) {
12167 gettimeofday(&i->dtmfcid_delay, NULL);
12168 i->dtmfcid_holdoff_state = 2;
12169 } else if (2 == i->dtmfcid_holdoff_state) {
12170 gettimeofday(&now, NULL);
12171 if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
12172 i->dtmfcid_holdoff_state = 0;
12173 }
12174 } else {
12175 energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
12176 if (!i->mwisendactive && energy > dtmfcid_level) {
12177 pthread_t threadid;
12178 struct ast_channel *chan;
12180 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12181 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12183 i->dtmfcid_holdoff_state = 1;
12184 } else {
12185 ast_callid callid = 0;
12186 int callid_created = ast_callid_threadstorage_auto(&callid);
12187 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
12188 if (!chan) {
12189 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
12190 } else {
12191 res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
12192 if (res) {
12193 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
12194 ast_hangup(chan);
12195 } else {
12196 i->dtmfcid_holdoff_state = 1;
12197 }
12198 }
12200 }
12202 }
12203 }
12204 }
12205 if (i->mwisendactive) {
12207 }
12208 } else {
12209 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
12210 }
12211 }
12212 if (pollres & POLLPRI) {
12213 if (i->owner || i->subs[SUB_REAL].owner) {
12214#ifdef HAVE_PRI
12215 if (!i->pri)
12216#endif
12217 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
12218 continue;
12219 }
12220 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12221 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
12222 /* Don't hold iflock while handling init events */
12224 if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
12225 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12227 else
12228 doomed = handle_init_event(i, res);
12229 }
12230 if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
12231 /* Actually automatically reoriginate this FXS line, if directed to.
12232 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12233 * doing its thing (one reason why this is for FXOKS only: FXOLS
12234 * hangups don't give us any DAHDI events to piggyback off of)*/
12235 i->doreoriginate = 0;
12236 /* Double check the channel is still off-hook. There's only about a millisecond
12237 * between when doreoriginate is set high and we see that here, but just to be safe. */
12238 if (!my_is_off_hook(i)) {
12239 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
12240 } else {
12241 ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
12242 res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
12243 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12245 } else {
12246 doomed = handle_init_event(i, res);
12247 }
12248 }
12249 }
12251 }
12252 }
12253 }
12256#ifdef HAVE_OPENR2
12257 dahdi_r2_destroy_nodev();
12258#endif
12259 }
12260 /* Never reached */
12261 pthread_cleanup_pop(1);
12262 return NULL;
12263
12264}
12265
12266static int restart_monitor(void)
12267{
12268 /* If we're supposed to be stopped -- stay stopped */
12270 return 0;
12272 if (monitor_thread == pthread_self()) {
12274 ast_log(LOG_WARNING, "Cannot kill myself\n");
12275 return -1;
12276 }
12278 /* Wake up the thread */
12279 pthread_kill(monitor_thread, SIGURG);
12280 } else {
12281 /* Start a new monitor */
12284 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
12285 return -1;
12286 }
12287 }
12289 return 0;
12290}
12291
12292#if defined(HAVE_PRI)
12293static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
12294{
12295 int x;
12296 int trunkgroup;
12297 /* Get appropriate trunk group if there is one */
12298 trunkgroup = pris[*span].mastertrunkgroup;
12299 if (trunkgroup) {
12300 /* Select a specific trunk group */
12301 for (x = 0; x < NUM_SPANS; x++) {
12302 if (pris[x].pri.trunkgroup == trunkgroup) {
12303 *span = x;
12304 return 0;
12305 }
12306 }
12307 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
12308 *span = -1;
12309 } else {
12310 if (pris[*span].pri.trunkgroup) {
12311 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);
12312 *span = -1;
12313 } else if (pris[*span].mastertrunkgroup) {
12314 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
12315 *span = -1;
12316 } else {
12317 if (si->totalchans == 31) {
12318 /* E1 */
12319 pris[*span].dchannels[0] = 16 + offset;
12320 } else if (si->totalchans == 24) {
12321 /* T1 or J1 */
12322 pris[*span].dchannels[0] = 24 + offset;
12323 } else if (si->totalchans == 3) {
12324 /* BRI */
12325 pris[*span].dchannels[0] = 3 + offset;
12326 } else {
12327 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);
12328 *span = -1;
12329 return 0;
12330 }
12331 pris[*span].pri.span = *span + 1;
12332 }
12333 }
12334 return 0;
12335}
12336#endif /* defined(HAVE_PRI) */
12337
12338#if defined(HAVE_PRI)
12339static int pri_create_trunkgroup(int trunkgroup, int *channels)
12340{
12341 struct dahdi_spaninfo si;
12342 struct dahdi_params p;
12343 int fd;
12344 int span;
12345 int ospan=0;
12346 int x,y;
12347 for (x = 0; x < NUM_SPANS; x++) {
12348 if (pris[x].pri.trunkgroup == trunkgroup) {
12349 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
12350 return -1;
12351 }
12352 }
12353 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12354 if (!channels[y])
12355 break;
12356 memset(&si, 0, sizeof(si));
12357 memset(&p, 0, sizeof(p));
12358 fd = open("/dev/dahdi/channel", O_RDWR);
12359 if (fd < 0) {
12360 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
12361 return -1;
12362 }
12363 x = channels[y];
12364 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
12365 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
12366 close(fd);
12367 return -1;
12368 }
12369 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
12370 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
12371 close(fd);
12372 return -1;
12373 }
12374 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
12375 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
12376 close(fd);
12377 return -1;
12378 }
12379 span = p.spanno - 1;
12380 if (pris[span].pri.trunkgroup) {
12381 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].pri.trunkgroup);
12382 close(fd);
12383 return -1;
12384 }
12385 if (pris[span].pri.pvts[0]) {
12386 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
12387 close(fd);
12388 return -1;
12389 }
12390 if (!y) {
12391 pris[span].pri.trunkgroup = trunkgroup;
12392 ospan = span;
12393 }
12394 pris[ospan].dchannels[y] = channels[y];
12395 pris[span].pri.span = span + 1;
12396 close(fd);
12397 }
12398 return 0;
12399}
12400#endif /* defined(HAVE_PRI) */
12401
12402#if defined(HAVE_PRI)
12403static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
12404{
12405 if (pris[span].mastertrunkgroup) {
12406 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);
12407 return -1;
12408 }
12409 pris[span].mastertrunkgroup = trunkgroup;
12410 pris[span].prilogicalspan = logicalspan;
12411 return 0;
12412}
12413#endif /* defined(HAVE_PRI) */
12414
12415#if defined(HAVE_SS7)
12416static unsigned int parse_pointcode(const char *pcstring)
12417{
12418 unsigned int code1, code2, code3;
12419 int numvals;
12420
12421 numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
12422 if (numvals == 1)
12423 return code1;
12424 if (numvals == 3)
12425 return (code1 << 16) | (code2 << 8) | code3;
12426
12427 return 0;
12428}
12429#endif /* defined(HAVE_SS7) */
12430
12431#if defined(HAVE_SS7)
12432static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
12433{
12434 if ((linkset < 0) || (linkset >= NUM_SPANS))
12435 return NULL;
12436 else
12437 return &linksets[linkset - 1];
12438}
12439#endif /* defined(HAVE_SS7) */
12440
12441#ifdef HAVE_OPENR2
12442static void dahdi_r2_destroy_links(void)
12443{
12444 struct r2link_entry *cur;
12445
12446 /* Queue everything for removal */
12447 AST_LIST_LOCK(&r2links);
12448 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
12449 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
12450 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
12451 }
12453 AST_LIST_UNLOCK(&r2links);
12454 /* Now destroy properly */
12455 dahdi_r2_destroy_nodev();
12456}
12457
12458/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12459#define R2_LINK_CAPACITY 30
12460static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
12461{
12462 struct r2link_entry *cur = NULL;
12463 /* Only create a new R2 link if
12464 1. This is the first link requested
12465 2. Configuration changed
12466 3. We got more channels than supported per link */
12467 AST_LIST_LOCK(&r2links);
12468 if (! AST_LIST_EMPTY(&r2links)) {
12469 cur = AST_LIST_LAST(&r2links);
12470 if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
12471 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12472 cur = NULL;
12473 } else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
12474 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
12475 cur = NULL;
12476 }
12477 }
12478 if (!cur) {
12479 struct r2link_entry *tmp = NULL;
12480 int new_idx = r2links_count + 1;
12481 int i;
12482 for (i = 1; i <= r2links_count; i++) {
12483 int i_unused = 1;
12484 AST_LIST_TRAVERSE(&r2links, tmp, list) {
12485 if (i == tmp->mfcr2.index) {
12486 i_unused = 0;
12487 break;
12488 }
12489 }
12490 if (i_unused) {
12491 new_idx = i;
12492 break;
12493 }
12494 }
12495 cur = ast_calloc(1, sizeof(*cur));
12496 if (!cur) {
12497 ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
12498 return NULL;
12499 }
12500 cur->mfcr2.index = new_idx;
12501 cur->mfcr2.r2master = AST_PTHREADT_NULL;
12502 r2links_count++;
12503 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
12504 AST_LIST_INSERT_TAIL(&r2links, cur, list);
12505 }
12506 AST_LIST_UNLOCK(&r2links);
12507 return cur;
12508}
12509
12510static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
12511{
12512 char tmplogdir[] = "/tmp";
12513 char logdir[OR2_MAX_PATH];
12514 int threshold = 0;
12515 int snres = 0;
12516 r2_link->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
12517 &dahdi_r2_transcode_iface, conf->mfcr2.variant, conf->mfcr2.max_ani,
12518 conf->mfcr2.max_dnis);
12519 if (!r2_link->protocol_context) {
12520 return -1;
12521 }
12522 openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
12523 openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
12524#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12525 openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
12526#endif
12527 openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
12528 openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
12529 openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
12530 openr2_context_set_double_answer(r2_link->protocol_context, conf->mfcr2.double_answer);
12531 openr2_context_set_immediate_accept(r2_link->protocol_context, conf->mfcr2.immediate_accept);
12532#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12533 openr2_context_set_dtmf_dialing(r2_link->protocol_context, conf->mfcr2.dtmf_dialing, conf->mfcr2.dtmf_time_on, conf->mfcr2.dtmf_time_off);
12534 openr2_context_set_dtmf_detection(r2_link->protocol_context, conf->mfcr2.dtmf_detection);
12535#endif
12536#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12537 openr2_context_set_dtmf_detection_end_timeout(r2_link->protocol_context, conf->mfcr2.dtmf_end_timeout);
12538#endif
12539 if (ast_strlen_zero(conf->mfcr2.logdir)) {
12540 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12541 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12542 }
12543 } else {
12544 snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", conf->mfcr2.logdir);
12545 if (snres >= sizeof(logdir)) {
12546 ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
12547 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12548 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12549 }
12550 } else {
12551 if (openr2_context_set_log_directory(r2_link->protocol_context, logdir)) {
12552 ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
12553 }
12554 }
12555 }
12556 if (!ast_strlen_zero(conf->mfcr2.r2proto_file)) {
12557 if (openr2_context_configure_from_advanced_file(r2_link->protocol_context, conf->mfcr2.r2proto_file)) {
12558 ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
12559 }
12560 }
12561 /* Save the configuration used to setup this link */
12562 memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
12563 return 0;
12564}
12565#endif
12566
12567/* converts a DAHDI sigtype to signalling as can be configured from
12568 * chan_dahdi.conf.
12569 * While both have basically the same values, this will later be the
12570 * place to add filters and sanity checks
12571 */
12573{
12574 return sigtype;
12575}
12576
12577/*!
12578 * \internal
12579 * \brief Initialize/create a channel interface.
12580 *
12581 * \param channel Channel interface number to initialize/create.
12582 * \param conf Configuration parameters to initialize interface with.
12583 * \param reloading What we are doing now:
12584 * 0 - initial module load,
12585 * 1 - module reload,
12586 * 2 - module restart
12587 *
12588 * \retval Interface-pointer initialized/created
12589 * \retval NULL if error
12590 */
12591static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
12592{
12593 /* Make a dahdi_pvt structure for this interface */
12594 struct dahdi_pvt *tmp;/*!< Current channel structure initializing */
12595 char fn[80];
12596 struct dahdi_bufferinfo bi;
12597
12598 int res;
12599#if defined(HAVE_PRI)
12600 int span = 0;
12601#endif /* defined(HAVE_PRI) */
12602 int here = 0;/*!< TRUE if the channel interface already exists. */
12603 int x;
12604 struct analog_pvt *analog_p = NULL;
12605 struct dahdi_params p;
12606#if defined(HAVE_PRI)
12607 struct dahdi_spaninfo si;
12608 struct sig_pri_chan *pri_chan = NULL;
12609#endif /* defined(HAVE_PRI) */
12610#if defined(HAVE_SS7)
12611 struct sig_ss7_chan *ss7_chan = NULL;
12612#endif /* defined(HAVE_SS7) */
12613
12614 /* Search channel interface list to see if it already exists. */
12615 for (tmp = iflist; tmp; tmp = tmp->next) {
12616 if (!tmp->destroy) {
12617 if (tmp->channel == channel) {
12618 /* The channel interface already exists. */
12619 here = 1;
12620 break;
12621 }
12622 if (tmp->channel > channel) {
12623 /* No way it can be in the sorted list. */
12624 tmp = NULL;
12625 break;
12626 }
12627 }
12628 }
12629
12630 if (!here && reloading != 1) {
12631 tmp = ast_calloc(1, sizeof(*tmp));
12632 if (!tmp) {
12633 return NULL;
12634 }
12636 if (!tmp->cc_params) {
12637 ast_free(tmp);
12638 return NULL;
12639 }
12640 ast_mutex_init(&tmp->lock);
12641 ifcount++;
12642 for (x = 0; x < 3; x++)
12643 tmp->subs[x].dfd = -1;
12644 tmp->channel = channel;
12645 tmp->priindication_oob = conf->chan.priindication_oob;
12646 }
12647
12648 if (tmp) {
12649 int chan_sig = conf->chan.sig;
12650
12651 /* If there are variables in tmp before it is updated to match the new config, clear them */
12652 if (reloading && tmp->vars) {
12654 tmp->vars = NULL;
12655 }
12656
12657 if (!here) {
12658 /* Can only get here if this is a new channel interface being created. */
12659 if ((channel != CHAN_PSEUDO)) {
12660 int count = 0;
12661
12662 snprintf(fn, sizeof(fn), "%d", channel);
12663 /* Open non-blocking */
12664 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12665 /* Retry open on restarts, but don't keep retrying if the channel doesn't exist (e.g. not configured) */
12666 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 */
12667 usleep(1);
12668 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12669 count++;
12670 }
12671 /* Allocate a DAHDI structure */
12672 if (tmp->subs[SUB_REAL].dfd < 0) {
12673 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);
12674 destroy_dahdi_pvt(tmp);
12675 return NULL;
12676 }
12677 memset(&p, 0, sizeof(p));
12678 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
12679 if (res < 0) {
12680 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
12681 destroy_dahdi_pvt(tmp);
12682 return NULL;
12683 }
12684 if (conf->is_sig_auto)
12685 chan_sig = sigtype_to_signalling(p.sigtype);
12686 if (p.sigtype != (chan_sig & 0x3ffff)) {
12687 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));
12688 destroy_dahdi_pvt(tmp);
12689 return NULL;
12690 }
12691 tmp->law_default = p.curlaw;
12692 tmp->law = p.curlaw;
12693 tmp->span = p.spanno;
12694#if defined(HAVE_PRI)
12695 span = p.spanno - 1;
12696#endif /* defined(HAVE_PRI) */
12697 } else {
12698 chan_sig = 0;
12699 }
12700 tmp->sig = chan_sig;
12701 tmp->outsigmod = conf->chan.outsigmod;
12702
12703 if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
12704 analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
12705 if (!analog_p) {
12706 destroy_dahdi_pvt(tmp);
12707 return NULL;
12708 }
12709 tmp->sig_pvt = analog_p;
12710 }
12711#if defined(HAVE_SS7)
12712 if (chan_sig == SIG_SS7) {
12713 struct dahdi_ss7 *ss7;
12714 int clear = 0;
12715
12716 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
12717 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12718 destroy_dahdi_pvt(tmp);
12719 return NULL;
12720 }
12721
12722 ss7 = ss7_resolve_linkset(cur_linkset);
12723 if (!ss7) {
12724 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
12725 destroy_dahdi_pvt(tmp);
12726 return NULL;
12727 }
12728 ss7->ss7.span = cur_linkset;
12729 if (cur_cicbeginswith < 0) {
12730 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
12731 destroy_dahdi_pvt(tmp);
12732 return NULL;
12733 }
12734 ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
12735 if (!ss7_chan) {
12736 destroy_dahdi_pvt(tmp);
12737 return NULL;
12738 }
12739 tmp->sig_pvt = ss7_chan;
12740 tmp->ss7 = &ss7->ss7;
12741
12742 ss7_chan->channel = tmp->channel;
12743 ss7_chan->cic = cur_cicbeginswith++;
12744
12745 /* DB: Add CIC's DPC information */
12746 ss7_chan->dpc = cur_defaultdpc;
12747
12748 ss7->ss7.pvts[ss7->ss7.numchans++] = ss7_chan;
12749
12750 ast_copy_string(ss7->ss7.internationalprefix, conf->ss7.ss7.internationalprefix, sizeof(ss7->ss7.internationalprefix));
12751 ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
12752 ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
12753 ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
12754 ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
12755
12756 ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
12757 ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
12758 }
12759#endif /* defined(HAVE_SS7) */
12760#ifdef HAVE_OPENR2
12761 if (chan_sig == SIG_MFCR2) {
12762 struct dahdi_mfcr2 *r2_link;
12763 struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
12764 r2_link = &r2_le->mfcr2;
12765 if (!r2_link) {
12766 ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
12767 destroy_dahdi_pvt(tmp);
12768 return NULL;
12769 }
12770 if (!r2_link->protocol_context && dahdi_r2_set_context(r2_link, conf)) {
12771 ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
12772 destroy_dahdi_pvt(tmp);
12773 return NULL;
12774 }
12775 if (r2_link->numchans == ARRAY_LEN(r2_link->pvts)) {
12776 ast_log(LOG_ERROR, "Cannot add more channels to this link!\n");
12777 destroy_dahdi_pvt(tmp);
12778 return NULL;
12779 }
12780 r2_link->pvts[r2_link->numchans++] = tmp;
12781 tmp->r2chan = openr2_chan_new_from_fd(r2_link->protocol_context,
12782 tmp->subs[SUB_REAL].dfd,
12783 NULL, NULL);
12784 if (!tmp->r2chan) {
12785 openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
12786 ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
12787 destroy_dahdi_pvt(tmp);
12788 return NULL;
12789 }
12790 r2_link->live_chans++;
12791 tmp->mfcr2 = r2_link;
12792 if (conf->mfcr2.call_files) {
12793 openr2_chan_enable_call_files(tmp->r2chan);
12794 }
12795 openr2_chan_set_client_data(tmp->r2chan, tmp);
12796 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12797 openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
12798 openr2_chan_set_log_level(tmp->r2chan, conf->mfcr2.loglevel);
12799 tmp->mfcr2_category = conf->mfcr2.category;
12800 tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
12801 tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
12802 tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
12803 tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
12804 tmp->mfcr2call = 0;
12805 tmp->mfcr2_dnis_index = 0;
12806 tmp->mfcr2_ani_index = 0;
12807 }
12808#endif
12809#ifdef HAVE_PRI
12810 if (dahdi_sig_pri_lib_handles(chan_sig)) {
12811 int offset;
12812 int matchesdchan;
12813 int x,y;
12814 int myswitchtype = 0;
12815
12816 offset = 0;
12817 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
12818 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12819 destroy_dahdi_pvt(tmp);
12820 return NULL;
12821 }
12822 if (span >= NUM_SPANS) {
12823 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
12824 destroy_dahdi_pvt(tmp);
12825 return NULL;
12826 } else {
12827 si.spanno = 0;
12828 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
12829 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
12830 destroy_dahdi_pvt(tmp);
12831 return NULL;
12832 }
12833 /* Store the logical span first based upon the real span */
12834 tmp->logicalspan = pris[span].prilogicalspan;
12835 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
12836 if (span < 0) {
12837 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
12838 destroy_dahdi_pvt(tmp);
12839 return NULL;
12840 }
12841 myswitchtype = conf->pri.pri.switchtype;
12842 /* Make sure this isn't a d-channel */
12843 matchesdchan=0;
12844 for (x = 0; x < NUM_SPANS; x++) {
12845 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12846 if (pris[x].dchannels[y] == tmp->channel) {
12847 matchesdchan = 1;
12848 break;
12849 }
12850 }
12851 }
12852 if (!matchesdchan) {
12853 if (pris[span].pri.nodetype && (pris[span].pri.nodetype != conf->pri.pri.nodetype)) {
12854 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].pri.nodetype));
12855 destroy_dahdi_pvt(tmp);
12856 return NULL;
12857 }
12858 if (pris[span].pri.switchtype && (pris[span].pri.switchtype != myswitchtype)) {
12859 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].pri.switchtype));
12860 destroy_dahdi_pvt(tmp);
12861 return NULL;
12862 }
12863 if ((pris[span].pri.dialplan) && (pris[span].pri.dialplan != conf->pri.pri.dialplan)) {
12864 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));
12865 destroy_dahdi_pvt(tmp);
12866 return NULL;
12867 }
12868 if (!ast_strlen_zero(pris[span].pri.idledial) && strcmp(pris[span].pri.idledial, conf->pri.pri.idledial)) {
12869 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.pri.idledial);
12870 destroy_dahdi_pvt(tmp);
12871 return NULL;
12872 }
12873 if (!ast_strlen_zero(pris[span].pri.idleext) && strcmp(pris[span].pri.idleext, conf->pri.pri.idleext)) {
12874 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.pri.idleext);
12875 destroy_dahdi_pvt(tmp);
12876 return NULL;
12877 }
12878 if (pris[span].pri.minunused && (pris[span].pri.minunused != conf->pri.pri.minunused)) {
12879 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.pri.minunused);
12880 destroy_dahdi_pvt(tmp);
12881 return NULL;
12882 }
12883 if (pris[span].pri.minidle && (pris[span].pri.minidle != conf->pri.pri.minidle)) {
12884 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.pri.minidle);
12885 destroy_dahdi_pvt(tmp);
12886 return NULL;
12887 }
12888 if (pris[span].pri.numchans >= ARRAY_LEN(pris[span].pri.pvts)) {
12889 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
12890 pris[span].pri.trunkgroup);
12891 destroy_dahdi_pvt(tmp);
12892 return NULL;
12893 }
12894
12895 pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
12896 if (!pri_chan) {
12897 destroy_dahdi_pvt(tmp);
12898 return NULL;
12899 }
12900 tmp->sig_pvt = pri_chan;
12901 tmp->pri = &pris[span].pri;
12902
12903 tmp->priexclusive = conf->chan.priexclusive;
12904
12905 if (!tmp->pri->cc_params) {
12907 if (!tmp->pri->cc_params) {
12908 destroy_dahdi_pvt(tmp);
12909 return NULL;
12910 }
12911 }
12913 conf->chan.cc_params);
12914
12915 pris[span].pri.sig = chan_sig;
12916 pris[span].pri.nodetype = conf->pri.pri.nodetype;
12917 pris[span].pri.switchtype = myswitchtype;
12918 pris[span].pri.nsf = conf->pri.pri.nsf;
12919 pris[span].pri.dialplan = conf->pri.pri.dialplan;
12920 pris[span].pri.localdialplan = conf->pri.pri.localdialplan;
12921 pris[span].pri.cpndialplan = conf->pri.pri.cpndialplan;
12922 pris[span].pri.pvts[pris[span].pri.numchans++] = tmp->sig_pvt;
12923 pris[span].pri.minunused = conf->pri.pri.minunused;
12924 pris[span].pri.minidle = conf->pri.pri.minidle;
12925 pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
12926 pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
12927 pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
12928#if defined(HAVE_PRI_SERVICE_MESSAGES)
12929 pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
12930#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12931#ifdef HAVE_PRI_INBANDDISCONNECT
12932 pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
12933#endif
12934#if defined(HAVE_PRI_CALL_HOLD)
12935 pris[span].pri.hold_disconnect_transfer =
12936 conf->pri.pri.hold_disconnect_transfer;
12937#endif /* defined(HAVE_PRI_CALL_HOLD) */
12938#if defined(HAVE_PRI_CCSS)
12939 pris[span].pri.cc_ptmp_recall_mode =
12940 conf->pri.pri.cc_ptmp_recall_mode;
12941 pris[span].pri.cc_qsig_signaling_link_req =
12942 conf->pri.pri.cc_qsig_signaling_link_req;
12943 pris[span].pri.cc_qsig_signaling_link_rsp =
12944 conf->pri.pri.cc_qsig_signaling_link_rsp;
12945#endif /* defined(HAVE_PRI_CCSS) */
12946#if defined(HAVE_PRI_CALL_WAITING)
12947 pris[span].pri.max_call_waiting_calls =
12948 conf->pri.pri.max_call_waiting_calls;
12949 pris[span].pri.allow_call_waiting_calls =
12950 conf->pri.pri.allow_call_waiting_calls;
12951#endif /* defined(HAVE_PRI_CALL_WAITING) */
12952 pris[span].pri.transfer = conf->chan.transfer;
12953 pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
12954#if defined(HAVE_PRI_L2_PERSISTENCE)
12955 pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
12956#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12957 pris[span].pri.colp_send = conf->pri.pri.colp_send;
12958#if defined(HAVE_PRI_AOC_EVENTS)
12959 pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
12960 pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
12961#endif /* defined(HAVE_PRI_AOC_EVENTS) */
12962 if (chan_sig == SIG_BRI_PTMP) {
12963 pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
12964 } else {
12965 /* Option does not apply to this line type. */
12966 pris[span].pri.layer1_ignored = 0;
12967 }
12968 pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
12969 pris[span].pri.inband_on_setup_ack = conf->pri.pri.inband_on_setup_ack;
12970 pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
12971 ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
12972 ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
12973#if defined(HAVE_PRI_MWI)
12974 ast_copy_string(pris[span].pri.mwi_mailboxes,
12975 conf->pri.pri.mwi_mailboxes,
12976 sizeof(pris[span].pri.mwi_mailboxes));
12977 ast_copy_string(pris[span].pri.mwi_vm_boxes,
12978 conf->pri.pri.mwi_vm_boxes,
12979 sizeof(pris[span].pri.mwi_vm_boxes));
12980 ast_copy_string(pris[span].pri.mwi_vm_numbers,
12981 conf->pri.pri.mwi_vm_numbers,
12982 sizeof(pris[span].pri.mwi_vm_numbers));
12983#endif /* defined(HAVE_PRI_MWI) */
12984 ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
12985 ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
12986 ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix));
12987 ast_copy_string(pris[span].pri.nationalprefix, conf->pri.pri.nationalprefix, sizeof(pris[span].pri.nationalprefix));
12988 ast_copy_string(pris[span].pri.localprefix, conf->pri.pri.localprefix, sizeof(pris[span].pri.localprefix));
12989 ast_copy_string(pris[span].pri.privateprefix, conf->pri.pri.privateprefix, sizeof(pris[span].pri.privateprefix));
12990 ast_copy_string(pris[span].pri.unknownprefix, conf->pri.pri.unknownprefix, sizeof(pris[span].pri.unknownprefix));
12991 pris[span].pri.moh_signaling = conf->pri.pri.moh_signaling;
12992 pris[span].pri.resetinterval = conf->pri.pri.resetinterval;
12993#if defined(HAVE_PRI_DISPLAY_TEXT)
12994 pris[span].pri.display_flags_send = conf->pri.pri.display_flags_send;
12995 pris[span].pri.display_flags_receive = conf->pri.pri.display_flags_receive;
12996#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12997#if defined(HAVE_PRI_MCID)
12998 pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
12999#endif /* defined(HAVE_PRI_MCID) */
13000 pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
13001#if defined(HAVE_PRI_DATETIME_SEND)
13002 pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
13003#endif /* defined(HAVE_PRI_DATETIME_SEND) */
13004
13005 for (x = 0; x < PRI_MAX_TIMERS; x++) {
13006 pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
13007 }
13008
13009#if defined(HAVE_PRI_CALL_WAITING)
13010 /* Channel initial config parameters. */
13011 pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
13012 pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
13013 pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
13014 pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
13015 pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
13016 pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
13017 pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
13018 pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
13019 ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
13020 ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
13021#endif /* defined(HAVE_PRI_CALL_WAITING) */
13022 } else {
13023 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
13024 destroy_dahdi_pvt(tmp);
13025 return NULL;
13026 }
13027 }
13028 }
13029#endif
13030 } else {
13031 /* already exists in interface list */
13032 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));
13033 chan_sig = tmp->sig;
13034 if (tmp->subs[SUB_REAL].dfd > -1) {
13035 memset(&p, 0, sizeof(p));
13036 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13037 }
13038 }
13039 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
13040 switch (chan_sig) {
13041 case SIG_FXSKS:
13042 case SIG_FXSLS:
13043 case SIG_EM:
13044 case SIG_EM_E1:
13045 case SIG_EMWINK:
13046 case SIG_FEATD:
13047 case SIG_FEATDMF:
13048 case SIG_FEATDMF_TA:
13049 case SIG_FEATB:
13050 case SIG_E911:
13051 case SIG_SF:
13052 case SIG_SFWINK:
13053 case SIG_FGC_CAMA:
13054 case SIG_FGC_CAMAMF:
13055 case SIG_SF_FEATD:
13056 case SIG_SF_FEATDMF:
13057 case SIG_SF_FEATB:
13058 p.starttime = 250;
13059 break;
13060 }
13061
13062 if (tmp->radio) {
13063 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
13064 p.channo = channel;
13065 p.rxwinktime = 1;
13066 p.rxflashtime = 1;
13067 p.starttime = 1;
13068 p.debouncetime = 5;
13069 } else {
13070 p.channo = channel;
13071 /* Override timing settings based on config file */
13072 if (conf->timing.prewinktime >= 0)
13073 p.prewinktime = conf->timing.prewinktime;
13074 if (conf->timing.preflashtime >= 0)
13075 p.preflashtime = conf->timing.preflashtime;
13076 if (conf->timing.winktime >= 0)
13077 p.winktime = conf->timing.winktime;
13078 if (conf->timing.flashtime >= 0)
13079 p.flashtime = conf->timing.flashtime;
13080 if (conf->timing.starttime >= 0)
13081 p.starttime = conf->timing.starttime;
13082 if (conf->timing.rxwinktime >= 0)
13083 p.rxwinktime = conf->timing.rxwinktime;
13084 if (conf->timing.rxflashtime >= 0)
13085 p.rxflashtime = conf->timing.rxflashtime;
13086 if (conf->timing.debouncetime >= 0)
13087 p.debouncetime = conf->timing.debouncetime;
13088 }
13089
13090 /* don't set parms on a pseudo-channel */
13091 if (tmp->subs[SUB_REAL].dfd >= 0)
13092 {
13093 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
13094 if (res < 0) {
13095 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
13096 destroy_dahdi_pvt(tmp);
13097 return NULL;
13098 }
13099 }
13100#if 1
13101 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
13102 memset(&bi, 0, sizeof(bi));
13103 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13104 if (!res) {
13105 bi.txbufpolicy = conf->chan.buf_policy;
13106 bi.rxbufpolicy = conf->chan.buf_policy;
13107 bi.numbufs = conf->chan.buf_no;
13108 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13109 if (res < 0) {
13110 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
13111 }
13112 } else {
13113 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
13114 }
13115 tmp->buf_policy = conf->chan.buf_policy;
13116 tmp->buf_no = conf->chan.buf_no;
13117 tmp->usefaxbuffers = conf->chan.usefaxbuffers;
13118 tmp->faxbuf_policy = conf->chan.faxbuf_policy;
13119 tmp->faxbuf_no = conf->chan.faxbuf_no;
13120 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
13121 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
13122 * The reason the ioctl call above failed should to be determined before worrying about the
13123 * faxbuffer-related ioctl calls */
13124 tmp->bufsize = bi.bufsize;
13125 }
13126#endif
13127 tmp->immediate = conf->chan.immediate;
13128 tmp->immediatering = conf->chan.immediatering;
13129 tmp->transfertobusy = conf->chan.transfertobusy;
13130 tmp->dialmode = conf->chan.dialmode;
13131 if (chan_sig & __DAHDI_SIG_FXS) {
13132 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
13133 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
13134 tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
13135 }
13136 tmp->ringt_base = ringt_base;
13137 tmp->firstradio = 0;
13138 if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
13139 tmp->permcallwaiting = conf->chan.callwaiting;
13140 else
13141 tmp->permcallwaiting = 0;
13142 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
13143 tmp->destroy = 0;
13144 tmp->drings = conf->chan.drings;
13145
13146 /* 10 is a nice default. */
13147 if (tmp->drings.ringnum[0].range == 0)
13148 tmp->drings.ringnum[0].range = 10;
13149 if (tmp->drings.ringnum[1].range == 0)
13150 tmp->drings.ringnum[1].range = 10;
13151 if (tmp->drings.ringnum[2].range == 0)
13152 tmp->drings.ringnum[2].range = 10;
13153
13155 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
13156 tmp->callwaitingdeluxe = conf->chan.callwaitingdeluxe; /* Not used in DAHDI pvt, only analog pvt */
13157 tmp->threewaycalling = conf->chan.threewaycalling;
13158 tmp->threewaysilenthold = conf->chan.threewaysilenthold;
13159 tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
13160 tmp->adsi = conf->chan.adsi;
13161 tmp->use_smdi = conf->chan.use_smdi;
13162 tmp->permhidecallerid = conf->chan.hidecallerid;
13163 tmp->hidecalleridname = conf->chan.hidecalleridname;
13164 tmp->callreturn = conf->chan.callreturn;
13165 tmp->lastnumredial = conf->chan.lastnumredial; /* Not used in DAHDI pvt, only analog pvt */
13166 tmp->echocancel = conf->chan.echocancel;
13167 tmp->echotraining = conf->chan.echotraining;
13168 tmp->pulse = conf->chan.pulse;
13169 if (tmp->echocancel.head.tap_length) {
13170 tmp->echocanbridged = conf->chan.echocanbridged;
13171 } else {
13172 if (conf->chan.echocanbridged)
13173 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
13174 tmp->echocanbridged = 0;
13175 }
13176 tmp->busydetect = conf->chan.busydetect;
13177 tmp->busycount = conf->chan.busycount;
13178 tmp->busy_cadence = conf->chan.busy_cadence;
13179 tmp->callprogress = conf->chan.callprogress;
13180 tmp->waitfordialtone = conf->chan.waitfordialtone;
13181 tmp->dialtone_detect = conf->chan.dialtone_detect;
13182 tmp->faxdetect_timeout = conf->chan.faxdetect_timeout;
13183 tmp->firstdigit_timeout = conf->chan.firstdigit_timeout;
13184 tmp->interdigit_timeout = conf->chan.interdigit_timeout;
13185 tmp->matchdigit_timeout = conf->chan.matchdigit_timeout;
13186 tmp->cancallforward = conf->chan.cancallforward;
13187 tmp->dtmfrelax = conf->chan.dtmfrelax;
13188 tmp->callwaiting = tmp->permcallwaiting;
13189 tmp->hidecallerid = tmp->permhidecallerid;
13190 tmp->channel = channel;
13191 tmp->stripmsd = conf->chan.stripmsd;
13192 tmp->use_callerid = conf->chan.use_callerid;
13193 tmp->cid_signalling = conf->chan.cid_signalling;
13194 tmp->cid_start = conf->chan.cid_start;
13195 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
13196 tmp->restrictcid = conf->chan.restrictcid;
13197 tmp->use_callingpres = conf->chan.use_callingpres;
13198 if (tmp->usedistinctiveringdetection) {
13199 if (!tmp->use_callerid) {
13200 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
13201 tmp->use_callerid = 1;
13202 }
13203 }
13204
13205 if (tmp->cid_signalling == CID_SIG_SMDI) {
13206 if (!tmp->use_smdi) {
13207 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13208 tmp->use_smdi = 1;
13209 }
13210 }
13211 if (tmp->use_smdi) {
13212 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
13213 if (!(tmp->smdi_iface)) {
13214 ast_log(LOG_ERROR, "Invalid SMDI port specified, disabling SMDI support\n");
13215 tmp->use_smdi = 0;
13216 }
13217 }
13218
13219 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
13220 tmp->amaflags = conf->chan.amaflags;
13221 if (!here) {
13222 tmp->confno = -1;
13223 tmp->propconfno = -1;
13224 }
13225 tmp->canpark = conf->chan.canpark;
13226 tmp->transfer = conf->chan.transfer;
13227 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
13228 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
13229 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
13230 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
13231 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
13232 ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
13233 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
13234 tmp->cid_ton = 0;
13235 if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
13236 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
13237 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
13238 } else {
13239 tmp->cid_num[0] = '\0';
13240 tmp->cid_name[0] = '\0';
13241 }
13242#if defined(HAVE_PRI)
13243 if (dahdi_sig_pri_lib_handles(tmp->sig)) {
13244 tmp->cid_tag[0] = '\0';
13245 } else
13246#endif /* defined(HAVE_PRI) */
13247 {
13248 ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
13249 }
13250 tmp->cid_subaddr[0] = '\0';
13251 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
13252 if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
13253 /* This module does not handle MWI in an event-based manner. However, it
13254 * subscribes to MWI for each mailbox that is configured so that the core
13255 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13256 * event cache instead of checking the mailbox directly. */
13258 }
13259#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13260 tmp->mwisend_setting = conf->chan.mwisend_setting;
13261 tmp->mwisend_fsk = conf->chan.mwisend_fsk;
13262 tmp->mwisend_rpas = conf->chan.mwisend_rpas;
13263#endif
13264
13265 tmp->group = conf->chan.group;
13266 tmp->callgroup = conf->chan.callgroup;
13267 tmp->pickupgroup= conf->chan.pickupgroup;
13269 tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
13271 tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
13272 if (conf->chan.vars) {
13273 struct ast_variable *v, *tmpvar;
13274 for (v = conf->chan.vars ; v ; v = v->next) {
13275 if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
13276 if (ast_variable_list_replace(&tmp->vars, tmpvar)) {
13277 tmpvar->next = tmp->vars;
13278 tmp->vars = tmpvar;
13279 }
13280 }
13281 }
13282 }
13283 tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
13284 tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
13285 tmp->hwrxgain = conf->chan.hwrxgain;
13286 tmp->hwtxgain = conf->chan.hwtxgain;
13287 tmp->cid_rxgain = conf->chan.cid_rxgain;
13288 tmp->rxgain = conf->chan.rxgain;
13289 tmp->txgain = conf->chan.txgain;
13290 tmp->txdrc = conf->chan.txdrc;
13291 tmp->rxdrc = conf->chan.rxdrc;
13292 tmp->tonezone = conf->chan.tonezone;
13293 if (tmp->subs[SUB_REAL].dfd > -1) {
13294 if (tmp->hwrxgain_enabled) {
13295 tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
13296 }
13297 if (tmp->hwtxgain_enabled) {
13298 tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
13299 }
13300 set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
13301 if (tmp->dsp)
13303 dahdi_conf_update(tmp);
13304 if (!here) {
13305 switch (chan_sig) {
13307 case SIG_SS7:
13308 case SIG_MFCR2:
13309 break;
13310 default:
13311 /* Hang it up to be sure it's good */
13312 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
13313 break;
13314 }
13315 }
13316 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
13317 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
13318 /* the dchannel is down so put the channel in alarm */
13319 switch (tmp->sig) {
13320#ifdef HAVE_PRI
13322 sig_pri_set_alarm(tmp->sig_pvt, 1);
13323 break;
13324#endif
13325#if defined(HAVE_SS7)
13326 case SIG_SS7:
13327 sig_ss7_set_alarm(tmp->sig_pvt, 1);
13328 break;
13329#endif /* defined(HAVE_SS7) */
13330 default:
13331 /* The only sig submodule left should be sig_analog. */
13332 analog_p = tmp->sig_pvt;
13333 if (analog_p) {
13334 analog_p->inalarm = 1;
13335 }
13336 tmp->inalarm = 1;
13337 break;
13338 }
13339 handle_alarms(tmp, res);
13340 }
13341 }
13342
13343 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13344 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13345 tmp->ani_info_digits = conf->chan.ani_info_digits;
13346 tmp->ani_wink_time = conf->chan.ani_wink_time;
13347 tmp->ani_timeout = conf->chan.ani_timeout;
13348 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13349 tmp->reoriginate = conf->chan.reoriginate;
13350 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
13351 ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
13352
13353 if (!here) {
13354 tmp->locallyblocked = 0;
13355 tmp->remotelyblocked = 0;
13356 switch (tmp->sig) {
13357#if defined(HAVE_PRI)
13359 tmp->inservice = 1;/* Inservice until actually implemented. */
13360#if defined(HAVE_PRI_SERVICE_MESSAGES)
13361 ((struct sig_pri_chan *) tmp->sig_pvt)->service_status = 0;
13362 if (chan_sig == SIG_PRI) {
13363 char db_chan_name[20];
13364 char db_answer[5];
13365
13366 /*
13367 * Initialize the active out-of-service status
13368 * and delete any record if the feature is not enabled.
13369 */
13370 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
13371 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
13372 unsigned *why;
13373
13374 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
13375 if (tmp->pri->enable_service_message_support) {
13376 char state;
13377
13378 sscanf(db_answer, "%1c:%30u", &state, why);
13379
13380 /* Ensure that only the implemented bits could be set.*/
13381 *why &= (SRVST_NEAREND | SRVST_FAREND);
13382 }
13383 if (!*why) {
13384 ast_db_del(db_chan_name, SRVST_DBKEY);
13385 }
13386 }
13387 }
13388#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13389 break;
13390#endif /* defined(HAVE_PRI) */
13391#if defined(HAVE_SS7)
13392 case SIG_SS7:
13393 tmp->inservice = 0;
13394 if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
13396 }
13397 break;
13398#endif /* defined(HAVE_SS7) */
13399 default:
13400 /* We default to in service on protocols that don't have a reset */
13401 tmp->inservice = 1;
13402 break;
13403 }
13404 }
13405
13406 switch (tmp->sig) {
13407#if defined(HAVE_PRI)
13409 if (pri_chan) {
13410 pri_chan->channel = tmp->channel;
13411 pri_chan->hidecallerid = tmp->hidecallerid;
13412 pri_chan->hidecalleridname = tmp->hidecalleridname;
13413 pri_chan->immediate = tmp->immediate;
13414 pri_chan->inalarm = tmp->inalarm;
13415 pri_chan->priexclusive = tmp->priexclusive;
13416 pri_chan->priindication_oob = tmp->priindication_oob;
13417 pri_chan->use_callerid = tmp->use_callerid;
13418 pri_chan->use_callingpres = tmp->use_callingpres;
13419 ast_copy_string(pri_chan->context, tmp->context,
13420 sizeof(pri_chan->context));
13422 sizeof(pri_chan->mohinterpret));
13423 pri_chan->stripmsd = tmp->stripmsd;
13424 }
13425 break;
13426#endif /* defined(HAVE_PRI) */
13427#if defined(HAVE_SS7)
13428 case SIG_SS7:
13429 if (ss7_chan) {
13430 ss7_chan->inalarm = tmp->inalarm;
13431 ss7_chan->inservice = tmp->inservice;
13432
13433 ss7_chan->stripmsd = tmp->stripmsd;
13434 ss7_chan->hidecallerid = tmp->hidecallerid;
13435 ss7_chan->use_callerid = tmp->use_callerid;
13436 ss7_chan->use_callingpres = tmp->use_callingpres;
13437 ss7_chan->immediate = tmp->immediate;
13438 ss7_chan->locallyblocked = tmp->locallyblocked;
13439 ss7_chan->remotelyblocked = tmp->remotelyblocked;
13440 ast_copy_string(ss7_chan->context, tmp->context,
13441 sizeof(ss7_chan->context));
13443 sizeof(ss7_chan->mohinterpret));
13444 }
13445 break;
13446#endif /* defined(HAVE_SS7) */
13447 default:
13448 /* The only sig submodule left should be sig_analog. */
13449 analog_p = tmp->sig_pvt;
13450 if (analog_p) {
13451 analog_p->channel = tmp->channel;
13452 analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13453 analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13454 analog_p->ani_info_digits = conf->chan.ani_info_digits;
13455 analog_p->ani_timeout = conf->chan.ani_timeout;
13456 analog_p->ani_wink_time = conf->chan.ani_wink_time;
13457 analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13458 analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13459 analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
13460 analog_p->callreturn = conf->chan.callreturn;
13461 analog_p->lastnumredial = conf->chan.lastnumredial; /* Only actually used in analog pvt, not DAHDI pvt */
13462 analog_p->cancallforward = conf->chan.cancallforward;
13463 analog_p->canpark = conf->chan.canpark;
13464 analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
13465 analog_p->immediate = conf->chan.immediate;
13466 analog_p->immediatering = conf->chan.immediatering;
13467 analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13468 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13469 analog_p->pulse = conf->chan.pulse;
13470 analog_p->threewaycalling = conf->chan.threewaycalling;
13471 analog_p->transfer = conf->chan.transfer;
13472 analog_p->transfertobusy = conf->chan.transfertobusy;
13473 analog_p->dialmode = conf->chan.dialmode;
13474 analog_p->use_callerid = tmp->use_callerid;
13476 analog_p->use_smdi = tmp->use_smdi;
13477 analog_p->smdi_iface = tmp->smdi_iface;
13478 analog_p->outsigmod = ANALOG_SIG_NONE;
13479 analog_p->echotraining = conf->chan.echotraining;
13480 analog_p->cid_signalling = conf->chan.cid_signalling;
13481 analog_p->stripmsd = conf->chan.stripmsd;
13482 switch (conf->chan.cid_start) {
13483 case CID_START_POLARITY:
13485 break;
13488 break;
13491 break;
13492 default:
13493 analog_p->cid_start = ANALOG_CID_START_RING;
13494 break;
13495 }
13496 analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
13497 analog_p->callwaitingdeluxe = conf->chan.callwaitingdeluxe;
13498 analog_p->ringt = conf->chan.ringt;
13499 analog_p->ringt_base = ringt_base;
13500 analog_p->onhooktime = time(NULL);
13501 if (chan_sig & __DAHDI_SIG_FXO) {
13502 memset(&p, 0, sizeof(p));
13503 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13504 if (!res) {
13505 analog_p->fxsoffhookstate = p.rxisoffhook;
13506 }
13507#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13508 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
13509#endif
13510 }
13511 analog_p->msgstate = -1;
13512
13513 ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
13514 ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
13515 ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
13516
13517 analog_config_complete(analog_p);
13518 }
13519 break;
13520 }
13521#if defined(HAVE_PRI)
13522 if (tmp->channel == CHAN_PSEUDO) {
13523 /*
13524 * Save off pseudo channel buffer policy values for dynamic creation of
13525 * no B channel interfaces.
13526 */
13527 dahdi_pseudo_parms.buf_no = tmp->buf_no;
13528 dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
13529 dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
13530 dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
13531 }
13532#endif /* defined(HAVE_PRI) */
13533 }
13534 if (tmp && !here) {
13535 /* Add the new channel interface to the sorted channel interface list. */
13537 }
13538 return tmp;
13539}
13540
13541static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
13542{
13543#if defined(HAVE_PRI)
13544 if (0 < span) {
13545 /* The channel must be on the specified PRI span. */
13546 if (!p->pri || p->pri->span != span) {
13547 return 0;
13548 }
13549 if (!groupmatch && channelmatch == -1) {
13550 /* Match any group since it only needs to be on the PRI span. */
13551 *groupmatched = 1;
13552 return 1;
13553 }
13554 }
13555#endif /* defined(HAVE_PRI) */
13556 /* check group matching */
13557 if (groupmatch) {
13558 if ((p->group & groupmatch) != groupmatch)
13559 /* Doesn't match the specified group, try the next one */
13560 return 0;
13561 *groupmatched = 1;
13562 }
13563 /* Check to see if we have a channel match */
13564 if (channelmatch != -1) {
13565 if (p->channel != channelmatch)
13566 /* Doesn't match the specified channel, try the next one */
13567 return 0;
13568 *channelmatched = 1;
13569 }
13570
13571 return 1;
13572}
13573
13574static int available(struct dahdi_pvt **pvt, int is_specific_channel)
13575{
13576 struct dahdi_pvt *p = *pvt;
13577
13578 if (p->inalarm)
13579 return 0;
13580
13581 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
13582 return analog_available(p->sig_pvt);
13583
13584 switch (p->sig) {
13585#if defined(HAVE_PRI)
13587 {
13588 struct sig_pri_chan *pvt_chan;
13589 int res;
13590
13591 pvt_chan = p->sig_pvt;
13592 res = sig_pri_available(&pvt_chan, is_specific_channel);
13593 *pvt = pvt_chan->chan_pvt;
13594 return res;
13595 }
13596#endif /* defined(HAVE_PRI) */
13597#if defined(HAVE_SS7)
13598 case SIG_SS7:
13599 return sig_ss7_available(p->sig_pvt);
13600#endif /* defined(HAVE_SS7) */
13601 default:
13602 break;
13603 }
13604
13605 if (p->locallyblocked || p->remotelyblocked) {
13606 return 0;
13607 }
13608
13609 /* If no owner definitely available */
13610 if (!p->owner) {
13611#ifdef HAVE_OPENR2
13612 /* Trust MFC/R2 */
13613 if (p->mfcr2) {
13614 if (p->mfcr2call) {
13615 return 0;
13616 } else {
13617 return 1;
13618 }
13619 }
13620#endif
13621 return 1;
13622 }
13623
13624 return 0;
13625}
13626
13627#if defined(HAVE_PRI)
13628#if defined(HAVE_PRI_CALL_WAITING)
13629/*!
13630 * \internal
13631 * \brief Init the private channel configuration using the span controller.
13632 * \since 1.8
13633 *
13634 * \param priv Channel to init the configuration.
13635 * \param pri sig_pri PRI control structure.
13636 *
13637 * \note Assumes the pri->lock is already obtained.
13638 */
13639static void my_pri_init_config(void *priv, struct sig_pri_span *pri)
13640{
13641 struct dahdi_pvt *pvt = priv;
13642
13643 pvt->stripmsd = pri->ch_cfg.stripmsd;
13644 pvt->hidecallerid = pri->ch_cfg.hidecallerid;
13645 pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
13646 pvt->immediate = pri->ch_cfg.immediate;
13647 pvt->priexclusive = pri->ch_cfg.priexclusive;
13648 pvt->priindication_oob = pri->ch_cfg.priindication_oob;
13649 pvt->use_callerid = pri->ch_cfg.use_callerid;
13650 pvt->use_callingpres = pri->ch_cfg.use_callingpres;
13651 ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
13652 ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
13653}
13654#endif /* defined(HAVE_PRI_CALL_WAITING) */
13655#endif /* defined(HAVE_PRI) */
13656
13657#if defined(HAVE_PRI)
13658/*!
13659 * \internal
13660 * \brief Create a no B channel interface.
13661 * \since 1.8
13662 *
13663 * \param pri sig_pri span controller to add interface.
13664 *
13665 * \note Assumes the pri->lock is already obtained.
13666 *
13667 * \retval array-index into private pointer array on success.
13668 * \retval -1 on error.
13669 */
13670static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri)
13671{
13672 int pvt_idx;
13673 int res;
13674 unsigned idx;
13675 struct dahdi_pvt *pvt;
13676 struct sig_pri_chan *chan;
13677 struct dahdi_bufferinfo bi;
13678
13679 static int nobch_channel = CHAN_PSEUDO;
13680
13681 /* Find spot in the private pointer array for new interface. */
13682 for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
13683 if (!pri->pvts[pvt_idx]) {
13684 break;
13685 }
13686 }
13687 if (pri->numchans == pvt_idx) {
13688 if (ARRAY_LEN(pri->pvts) <= pvt_idx) {
13689 ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
13690 return -1;
13691 }
13692
13693 /* Add new spot to the private pointer array. */
13694 pri->pvts[pvt_idx] = NULL;
13695 ++pri->numchans;
13696 }
13697
13698 pvt = ast_calloc(1, sizeof(*pvt));
13699 if (!pvt) {
13700 return -1;
13701 }
13703 if (!pvt->cc_params) {
13704 ast_free(pvt);
13705 return -1;
13706 }
13707 ast_mutex_init(&pvt->lock);
13708 for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
13709 pvt->subs[idx].dfd = -1;
13710 }
13711 pvt->buf_no = dahdi_pseudo_parms.buf_no;
13712 pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
13713 pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
13714 pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
13715
13716 chan = sig_pri_chan_new(pvt, pri, 0, 0, 0);
13717 if (!chan) {
13718 destroy_dahdi_pvt(pvt);
13719 return -1;
13720 }
13721 chan->no_b_channel = 1;
13722
13723 /*
13724 * Pseudo channel companding law.
13725 * Needed for outgoing call waiting calls.
13726 * XXX May need to make this determined by switchtype or user option.
13727 */
13728 pvt->law_default = DAHDI_LAW_ALAW;
13729
13730 pvt->sig = pri->sig;
13731 pvt->outsigmod = -1;
13732 pvt->pri = pri;
13733 pvt->sig_pvt = chan;
13734 pri->pvts[pvt_idx] = chan;
13735
13736 pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13737 if (pvt->subs[SUB_REAL].dfd < 0) {
13738 ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
13739 strerror(errno));
13740 destroy_dahdi_pvt(pvt);
13741 return -1;
13742 }
13743 memset(&bi, 0, sizeof(bi));
13744 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13745 if (!res) {
13746 pvt->bufsize = bi.bufsize;
13747 bi.txbufpolicy = pvt->buf_policy;
13748 bi.rxbufpolicy = pvt->buf_policy;
13749 bi.numbufs = pvt->buf_no;
13750 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13751 if (res < 0) {
13753 "Unable to set buffer policy on no B channel interface: %s\n",
13754 strerror(errno));
13755 }
13756 } else
13758 "Unable to check buffer policy on no B channel interface: %s\n",
13759 strerror(errno));
13760
13761 --nobch_channel;
13762 if (CHAN_PSEUDO < nobch_channel) {
13763 nobch_channel = CHAN_PSEUDO - 1;
13764 }
13765 pvt->channel = nobch_channel;
13766 pvt->span = pri->span;
13767 chan->channel = pvt->channel;
13768
13769 dahdi_nobch_insert(pri, pvt);
13770
13771 return pvt_idx;
13772}
13773#endif /* defined(HAVE_PRI) */
13774
13775/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13776 structures; it makes no attempt to safely copy regular channel private
13777 structures that might contain reference-counted object pointers and other
13778 scary bits
13779*/
13780static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src)
13781{
13782 struct dahdi_pvt *p;
13783 struct dahdi_bufferinfo bi;
13784 int res;
13785
13786 p = ast_malloc(sizeof(*p));
13787 if (!p) {
13788 return NULL;
13789 }
13790 *p = *src;
13791
13792 /* Must deep copy the cc_params. */
13794 if (!p->cc_params) {
13795 ast_free(p);
13796 return NULL;
13797 }
13799
13801 p->next = NULL;
13802 p->prev = NULL;
13803 ast_mutex_init(&p->lock);
13804 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13805 if (p->subs[SUB_REAL].dfd < 0) {
13806 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
13808 return NULL;
13809 }
13810 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13811 if (!res) {
13812 bi.txbufpolicy = src->buf_policy;
13813 bi.rxbufpolicy = src->buf_policy;
13814 bi.numbufs = src->buf_no;
13815 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13816 if (res < 0) {
13817 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
13818 }
13819 } else
13820 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
13821 p->destroy = 1;
13823 return p;
13824}
13825
13827 /*! Group matching mask. Zero if not specified. */
13829 /*! DAHDI channel to match with. -1 if not specified. */
13831 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13833 /*! ISDN span where channels can be picked (Zero if not specified) */
13834 int span;
13835 /*! Analog channel distinctive ring cadence index. */
13837 /*! Dialing option. c/r/d if present and valid. */
13838 char opt;
13839 /*! TRUE if to search the channel list backwards. */
13841 /*! TRUE if search is done with round robin sequence. */
13843};
13844static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
13845{
13846 char *dest;
13847 char *s;
13848 int x;
13849 int res = 0;
13850 struct dahdi_pvt *p;
13851 char *subdir = NULL;
13853 AST_APP_ARG(group); /* channel/group token */
13854 //AST_APP_ARG(ext); /* extension token */
13855 //AST_APP_ARG(opts); /* options token */
13856 AST_APP_ARG(other); /* Any remaining unused arguments */
13857 );
13858
13859 /*
13860 * data is ---v
13861 * Dial(DAHDI/pseudo[/extension[/options]])
13862 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13863 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13864 * Dial(DAHDI/i<span>[/extension[/options]])
13865 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13866 *
13867 * i - ISDN span channel restriction.
13868 * Used by CC to ensure that the CC recall goes out the same span.
13869 * Also to make ISDN channel names dialable when the sequence number
13870 * is stripped off. (Used by DTMF attended transfer feature.)
13871 *
13872 * g - channel group allocation search forward
13873 * G - channel group allocation search backward
13874 * r - channel group allocation round robin search forward
13875 * R - channel group allocation round robin search backward
13876 *
13877 * c - Wait for DTMF digit to confirm answer
13878 * r<cadence#> - Set distinctive ring cadence number
13879 * d - Force bearer capability for ISDN/SS7 call to digital.
13880 */
13881
13882 if (data) {
13883 dest = ast_strdupa(data);
13884 } else {
13885 ast_log(LOG_WARNING, "Channel requested with no data\n");
13886 return NULL;
13887 }
13888 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
13889 if (!args.argc || ast_strlen_zero(args.group)) {
13890 ast_log(LOG_WARNING, "No channel/group specified\n");
13891 return NULL;
13892 }
13893
13894 /* Initialize the output parameters */
13895 memset(param, 0, sizeof(*param));
13896 param->channelmatch = -1;
13897
13898 if (strchr(args.group, '!') != NULL) {
13899 char *prev = args.group;
13900 while ((s = strchr(prev, '!')) != NULL) {
13901 *s++ = '/';
13902 prev = s;
13903 }
13904 *(prev - 1) = '\0';
13905 subdir = args.group;
13906 args.group = prev;
13907 } else if (args.group[0] == 'i') {
13908 /* Extract the ISDN span channel restriction specifier. */
13909 res = sscanf(args.group + 1, "%30d", &x);
13910 if (res < 1) {
13911 ast_log(LOG_WARNING, "Unable to determine ISDN span for data %s\n", data);
13912 return NULL;
13913 }
13914 param->span = x;
13915
13916 /* Remove the ISDN span channel restriction specifier. */
13917 s = strchr(args.group, '-');
13918 if (!s) {
13919 /* Search all groups since we are ISDN span restricted. */
13920 return iflist;
13921 }
13922 args.group = s + 1;
13923 res = 0;
13924 }
13925 if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
13926 /* Retrieve the group number */
13927 s = args.group + 1;
13928 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13929 if (res < 1) {
13930 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
13931 return NULL;
13932 }
13933 param->groupmatch = ((ast_group_t) 1 << x);
13934
13935 if (toupper(args.group[0]) == 'G') {
13936 if (args.group[0] == 'G') {
13937 param->backwards = 1;
13938 p = ifend;
13939 } else
13940 p = iflist;
13941 } else {
13942 if (ARRAY_LEN(round_robin) <= x) {
13943 ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
13944 x, data);
13945 return NULL;
13946 }
13947 if (args.group[0] == 'R') {
13948 param->backwards = 1;
13949 p = round_robin[x] ? round_robin[x]->prev : ifend;
13950 if (!p)
13951 p = ifend;
13952 } else {
13953 p = round_robin[x] ? round_robin[x]->next : iflist;
13954 if (!p)
13955 p = iflist;
13956 }
13957 param->roundrobin = 1;
13958 param->rr_starting_point = x;
13959 }
13960 } else {
13961 s = args.group;
13962 if (!strcasecmp(s, "pseudo")) {
13963 /* Special case for pseudo */
13964 x = CHAN_PSEUDO;
13965 param->channelmatch = x;
13966 } else {
13967 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13968 if (res < 1) {
13969 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
13970 return NULL;
13971 } else {
13972 param->channelmatch = x;
13973 }
13974 }
13975 if (subdir) {
13976 char path[PATH_MAX];
13977 struct stat stbuf;
13978
13979 snprintf(path, sizeof(path), "/dev/dahdi/%s/%d",
13980 subdir, param->channelmatch);
13981 if (stat(path, &stbuf) < 0) {
13982 ast_log(LOG_WARNING, "stat(%s) failed: %s\n",
13983 path, strerror(errno));
13984 return NULL;
13985 }
13986 if (!S_ISCHR(stbuf.st_mode)) {
13987 ast_log(LOG_ERROR, "%s: Not a character device file\n",
13988 path);
13989 return NULL;
13990 }
13991 param->channelmatch = minor(stbuf.st_rdev);
13992 }
13993
13994 p = iflist;
13995 }
13996
13997 if (param->opt == 'r' && res < 3) {
13998 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
13999 param->opt = '\0';
14000 }
14001
14002 return p;
14003}
14004
14005static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
14006 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
14007 const char *data, int *cause)
14008{
14009 int callwait = 0;
14010 struct dahdi_pvt *p;
14011 struct ast_channel *tmp = NULL;
14012 struct dahdi_pvt *exitpvt;
14013 int channelmatched = 0;
14014 int foundowner = 0;
14015 int groupmatched = 0;
14016#if defined(HAVE_PRI) || defined(HAVE_SS7)
14017 int transcapdigital = 0;
14018#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14019 struct dahdi_starting_point start;
14020 ast_callid callid = 0;
14021 int callid_created = ast_callid_threadstorage_auto(&callid);
14022
14024 p = determine_starting_point(data, &start);
14025 if (!p) {
14026 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
14028 ast_callid_threadstorage_auto_clean(callid, callid_created);
14029 return NULL;
14030 }
14031
14032 /* Search for an unowned channel */
14033 exitpvt = p;
14034 while (p && !tmp) {
14035 if (start.roundrobin)
14036 round_robin[start.rr_starting_point] = p;
14037
14038 if (p->owner) {
14039 foundowner++;
14040 }
14041
14042 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
14043 && available(&p, channelmatched)) {
14044 ast_debug(1, "Using channel %d\n", p->channel);
14045
14046 callwait = (p->owner != NULL);
14047#ifdef HAVE_OPENR2
14048 if (p->mfcr2) {
14049 ast_mutex_lock(&p->lock);
14050 if (p->mfcr2call) {
14052 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
14053 goto next;
14054 }
14055 p->mfcr2call = 1;
14057 }
14058#endif
14059 if (p->channel == CHAN_PSEUDO) {
14060 p = duplicate_pseudo(p);
14061 if (!p) {
14062 break;
14063 }
14064 }
14065
14066 p->distinctivering = 0;
14067 /* Make special notes */
14068 switch (start.opt) {
14069 case '\0':
14070 /* No option present. */
14071 break;
14072 case 'c':
14073 /* Confirm answer */
14074 p->confirmanswer = 1;
14075 break;
14076 case 'r':
14077 /* Distinctive ring */
14078 p->distinctivering = start.cadence;
14079 break;
14080 case 'd':
14081#if defined(HAVE_PRI) || defined(HAVE_SS7)
14082 /* If this is an ISDN call, make it digital */
14083 transcapdigital = AST_TRANS_CAP_DIGITAL;
14084#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14085 break;
14086 default:
14087 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, data);
14088 break;
14089 }
14090
14091 p->outgoing = 1;
14092 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
14093 tmp = analog_request(p->sig_pvt, &callwait, requestor);
14094#ifdef HAVE_PRI
14095 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
14096 /*
14097 * We already have the B channel reserved for this call. We
14098 * just need to make sure that dahdi_hangup() has completed
14099 * cleaning up before continuing.
14100 */
14101 ast_mutex_lock(&p->lock);
14103
14105 sizeof(p->dnid));
14106 tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
14107#endif
14108#if defined(HAVE_SS7)
14109 } else if (p->sig == SIG_SS7) {
14110 tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
14111#endif /* defined(HAVE_SS7) */
14112 } else {
14113 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
14114 }
14115 if (!tmp) {
14116 p->outgoing = 0;
14117#if defined(HAVE_PRI)
14118 switch (p->sig) {
14120#if defined(HAVE_PRI_CALL_WAITING)
14121 if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
14122 ((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
14123 ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
14124 }
14125#endif /* defined(HAVE_PRI_CALL_WAITING) */
14126 /*
14127 * This should be the last thing to clear when we are done with
14128 * the channel.
14129 */
14130 ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
14131 break;
14132 default:
14133 break;
14134 }
14135#endif /* defined(HAVE_PRI) */
14136 } else {
14137 snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", data);
14138 }
14139 break;
14140 }
14141#ifdef HAVE_OPENR2
14142next:
14143#endif
14144 if (start.backwards) {
14145 p = p->prev;
14146 if (!p)
14147 p = ifend;
14148 } else {
14149 p = p->next;
14150 if (!p)
14151 p = iflist;
14152 }
14153 /* stop when you roll to the one that we started from */
14154 if (p == exitpvt)
14155 break;
14156 }
14159 if (cause && !tmp) {
14160 if (callwait || (channelmatched && foundowner)) {
14161 *cause = AST_CAUSE_BUSY;
14162 } else if (groupmatched) {
14163 *cause = AST_CAUSE_CONGESTION;
14164 } else {
14165 /*
14166 * We did not match any channel requested.
14167 * Dialplan error requesting non-existant channel?
14168 */
14169 }
14170 }
14171
14172 ast_callid_threadstorage_auto_clean(callid, callid_created);
14173 return tmp;
14174}
14175
14176/*!
14177 * \internal
14178 * \brief Determine the device state for a given DAHDI device if we can.
14179 * \since 1.8
14180 *
14181 * \param data DAHDI device name after "DAHDI/".
14182 *
14183 * \retval device_state enum ast_device_state value.
14184 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14185 */
14186static int dahdi_devicestate(const char *data)
14187{
14188#if defined(HAVE_PRI)
14189 const char *device;
14190 unsigned span;
14191 int res;
14192
14193 device = data;
14194
14195 if (*device != 'I') {
14196 /* The request is not for an ISDN span device. */
14197 return AST_DEVICE_UNKNOWN;
14198 }
14199 res = sscanf(device, "I%30u", &span);
14200 if (res != 1 || !span || NUM_SPANS < span) {
14201 /* Bad format for ISDN span device name. */
14202 return AST_DEVICE_UNKNOWN;
14203 }
14204 device = strchr(device, '/');
14205 if (!device) {
14206 /* Bad format for ISDN span device name. */
14207 return AST_DEVICE_UNKNOWN;
14208 }
14209
14210 /*
14211 * Since there are currently no other span devstate's defined,
14212 * it must be congestion.
14213 */
14214#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14215 ++device;
14216 if (!strcmp(device, "congestion"))
14217#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14218 {
14219 return pris[span - 1].pri.congestion_devstate;
14220 }
14221#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14222 else if (!strcmp(device, "threshold")) {
14223 return pris[span - 1].pri.threshold_devstate;
14224 }
14225 return AST_DEVICE_UNKNOWN;
14226#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14227#else
14228 return AST_DEVICE_UNKNOWN;
14229#endif /* defined(HAVE_PRI) */
14230}
14231
14232/*!
14233 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14234 * \since 1.8
14235 *
14236 * \param inbound Incoming asterisk channel.
14237 * \param dest Same dial string passed to dahdi_request().
14238 * \param callback Callback into CC core to announce a busy channel available for CC.
14239 *
14240 * \details
14241 * This callback acts like a forked dial with all prongs of the fork busy.
14242 * Essentially, for each channel that could have taken the call, indicate that
14243 * it is busy.
14244 *
14245 * \retval 0 on success.
14246 * \retval -1 on error.
14247 */
14248static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
14249{
14250 struct dahdi_pvt *p;
14251 struct dahdi_pvt *exitpvt;
14252 struct dahdi_starting_point start;
14253 int groupmatched = 0;
14254 int channelmatched = 0;
14255
14257 p = determine_starting_point(dest, &start);
14258 if (!p) {
14260 return -1;
14261 }
14262 exitpvt = p;
14263 for (;;) {
14264 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
14265 /* We found a potential match. call the callback */
14266 struct ast_str *device_name;
14267 char *dash;
14268 const char *monitor_type;
14269 char dialstring[AST_CHANNEL_NAME];
14270 char full_device_name[AST_CHANNEL_NAME];
14271
14274 break;
14278#if defined(HAVE_PRI)
14280 /*
14281 * ISDN is in a trunk busy condition so we need to monitor
14282 * the span congestion device state.
14283 */
14284 snprintf(full_device_name, sizeof(full_device_name),
14285 "DAHDI/I%d/congestion", p->pri->span);
14286 } else
14287#endif /* defined(HAVE_PRI) */
14288 {
14289#if defined(HAVE_PRI)
14290 device_name = create_channel_name(p, 1, "");
14291#else
14292 device_name = create_channel_name(p);
14293#endif /* defined(HAVE_PRI) */
14294 snprintf(full_device_name, sizeof(full_device_name), "DAHDI/%s",
14295 device_name ? ast_str_buffer(device_name) : "");
14296 ast_free(device_name);
14297 /*
14298 * The portion after the '-' in the channel name is either a random
14299 * number, a sequence number, or a subchannel number. None are
14300 * necessary so strip them off.
14301 */
14302 dash = strrchr(full_device_name, '-');
14303 if (dash) {
14304 *dash = '\0';
14305 }
14306 }
14307 snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
14308
14309 /*
14310 * Analog can only do generic monitoring.
14311 * ISDN is in a trunk busy condition and any "device" is going
14312 * to be busy until a B channel becomes available. The generic
14313 * monitor can do this task.
14314 */
14315 monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
14316 callback(inbound,
14317#if defined(HAVE_PRI)
14318 p->pri ? p->pri->cc_params : p->cc_params,
14319#else
14320 p->cc_params,
14321#endif /* defined(HAVE_PRI) */
14322 monitor_type, full_device_name, dialstring, NULL);
14323 break;
14324 }
14325 }
14326 p = start.backwards ? p->prev : p->next;
14327 if (!p) {
14328 p = start.backwards ? ifend : iflist;
14329 }
14330 if (p == exitpvt) {
14331 break;
14332 }
14333 }
14335 return 0;
14336}
14337
14338#if defined(HAVE_SS7)
14339static void dahdi_ss7_message(struct ss7 *ss7, char *s)
14340{
14341 int i;
14342
14343 if (ss7) {
14344 for (i = 0; i < NUM_SPANS; i++) {
14345 if (linksets[i].ss7.ss7 == ss7) {
14346 ast_verbose_callid(0, "[%d] %s", i + 1, s);
14347 return;
14348 }
14349 }
14350 }
14351 ast_verbose_callid(0, "%s", s);
14352}
14353#endif /* defined(HAVE_SS7) */
14354
14355#if defined(HAVE_SS7)
14356static void dahdi_ss7_error(struct ss7 *ss7, char *s)
14357{
14358 int i;
14359
14360 if (ss7) {
14361 for (i = 0; i < NUM_SPANS; i++) {
14362 if (linksets[i].ss7.ss7 == ss7) {
14363 ast_log_callid(LOG_ERROR, 0, "[%d] %s", i + 1, s);
14364 return;
14365 }
14366 }
14367 }
14368 ast_log_callid(LOG_ERROR, 0, "%s", s);
14369}
14370#endif /* defined(HAVE_SS7) */
14371
14372#if defined(HAVE_OPENR2)
14373static void *mfcr2_monitor(void *data)
14374{
14375 struct dahdi_mfcr2 *mfcr2 = data;
14376 struct dahdi_pvt *pvt;
14377
14378 /* we should be using pthread_key_create
14379 and allocate pollers dynamically.
14380 I think do_monitor() could be leaking, since it
14381 could be cancelled at any time and is not
14382 using thread keys, why?, */
14383 struct pollfd pollers[ARRAY_LEN(mfcr2->pvts)];
14384 int res = 0;
14385 int i = 0;
14386 int oldstate = 0;
14387 int quit_loop = 0;
14388 int maxsleep = 20;
14389 int was_idle = 0;
14390 int pollsize = 0;
14391 /* now that we're ready to get calls, unblock our side and
14392 get current line state */
14393 for (i = 0; i < mfcr2->numchans; i++) {
14394 pvt = mfcr2->pvts[i];
14395 if (!pvt) {
14396 continue;
14397 }
14398 openr2_chan_set_idle(pvt->r2chan);
14399 openr2_chan_handle_cas(pvt->r2chan);
14400 }
14401 while (1) {
14402 /* we trust here that the mfcr2 channel list will not ever change once
14403 the module is loaded */
14404 pollsize = 0;
14405 for (i = 0; i < mfcr2->numchans; i++) {
14406 pollers[i].revents = 0;
14407 pollers[i].events = 0;
14408 pvt = mfcr2->pvts[i];
14409 if (!pvt) {
14410 continue;
14411 }
14412 if (pvt->owner) {
14413 continue;
14414 }
14415 if (mfcr2->nodev) {
14416 continue;
14417 }
14418 if (!pvt->r2chan) {
14419 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
14420 quit_loop = 1;
14421 break;
14422 }
14423 openr2_chan_enable_read(pvt->r2chan);
14424 pollers[i].events = POLLIN | POLLPRI;
14425 pollers[i].fd = pvt->subs[SUB_REAL].dfd;
14426 pollsize++;
14427 }
14428 if (quit_loop) {
14429 break;
14430 }
14431 if (pollsize == 0) {
14432 if (!was_idle) {
14433 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14434 was_idle = 1;
14435 }
14436 poll(NULL, 0, maxsleep);
14437 continue;
14438 }
14439 was_idle = 0;
14440 /* probably poll() is a valid cancel point, lets just be on the safe side
14441 by calling pthread_testcancel */
14442 pthread_testcancel();
14443 res = poll(pollers, mfcr2->numchans, maxsleep);
14444 pthread_testcancel();
14445 if ((res < 0) && (errno != EINTR)) {
14446 ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
14447 break;
14448 }
14449 /* do we want to allow to cancel while processing events? */
14450 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
14451 for (i = 0; i < mfcr2->numchans; i++) {
14452 pvt = mfcr2->pvts[i];
14453 if (!pvt) {
14454 continue;
14455 }
14456 if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
14457 openr2_chan_process_event(pvt->r2chan);
14458 }
14459 }
14460 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14461 }
14462 ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
14463 return 0;
14464}
14465#endif /* HAVE_OPENR2 */
14466
14467#if defined(HAVE_PRI)
14468static void dahdi_pri_message(struct pri *pri, char *s)
14469{
14470 int x;
14471 int y;
14472 int dchan = -1;
14473 int span = -1;
14474 int dchancount = 0;
14475
14476 if (pri) {
14477 for (x = 0; x < NUM_SPANS; x++) {
14478 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14479 if (pris[x].pri.dchans[y]) {
14480 dchancount++;
14481 }
14482
14483 if (pris[x].pri.dchans[y] == pri) {
14484 dchan = y;
14485 }
14486 }
14487 if (dchan >= 0) {
14488 span = x;
14489 break;
14490 }
14491 dchancount = 0;
14492 }
14493 if (-1 < span) {
14494 if (1 < dchancount) {
14495 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14496 } else {
14497 ast_verbose_callid(0, "PRI Span: %d %s", span + 1, s);
14498 }
14499 } else {
14500 ast_verbose_callid(0, "PRI Span: ? %s", s);
14501 }
14502 } else {
14503 ast_verbose_callid(0, "PRI Span: ? %s", s);
14504 }
14505
14506 ast_mutex_lock(&pridebugfdlock);
14507
14508 if (pridebugfd >= 0) {
14509 if (write(pridebugfd, s, strlen(s)) < 0) {
14510 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14511 }
14512 }
14513
14514 ast_mutex_unlock(&pridebugfdlock);
14515}
14516#endif /* defined(HAVE_PRI) */
14517
14518#if defined(HAVE_PRI)
14519static void dahdi_pri_error(struct pri *pri, char *s)
14520{
14521 int x;
14522 int y;
14523 int dchan = -1;
14524 int span = -1;
14525 int dchancount = 0;
14526
14527 if (pri) {
14528 for (x = 0; x < NUM_SPANS; x++) {
14529 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14530 if (pris[x].pri.dchans[y]) {
14531 dchancount++;
14532 }
14533
14534 if (pris[x].pri.dchans[y] == pri) {
14535 dchan = y;
14536 }
14537 }
14538 if (dchan >= 0) {
14539 span = x;
14540 break;
14541 }
14542 dchancount = 0;
14543 }
14544 if (-1 < span) {
14545 if (1 < dchancount) {
14546 ast_log_callid(LOG_ERROR, 0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14547 } else {
14548 ast_log_callid(LOG_ERROR, 0, "PRI Span: %d %s", span + 1, s);
14549 }
14550 } else {
14551 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14552 }
14553 } else {
14554 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14555 }
14556
14557 ast_mutex_lock(&pridebugfdlock);
14558
14559 if (pridebugfd >= 0) {
14560 if (write(pridebugfd, s, strlen(s)) < 0) {
14561 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14562 }
14563 }
14564
14565 ast_mutex_unlock(&pridebugfdlock);
14566}
14567#endif /* defined(HAVE_PRI) */
14568
14569#if defined(HAVE_PRI)
14570static int prepare_pri(struct dahdi_pri *pri)
14571{
14572 int i, res, x;
14573 struct dahdi_params p;
14574 struct dahdi_bufferinfo bi;
14575 struct dahdi_spaninfo si;
14576
14577 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
14578 if (!pri->dchannels[i])
14579 break;
14580 if (pri->pri.fds[i] >= 0) {
14581 /* A partial range addition. Not a complete setup. */
14582 break;
14583 }
14584 pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
14585 if ((pri->pri.fds[i] < 0)) {
14586 ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
14587 pri->pri.fds[i], strerror(errno));
14588 return -1;
14589 }
14590 x = pri->dchannels[i];
14591 res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
14592 if (res) {
14593 dahdi_close_pri_fd(pri, i);
14594 ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
14595 return -1;
14596 }
14597 memset(&p, 0, sizeof(p));
14598 res = ioctl(pri->pri.fds[i], DAHDI_GET_PARAMS, &p);
14599 if (res) {
14600 dahdi_close_pri_fd(pri, i);
14601 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
14602 return -1;
14603 }
14604 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
14605 dahdi_close_pri_fd(pri, i);
14606 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
14607 return -1;
14608 }
14609 memset(&si, 0, sizeof(si));
14610 res = ioctl(pri->pri.fds[i], DAHDI_SPANSTAT, &si);
14611 if (res) {
14612 dahdi_close_pri_fd(pri, i);
14613 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
14614 }
14615 if (!si.alarms) {
14616 pri_event_noalarm(&pri->pri, i, 1);
14617 } else {
14618 pri_event_alarm(&pri->pri, i, 1);
14619 }
14620 memset(&bi, 0, sizeof(bi));
14621 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
14622 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
14623 bi.numbufs = 32;
14624 bi.bufsize = 1024;
14625 if (ioctl(pri->pri.fds[i], DAHDI_SET_BUFINFO, &bi)) {
14626 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
14627 dahdi_close_pri_fd(pri, i);
14628 return -1;
14629 }
14630 pri->pri.dchan_logical_span[i] = pris[p.spanno - 1].prilogicalspan;
14631 }
14632 return 0;
14633}
14634#endif /* defined(HAVE_PRI) */
14635
14636#if defined(HAVE_PRI)
14637static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
14638{
14639 int which, span;
14640 char *ret = NULL;
14641
14642 if (pos != rpos)
14643 return ret;
14644
14645 for (which = span = 0; span < NUM_SPANS; span++) {
14646 if (pris[span].pri.pri && ++which > state) {
14647 if (ast_asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
14648 ret = NULL;
14649 }
14650 break;
14651 }
14652 }
14653 return ret;
14654}
14655#endif /* defined(HAVE_PRI) */
14656
14657#if defined(HAVE_PRI)
14658static char *complete_span_4(const char *line, const char *word, int pos, int state)
14659{
14660 return complete_span_helper(line,word,pos,state,3);
14661}
14662#endif /* defined(HAVE_PRI) */
14663
14664#if defined(HAVE_PRI)
14665static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14666{
14667 int myfd;
14668 switch (cmd) {
14669 case CLI_INIT:
14670 e->command = "pri set debug file";
14671 e->usage = "Usage: pri set debug file [output-file]\n"
14672 " Sends PRI debug output to the specified output file\n";
14673 return NULL;
14674 case CLI_GENERATE:
14675 return NULL;
14676 }
14677 if (a->argc < 5)
14678 return CLI_SHOWUSAGE;
14679
14680 if (ast_strlen_zero(a->argv[4]))
14681 return CLI_SHOWUSAGE;
14682
14683 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
14684 if (myfd < 0) {
14685 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
14686 return CLI_SUCCESS;
14687 }
14688
14689 ast_mutex_lock(&pridebugfdlock);
14690
14691 if (pridebugfd >= 0)
14692 close(pridebugfd);
14693
14694 pridebugfd = myfd;
14695 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
14696 ast_mutex_unlock(&pridebugfdlock);
14697 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
14698 return CLI_SUCCESS;
14699}
14700#endif /* defined(HAVE_PRI) */
14701
14702#if defined(HAVE_PRI)
14703static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
14704{
14705 const char *output_file = astman_get_header(m, "File");
14706 int myfd;
14707
14708 if (ast_strlen_zero(output_file)) {
14709 astman_send_error(s, m, "Action must define a 'File'");
14710 }
14711
14712 myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
14713 if (myfd < 0) {
14714 astman_send_error(s, m, "Unable to open requested file for writing");
14715 return 0;
14716 }
14717
14718 ast_mutex_lock(&pridebugfdlock);
14719
14720 if (pridebugfd >= 0) {
14721 close(pridebugfd);
14722 }
14723
14724 pridebugfd = myfd;
14725 ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
14726 ast_mutex_unlock(&pridebugfdlock);
14727 astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
14728
14729 return 0;
14730}
14731#endif /* defined(HAVE_PRI) */
14732
14733#if defined(HAVE_PRI)
14734static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
14735{
14736 ast_mutex_lock(&pridebugfdlock);
14737
14738 if (pridebugfd >= 0) {
14739 close(pridebugfd);
14740 }
14741
14742 pridebugfd = -1;
14743
14744 ast_mutex_unlock(&pridebugfdlock);
14745
14746 astman_send_ack(s, m, "PRI Debug output to file disabled");
14747 return 0;
14748}
14749#endif /* defined(HAVE_PRI) */
14750
14751#if defined(HAVE_PRI)
14752static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14753{
14754 int span;
14755 int x;
14756 int debugmask = 0;
14757 int level = 0;
14758 switch (cmd) {
14759 case CLI_INIT:
14760 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";
14761 e->usage =
14762 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14763 " Enables debugging on a given PRI span\n"
14764 " Level is a bitmap of the following values:\n"
14765 " 1 General debugging incl. state changes\n"
14766 " 2 Decoded Q.931 messages\n"
14767 " 4 Decoded Q.921 messages\n"
14768 " 8 Raw hex dumps of Q.921 frames\n"
14769 " on - equivalent to 3\n"
14770 " hex - equivalent to 8\n"
14771 " intense - equivalent to 15\n";
14772 return NULL;
14773 case CLI_GENERATE:
14774 return complete_span_4(a->line, a->word, a->pos, a->n);
14775 }
14776 if (a->argc < 6) {
14777 return CLI_SHOWUSAGE;
14778 }
14779
14780 if (!strcasecmp(a->argv[3], "on")) {
14781 level = 3;
14782 } else if (!strcasecmp(a->argv[3], "off")) {
14783 level = 0;
14784 } else if (!strcasecmp(a->argv[3], "intense")) {
14785 level = 15;
14786 } else if (!strcasecmp(a->argv[3], "hex")) {
14787 level = 8;
14788 } else {
14789 level = atoi(a->argv[3]);
14790 }
14791 span = atoi(a->argv[5]);
14792 if ((span < 1) || (span > NUM_SPANS)) {
14793 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS);
14794 return CLI_SUCCESS;
14795 }
14796 if (!pris[span-1].pri.pri) {
14797 ast_cli(a->fd, "No PRI running on span %d\n", span);
14798 return CLI_SUCCESS;
14799 }
14800
14801 if (level & 1) debugmask |= SIG_PRI_DEBUG_NORMAL;
14802 if (level & 2) debugmask |= PRI_DEBUG_Q931_DUMP;
14803 if (level & 4) debugmask |= PRI_DEBUG_Q921_DUMP;
14804 if (level & 8) debugmask |= PRI_DEBUG_Q921_RAW;
14805
14806 /* Set debug level in libpri */
14807 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14808 if (pris[span - 1].pri.dchans[x]) {
14809 pri_set_debug(pris[span - 1].pri.dchans[x], debugmask);
14810 }
14811 }
14812 if (level == 0) {
14813 /* Close the debugging file if it's set */
14814 ast_mutex_lock(&pridebugfdlock);
14815 if (0 <= pridebugfd) {
14816 close(pridebugfd);
14817 pridebugfd = -1;
14818 ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
14819 pridebugfilename);
14820 }
14821 ast_mutex_unlock(&pridebugfdlock);
14822 }
14823 pris[span - 1].pri.debug = (level) ? 1 : 0;
14824 ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
14825 return CLI_SUCCESS;
14826}
14827#endif /* defined(HAVE_PRI) */
14828
14829#if defined(HAVE_PRI)
14830static int action_pri_debug_set(struct mansession *s, const struct message *m)
14831{
14832 const char *level = astman_get_header(m, "Level");
14833 const char *span = astman_get_header(m, "Span");
14834 int level_val;
14835 int span_val;
14836 int x;
14837 int debugmask = 0;
14838
14839 if (ast_strlen_zero(level)) {
14840 astman_send_error(s, m, "'Level' was not specified");
14841 return 0;
14842 }
14843
14844 if (ast_strlen_zero(span)) {
14845 astman_send_error(s, m, "'Span' was not specified");
14846 return 0;
14847 }
14848
14849 if (!strcasecmp(level, "on")) {
14850 level_val = 3;
14851 } else if (!strcasecmp(level, "off")) {
14852 level_val = 0;
14853 } else if (!strcasecmp(level, "intense")) {
14854 level_val = 15;
14855 } else if (!strcasecmp(level, "hex")) {
14856 level_val = 8;
14857 } else {
14858 if (sscanf(level, "%30d", &level_val) != 1) {
14859 astman_send_error(s, m, "Invalid value for 'Level'");
14860 return 0;
14861 }
14862 }
14863
14864 if (sscanf(span, "%30d", &span_val) != 1) {
14865 astman_send_error(s, m, "Invalid value for 'Span'");
14866 }
14867
14868 if ((span_val < 1) || (span_val > NUM_SPANS)) {
14869 const char *id = astman_get_header(m, "ActionID");
14870 char id_text[256] = "";
14871
14872 if (!ast_strlen_zero(id)) {
14873 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
14874 }
14875
14876 astman_append(s, "Response: Error\r\n"
14877 "%s" /* id_text */
14878 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14879 "\r\n",
14880 id_text,
14881 span, NUM_SPANS);
14882
14883 return 0;
14884 }
14885
14886 if (!pris[span_val-1].pri.pri) {
14887 astman_send_error(s, m, "No PRI running on requested span");
14888 return 0;
14889 }
14890
14891 if (level_val & 1) {
14892 debugmask |= SIG_PRI_DEBUG_NORMAL;
14893 }
14894 if (level_val & 2) {
14895 debugmask |= PRI_DEBUG_Q931_DUMP;
14896 }
14897 if (level_val & 4) {
14898 debugmask |= PRI_DEBUG_Q921_DUMP;
14899 }
14900 if (level_val & 8) {
14901 debugmask |= PRI_DEBUG_Q921_RAW;
14902 }
14903
14904 /* Set debug level in libpri */
14905 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14906 if (pris[span_val - 1].pri.dchans[x]) {
14907 pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
14908 }
14909 }
14910
14911 pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
14912 astman_send_ack(s, m, "Debug level set for requested span");
14913
14914 return 0;
14915}
14916#endif /* defined(HAVE_PRI) */
14917
14918#if defined(HAVE_PRI)
14919#if defined(HAVE_PRI_SERVICE_MESSAGES)
14920static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
14921{
14922 unsigned *why;
14923 int channel;
14924 int trunkgroup;
14925 int x, y, fd = a->fd;
14926 int interfaceid = 0;
14927 char db_chan_name[20], db_answer[15];
14928 struct dahdi_pvt *tmp;
14929 struct dahdi_pri *pri;
14930
14931 if (a->argc < 5 || a->argc > 6)
14932 return CLI_SHOWUSAGE;
14933 if (strchr(a->argv[4], ':')) {
14934 if (sscanf(a->argv[4], "%30d:%30d", &trunkgroup, &channel) != 2)
14935 return CLI_SHOWUSAGE;
14936 if ((trunkgroup < 1) || (channel < 1))
14937 return CLI_SHOWUSAGE;
14938 pri = NULL;
14939 for (x=0;x<NUM_SPANS;x++) {
14940 if (pris[x].pri.trunkgroup == trunkgroup) {
14941 pri = pris + x;
14942 break;
14943 }
14944 }
14945 if (!pri) {
14946 ast_cli(fd, "No such trunk group %d\n", trunkgroup);
14947 return CLI_FAILURE;
14948 }
14949 } else
14950 channel = atoi(a->argv[4]);
14951
14952 if (a->argc == 6)
14953 interfaceid = atoi(a->argv[5]);
14954
14955 /* either servicing a D-Channel */
14956 for (x = 0; x < NUM_SPANS; x++) {
14957 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14958 if (pris[x].dchannels[y] == channel) {
14959 pri = pris + x;
14960 if (pri->pri.enable_service_message_support) {
14961 ast_mutex_lock(&pri->pri.lock);
14962 pri_maintenance_service(pri->pri.pri, interfaceid, -1, changestatus);
14963 ast_mutex_unlock(&pri->pri.lock);
14964 } else {
14965 ast_cli(fd,
14966 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14967 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14968 }
14969 return CLI_SUCCESS;
14970 }
14971 }
14972 }
14973
14974 /* or servicing a B-Channel */
14976 for (tmp = iflist; tmp; tmp = tmp->next) {
14977 if (tmp->pri && tmp->channel == channel) {
14979 ast_mutex_lock(&tmp->pri->lock);
14980 if (!tmp->pri->enable_service_message_support) {
14981 ast_mutex_unlock(&tmp->pri->lock);
14982 ast_cli(fd,
14983 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14984 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14985 return CLI_SUCCESS;
14986 }
14987 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
14988 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
14989 switch(changestatus) {
14990 case 0: /* enable */
14991 /* Near end wants to be in service now. */
14992 ast_db_del(db_chan_name, SRVST_DBKEY);
14993 *why &= ~SRVST_NEAREND;
14994 if (*why) {
14995 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14996 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14997 } else {
14998 dahdi_pri_update_span_devstate(tmp->pri);
14999 }
15000 break;
15001 /* case 1: -- loop */
15002 case 2: /* disable */
15003 /* Near end wants to be out-of-service now. */
15004 ast_db_del(db_chan_name, SRVST_DBKEY);
15005 *why |= SRVST_NEAREND;
15006 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
15007 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
15008 dahdi_pri_update_span_devstate(tmp->pri);
15009 break;
15010 /* case 3: -- continuity */
15011 /* case 4: -- shutdown */
15012 default:
15013 ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
15014 break;
15015 }
15016 pri_maintenance_bservice(tmp->pri->pri, tmp->sig_pvt, changestatus);
15017 ast_mutex_unlock(&tmp->pri->lock);
15018 return CLI_SUCCESS;
15019 }
15020 }
15022
15023 ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
15024 return CLI_FAILURE;
15025}
15026
15027static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15028{
15029 switch (cmd) {
15030 case CLI_INIT:
15031 e->command = "pri service enable channel";
15032 e->usage =
15033 "Usage: pri service enable channel <channel> [<interface id>]\n"
15034 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15035 " to restore a channel to service, with optional interface id\n"
15036 " as agreed upon with remote switch operator\n";
15037 return NULL;
15038 case CLI_GENERATE:
15039 return NULL;
15040 }
15041 return handle_pri_service_generic(e, cmd, a, 0);
15042}
15043
15044static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15045{
15046 switch (cmd) {
15047 case CLI_INIT:
15048 e->command = "pri service disable channel";
15049 e->usage =
15050 "Usage: pri service disable channel <chan num> [<interface id>]\n"
15051 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15052 " to remove a channel from service, with optional interface id\n"
15053 " as agreed upon with remote switch operator\n";
15054 return NULL;
15055 case CLI_GENERATE:
15056 return NULL;
15057 }
15058 return handle_pri_service_generic(e, cmd, a, 2);
15059}
15060#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15061#endif /* defined(HAVE_PRI) */
15062
15063#if defined(HAVE_PRI)
15064static char *handle_pri_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15065{
15066 int span;
15067
15068 switch (cmd) {
15069 case CLI_INIT:
15070 e->command = "pri show channels";
15071 e->usage =
15072 "Usage: pri show channels\n"
15073 " Displays PRI channel information such as the current mapping\n"
15074 " of DAHDI B channels to Asterisk channel names and which calls\n"
15075 " are on hold or call-waiting. Calls on hold or call-waiting\n"
15076 " are not associated with any B channel.\n";
15077 return NULL;
15078 case CLI_GENERATE:
15079 return NULL;
15080 }
15081
15082 if (a->argc != 3)
15083 return CLI_SHOWUSAGE;
15084
15086 for (span = 0; span < NUM_SPANS; ++span) {
15087 if (pris[span].pri.pri) {
15088 sig_pri_cli_show_channels(a->fd, &pris[span].pri);
15089 }
15090 }
15091 return CLI_SUCCESS;
15092}
15093#endif /* defined(HAVE_PRI) */
15094
15095#if defined(HAVE_PRI)
15096static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15097{
15098 int span;
15099
15100 switch (cmd) {
15101 case CLI_INIT:
15102 e->command = "pri show spans";
15103 e->usage =
15104 "Usage: pri show spans\n"
15105 " Displays PRI span information\n";
15106 return NULL;
15107 case CLI_GENERATE:
15108 return NULL;
15109 }
15110
15111 if (a->argc != 3)
15112 return CLI_SHOWUSAGE;
15113
15114 for (span = 0; span < NUM_SPANS; span++) {
15115 if (pris[span].pri.pri) {
15116 sig_pri_cli_show_spans(a->fd, span + 1, &pris[span].pri);
15117 }
15118 }
15119 return CLI_SUCCESS;
15120}
15121#endif /* defined(HAVE_PRI) */
15122
15123#if defined(HAVE_PRI)
15124#define container_of(ptr, type, member) \
15125 ((type *)((char *)(ptr) - offsetof(type, member)))
15126/*!
15127 * \internal
15128 * \brief Destroy a D-Channel of a PRI span
15129 * \since 12
15130 *
15131 * \param pri the pri span
15132 *
15133 * Shuts down a span and destroys its D-Channel. Further destruction
15134 * of the B-channels using dahdi_destroy_channel() would probably be required
15135 * for the B-Channels.
15136 */
15137static void pri_destroy_span(struct sig_pri_span *pri)
15138{
15139 int i;
15140 int res;
15141 int cancel_code;
15142 struct dahdi_pri* dahdi_pri;
15143 pthread_t master = pri->master;
15144
15145 if (!master || (master == AST_PTHREADT_NULL)) {
15146 return;
15147 }
15148 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
15149 for (i = 0; i < pri->numchans; i++) {
15150 int channel;
15151 struct sig_pri_chan *pvt = pri->pvts[i];
15152
15153 if (!pvt) {
15154 continue;
15155 }
15156 channel = pvt->channel;
15157 ast_debug(2, "About to destroy B-channel %d.\n", channel);
15159 }
15160
15161 cancel_code = pthread_cancel(master);
15162 pthread_kill(master, SIGURG);
15163 ast_debug(4,
15164 "Waiting to join thread of span %d "
15165 "with pid=%p cancel_code=%d\n",
15166 pri->span, (void *)master, cancel_code);
15167 res = pthread_join(master, NULL);
15168 if (res != 0) {
15169 ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
15170 }
15172
15173 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
15174 dahdi_pri = container_of(pri, struct dahdi_pri, pri);
15175 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
15176 ast_debug(4, "closing pri_fd %d\n", i);
15177 dahdi_close_pri_fd(dahdi_pri, i);
15178 dahdi_pri->dchannels[i] = 0;
15179 }
15181 ast_debug(1, "PRI span %d destroyed\n", pri->span);
15182}
15183
15184static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
15185 struct ast_cli_args *a)
15186{
15187 int span;
15188 int res;
15189 struct sig_pri_span *pri;
15190
15191 switch (cmd) {
15192 case CLI_INIT:
15193 e->command = "pri destroy span";
15194 e->usage =
15195 "Usage: pri destroy span <span>\n"
15196 " Destroys D-channel of span and its B-channels.\n"
15197 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15198 return NULL;
15199 case CLI_GENERATE:
15200 return complete_span_4(a->line, a->word, a->pos, a->n);
15201 }
15202
15203 if (a->argc < 4) {
15204 return CLI_SHOWUSAGE;
15205 }
15206 res = sscanf(a->argv[3], "%30d", &span);
15207 if ((res != 1) || span < 1 || span > NUM_SPANS) {
15208 ast_cli(a->fd,
15209 "Invalid span '%s'. Should be a number from %d to %d\n",
15210 a->argv[3], 1, NUM_SPANS);
15211 return CLI_SUCCESS;
15212 }
15213 pri = &pris[span - 1].pri;
15214 if (!pri->pri) {
15215 ast_cli(a->fd, "No PRI running on span %d\n", span);
15216 return CLI_SUCCESS;
15217 }
15218
15219 pri_destroy_span(pri);
15220 return CLI_SUCCESS;
15221}
15222
15223#endif /* defined(HAVE_PRI) */
15224
15225#if defined(HAVE_PRI)
15226static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15227{
15228 int span;
15229
15230 switch (cmd) {
15231 case CLI_INIT:
15232 e->command = "pri show span";
15233 e->usage =
15234 "Usage: pri show span <span>\n"
15235 " Displays PRI Information on a given PRI span\n";
15236 return NULL;
15237 case CLI_GENERATE:
15238 return complete_span_4(a->line, a->word, a->pos, a->n);
15239 }
15240
15241 if (a->argc < 4)
15242 return CLI_SHOWUSAGE;
15243 span = atoi(a->argv[3]);
15244 if ((span < 1) || (span > NUM_SPANS)) {
15245 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
15246 return CLI_SUCCESS;
15247 }
15248 if (!pris[span-1].pri.pri) {
15249 ast_cli(a->fd, "No PRI running on span %d\n", span);
15250 return CLI_SUCCESS;
15251 }
15252
15253 sig_pri_cli_show_span(a->fd, pris[span-1].dchannels, &pris[span-1].pri);
15254
15255 return CLI_SUCCESS;
15256}
15257#endif /* defined(HAVE_PRI) */
15258
15259#if defined(HAVE_PRI)
15260static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15261{
15262 int x;
15263 int span;
15264 int count=0;
15265 int debug;
15266
15267 switch (cmd) {
15268 case CLI_INIT:
15269 e->command = "pri show debug";
15270 e->usage =
15271 "Usage: pri show debug\n"
15272 " Show the debug state of pri spans\n";
15273 return NULL;
15274 case CLI_GENERATE:
15275 return NULL;
15276 }
15277
15278 for (span = 0; span < NUM_SPANS; span++) {
15279 if (pris[span].pri.pri) {
15280 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
15281 if (pris[span].pri.dchans[x]) {
15282 debug = pri_get_debug(pris[span].pri.dchans[x]);
15283 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" );
15284 count++;
15285 }
15286 }
15287 }
15288
15289 }
15290 ast_mutex_lock(&pridebugfdlock);
15291 if (pridebugfd >= 0)
15292 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
15293 ast_mutex_unlock(&pridebugfdlock);
15294
15295 if (!count)
15296 ast_cli(a->fd, "No PRI running\n");
15297 return CLI_SUCCESS;
15298}
15299#endif /* defined(HAVE_PRI) */
15300
15301#if defined(HAVE_PRI)
15302static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15303{
15304 switch (cmd) {
15305 case CLI_INIT:
15306 e->command = "pri show version";
15307 e->usage =
15308 "Usage: pri show version\n"
15309 "Show libpri version information\n";
15310 return NULL;
15311 case CLI_GENERATE:
15312 return NULL;
15313 }
15314
15315 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
15316
15317 return CLI_SUCCESS;
15318}
15319#endif /* defined(HAVE_PRI) */
15320
15321#if defined(HAVE_PRI)
15322static struct ast_cli_entry dahdi_pri_cli[] = {
15323 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
15324#if defined(HAVE_PRI_SERVICE_MESSAGES)
15325 AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
15326 AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
15327#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15328 AST_CLI_DEFINE(handle_pri_show_channels, "Displays PRI channel information"),
15329 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI span information"),
15330 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI span information"),
15331 AST_CLI_DEFINE(handle_pri_destroy_span, "Destroy a PRI span"),
15332 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
15333 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
15334 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
15335};
15336#endif /* defined(HAVE_PRI) */
15337
15338#ifdef HAVE_OPENR2
15339
15340static char *handle_mfcr2_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15341{
15342 switch (cmd) {
15343 case CLI_INIT:
15344 e->command = "mfcr2 show version";
15345 e->usage =
15346 "Usage: mfcr2 show version\n"
15347 " Shows the version of the OpenR2 library being used.\n";
15348 return NULL;
15349 case CLI_GENERATE:
15350 return NULL;
15351 }
15352 ast_cli(a->fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15353 return CLI_SUCCESS;
15354}
15355
15356static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15357{
15358#define FORMAT "%4s %40s\n"
15359 int i = 0;
15360 int numvariants = 0;
15361 const openr2_variant_entry_t *variants;
15362 switch (cmd) {
15363 case CLI_INIT:
15364 e->command = "mfcr2 show variants";
15365 e->usage =
15366 "Usage: mfcr2 show variants\n"
15367 " Shows the list of MFC/R2 variants supported.\n";
15368 return NULL;
15369 case CLI_GENERATE:
15370 return NULL;
15371 }
15372 if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
15373 ast_cli(a->fd, "Failed to get list of variants.\n");
15374 return CLI_FAILURE;
15375 }
15376 ast_cli(a->fd, FORMAT, "Variant Code", "Country");
15377 for (i = 0; i < numvariants; i++) {
15378 ast_cli(a->fd, FORMAT, variants[i].name, variants[i].country);
15379 }
15380 return CLI_SUCCESS;
15381#undef FORMAT
15382}
15383
15384static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15385{
15386#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15387 int filtertype = 0;
15388 int targetnum = 0;
15389 char channo[5];
15390 char linkno[5];
15391 char anino[5];
15392 char dnisno[5];
15393 struct dahdi_pvt *p;
15394 openr2_context_t *r2context;
15395 openr2_variant_t r2variant;
15396 switch (cmd) {
15397 case CLI_INIT:
15398 e->command = "mfcr2 show channels [group|context]";
15399 e->usage =
15400 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15401 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15402 return NULL;
15403 case CLI_GENERATE:
15404 return NULL;
15405 }
15406 if (!((a->argc == 3) || (a->argc == 5))) {
15407 return CLI_SHOWUSAGE;
15408 }
15409 if (a->argc == 5) {
15410 if (!strcasecmp(a->argv[3], "group")) {
15411 targetnum = atoi(a->argv[4]);
15412 if ((targetnum < 0) || (targetnum > 63))
15413 return CLI_SHOWUSAGE;
15414 targetnum = 1 << targetnum;
15415 filtertype = 1;
15416 } else if (!strcasecmp(a->argv[3], "context")) {
15417 filtertype = 2;
15418 } else {
15419 return CLI_SHOWUSAGE;
15420 }
15421 }
15422 ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15424 for (p = iflist; p; p = p->next) {
15425 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15426 continue;
15427 }
15428 if (filtertype) {
15429 switch(filtertype) {
15430 case 1: /* mfcr2 show channels group <group> */
15431 if (p->group != targetnum) {
15432 continue;
15433 }
15434 break;
15435 case 2: /* mfcr2 show channels context <context> */
15436 if (strcasecmp(p->context, a->argv[4])) {
15437 continue;
15438 }
15439 break;
15440 default:
15441 ;
15442 }
15443 }
15444 r2context = openr2_chan_get_context(p->r2chan);
15445 r2variant = openr2_context_get_variant(r2context);
15446 snprintf(channo, sizeof(channo), "%d", p->channel);
15447 snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
15448 snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
15449 snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
15450 ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
15451 anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
15452 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
15453 openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
15454 }
15456 return CLI_SUCCESS;
15457#undef FORMAT
15458}
15459
15460static char *handle_mfcr2_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15461{
15462 struct dahdi_pvt *p = NULL;
15463 int channo = 0;
15464 char *toklevel = NULL;
15465 char *saveptr = NULL;
15466 char *logval = NULL;
15467 openr2_log_level_t loglevel = OR2_LOG_NOTHING;
15468 openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
15469 switch (cmd) {
15470 case CLI_INIT:
15471 e->command = "mfcr2 set debug";
15472 e->usage =
15473 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15474 " Set a new logging level for the specified channel.\n"
15475 " If no channel is specified the logging level will be applied to all channels.\n";
15476 return NULL;
15477 case CLI_GENERATE:
15478 return NULL;
15479 }
15480 if (a->argc < 4) {
15481 return CLI_SHOWUSAGE;
15482 }
15483 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15484 logval = ast_strdupa(a->argv[3]);
15485 toklevel = strtok_r(logval, ",", &saveptr);
15486 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15487 ast_cli(a->fd, "Invalid MFC/R2 logging level '%s'.\n", a->argv[3]);
15488 return CLI_FAILURE;
15489 } else if (OR2_LOG_NOTHING == tmplevel) {
15490 loglevel = tmplevel;
15491 } else {
15492 loglevel |= tmplevel;
15493 while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
15494 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15495 ast_cli(a->fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
15496 continue;
15497 }
15498 loglevel |= tmplevel;
15499 }
15500 }
15502 for (p = iflist; p; p = p->next) {
15503 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15504 continue;
15505 }
15506 if ((channo != -1) && (p->channel != channo )) {
15507 continue;
15508 }
15509 openr2_chan_set_log_level(p->r2chan, loglevel);
15510 if (channo != -1) {
15511 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for channel %d.\n", a->argv[3], p->channel);
15512 break;
15513 }
15514 }
15515 if ((channo != -1) && !p) {
15516 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15517 }
15518 if (channo == -1) {
15519 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for all channels.\n", a->argv[3]);
15520 }
15522 return CLI_SUCCESS;
15523}
15524
15525static char *handle_mfcr2_call_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15526{
15527 struct dahdi_pvt *p = NULL;
15528 int channo = 0;
15529 switch (cmd) {
15530 case CLI_INIT:
15531 e->command = "mfcr2 call files [on|off]";
15532 e->usage =
15533 "Usage: mfcr2 call files [on|off] <channel>\n"
15534 " Enable call files creation on the specified channel.\n"
15535 " If no channel is specified call files creation policy will be applied to all channels.\n";
15536 return NULL;
15537 case CLI_GENERATE:
15538 return NULL;
15539 }
15540 if (a->argc < 4) {
15541 return CLI_SHOWUSAGE;
15542 }
15543 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15545 for (p = iflist; p; p = p->next) {
15546 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15547 continue;
15548 }
15549 if ((channo != -1) && (p->channel != channo )) {
15550 continue;
15551 }
15552 if (ast_true(a->argv[3])) {
15553 openr2_chan_enable_call_files(p->r2chan);
15554 } else {
15555 openr2_chan_disable_call_files(p->r2chan);
15556 }
15557 if (channo != -1) {
15558 if (ast_true(a->argv[3])) {
15559 ast_cli(a->fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
15560 } else {
15561 ast_cli(a->fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
15562 }
15563 break;
15564 }
15565 }
15566 if ((channo != -1) && !p) {
15567 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15568 }
15569 if (channo == -1) {
15570 if (ast_true(a->argv[3])) {
15571 ast_cli(a->fd, "MFC/R2 Call files enabled for all channels.\n");
15572 } else {
15573 ast_cli(a->fd, "MFC/R2 Call files disabled for all channels.\n");
15574 }
15575 }
15577 return CLI_SUCCESS;
15578}
15579
15580static char *handle_mfcr2_set_idle(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15581{
15582 struct dahdi_pvt *p = NULL;
15583 int channo = 0;
15584 switch (cmd) {
15585 case CLI_INIT:
15586 e->command = "mfcr2 set idle";
15587 e->usage =
15588 "Usage: mfcr2 set idle <channel>\n"
15589 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15590 " Force the given channel into IDLE state.\n"
15591 " If no channel is specified, all channels will be set to IDLE.\n";
15592 return NULL;
15593 case CLI_GENERATE:
15594 return NULL;
15595 }
15596 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15598 for (p = iflist; p; p = p->next) {
15599 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15600 continue;
15601 }
15602 if ((channo != -1) && (p->channel != channo )) {
15603 continue;
15604 }
15605 openr2_chan_set_idle(p->r2chan);
15606 ast_mutex_lock(&p->lock);
15607 p->locallyblocked = 0;
15608 p->mfcr2call = 0;
15610 if (channo != -1) {
15611 break;
15612 }
15613 }
15614 if ((channo != -1) && !p) {
15615 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15616 }
15618 return CLI_SUCCESS;
15619}
15620
15621static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15622{
15623 struct dahdi_pvt *p = NULL;
15624 int channo = 0;
15625 switch (cmd) {
15626 case CLI_INIT:
15627 e->command = "mfcr2 set blocked";
15628 e->usage =
15629 "Usage: mfcr2 set blocked <channel>\n"
15630 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15631 " Force the given channel into BLOCKED state.\n"
15632 " If no channel is specified, all channels will be set to BLOCKED.\n";
15633 return NULL;
15634 case CLI_GENERATE:
15635 return NULL;
15636 }
15637 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15639 for (p = iflist; p; p = p->next) {
15640 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15641 continue;
15642 }
15643 if ((channo != -1) && (p->channel != channo )) {
15644 continue;
15645 }
15646 openr2_chan_set_blocked(p->r2chan);
15647 ast_mutex_lock(&p->lock);
15648 p->locallyblocked = 1;
15650 if (channo != -1) {
15651 break;
15652 }
15653 }
15654 if ((channo != -1) && !p) {
15655 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15656 }
15658 return CLI_SUCCESS;
15659}
15660
15661static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
15662{
15663#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15664 AST_LIST_LOCK(list_head);
15665 if (! AST_LIST_EMPTY(list_head)) {
15666 int x = 0;
15667 char index[5];
15668 char live_chans_str[5];
15669 char channel_list[R2_LINK_CAPACITY * 4];
15670 struct r2link_entry *cur;
15671 ast_cli(a->fd, "%s\n", title);
15672 ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15673 AST_LIST_TRAVERSE(list_head, cur, list) {
15674 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15675 const char *thread_status = NULL;
15676 int i;
15677 int len;
15678 int inside_range;
15679 int channo;
15680 int prev_channo;
15681 x++;
15682 if (mfcr2->r2master == 0L) {
15683 thread_status = "zero";
15684 } else if (mfcr2->r2master == AST_PTHREADT_NULL) {
15685 thread_status = "none";
15686 } else {
15687 thread_status = "created";
15688 }
15689 snprintf(index, sizeof(index), "%d", mfcr2->index);
15690 snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
15691 channo = 0;
15692 prev_channo = 0;
15693 inside_range = 0;
15694 len = 0;
15695 /* Prepare nice string in channel_list[] */
15696 for (i = 0; i < mfcr2->numchans && len < sizeof(channel_list) - 1; i++) {
15697 struct dahdi_pvt *p = mfcr2->pvts[i];
15698 if (!p) {
15699 continue;
15700 }
15701 channo = p->channel;
15702 /* Don't show a range until we know the last channel number */
15703 if (prev_channo && prev_channo == channo - 1) {
15704 prev_channo = channo;
15705 inside_range = 1;
15706 continue;
15707 }
15708 if (inside_range) {
15709 /* Close range */
15710 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
15711 inside_range = 0;
15712 } else if (prev_channo) {
15713 /* Non-sequential channel numbers */
15714 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15715 } else {
15716 /* First channel number */
15717 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
15718 }
15719 prev_channo = channo;
15720 }
15721 /* Handle leftover channels */
15722 if (inside_range) {
15723 /* Close range */
15724 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
15725 inside_range = 0;
15726 } else if (prev_channo) {
15727 /* Non-sequential channel numbers */
15728 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15729 }
15730 // channel_list[len] = '\0';
15731 ast_cli(a->fd, FORMAT,
15732 index,
15733 thread_status,
15734 (mfcr2->nodev) ? "MISSING" : "OK",
15735 live_chans_str,
15736 channel_list);
15737 }
15738 }
15739 AST_LIST_UNLOCK(list_head);
15740#undef FORMAT
15741}
15742
15743static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15744{
15745 switch (cmd) {
15746 case CLI_INIT:
15747 e->command = "mfcr2 show links";
15748 e->usage =
15749 "Usage: mfcr2 show links\n"
15750 " Shows the DAHDI MFC/R2 links.\n";
15751 return NULL;
15752 case CLI_GENERATE:
15753 return NULL;
15754 }
15755 if (a->argc != 3) {
15756 return CLI_SHOWUSAGE;
15757 }
15758 mfcr2_show_links_of(a, &r2links, "Live links\n");
15759 mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
15760 return CLI_SUCCESS;
15761}
15762
15763static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15764{
15765 int res;
15766 int wanted_link_index;
15767 int found_link = 0;
15768 struct r2link_entry *cur = NULL;
15769
15770 switch (cmd) {
15771 case CLI_INIT:
15772 e->command = "mfcr2 destroy link";
15773 e->usage =
15774 "Usage: mfcr2 destroy link <index-number>\n"
15775 " Destroys D-channel of link and its B-channels.\n"
15776 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15777 return NULL;
15778 case CLI_GENERATE:
15779 return NULL;
15780 }
15781 if (a->argc < 4) {
15782 return CLI_SHOWUSAGE;
15783 }
15784 res = sscanf(a->argv[3], "%30d", &wanted_link_index);
15785 if ((res != 1) || wanted_link_index < 1) {
15786 ast_cli(a->fd,
15787 "Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
15788 return CLI_SUCCESS;
15789 }
15790 AST_LIST_LOCK(&r2links);
15791 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
15792 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15793 if (wanted_link_index == mfcr2->index) {
15794 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
15795 r2links_count--;
15796 break;
15797 }
15798 }
15800 AST_LIST_UNLOCK(&r2links);
15801 if (! found_link) {
15802 ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
15803 return CLI_FAILURE;
15804 }
15805 return CLI_SUCCESS;
15806}
15807
15808static struct ast_cli_entry dahdi_mfcr2_cli[] = {
15809 AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
15810 AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
15811 AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
15812 AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
15813 AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
15814 AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
15815 AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
15816 AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
15817 AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
15818};
15819
15820#endif /* HAVE_OPENR2 */
15821
15822static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15823{
15824 int start;
15825 int end;
15826 switch (cmd) {
15827 case CLI_INIT:
15828 e->command = "dahdi destroy channels";
15829 e->usage =
15830 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15831 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15832 return NULL;
15833 case CLI_GENERATE:
15834 return NULL;
15835 }
15836 if ((a->argc < 4) || a->argc > 5) {
15837 return CLI_SHOWUSAGE;
15838 }
15839 start = atoi(a->argv[3]);
15840 if (start < 1) {
15841 ast_cli(a->fd, "Invalid starting channel number %s.\n",
15842 a->argv[4]);
15843 return CLI_FAILURE;
15844 }
15845 if (a->argc == 5) {
15846 end = atoi(a->argv[4]);
15847 if (end < 1) {
15848 ast_cli(a->fd, "Invalid ending channel number %s.\n",
15849 a->argv[4]);
15850 return CLI_FAILURE;
15851 }
15852 } else {
15853 end = start;
15854 }
15855
15856 if (end < start) {
15857 ast_cli(a->fd,
15858 "range end (%d) is smaller than range start (%d)\n",
15859 end, start);
15860 return CLI_FAILURE;
15861 }
15863 return CLI_SUCCESS;
15864}
15865
15866static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15867{
15868 int start;
15869 int end;
15870 int ret;
15871
15872 switch (cmd) {
15873 case CLI_INIT:
15874 e->command = "dahdi create channels";
15875 e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15876 " dahdi create channels new - add channels not yet created\n"
15877 "For ISDN and SS7 the range should include complete spans.\n";
15878 return NULL;
15879 case CLI_GENERATE:
15880 return NULL;
15881 }
15882 if ((a->argc < 4) || a->argc > 5) {
15883 return CLI_SHOWUSAGE;
15884 }
15885 if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
15886 ret = dahdi_create_channel_range(0, 0);
15887 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15888 }
15889 start = atoi(a->argv[3]);
15890 if (start <= 0) {
15891 ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
15892 a->argv[3]);
15893 return CLI_FAILURE;
15894 }
15895 if (a->argc == 5) {
15896 end = atoi(a->argv[4]);
15897 if (end <= 0) {
15898 ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
15899 a->argv[4]);
15900 return CLI_FAILURE;
15901 }
15902 } else {
15903 end = start;
15904 }
15905 if (end < start) {
15906 ast_cli(a->fd,
15907 "range end (%d) is smaller than range start (%d)\n",
15908 end, start);
15909 return CLI_FAILURE;
15910 }
15911 ret = dahdi_create_channel_range(start, end);
15912 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15913}
15914
15915static void dahdi_softhangup_all(void)
15916{
15917 struct dahdi_pvt *p;
15918retry:
15920 for (p = iflist; p; p = p->next) {
15921 ast_mutex_lock(&p->lock);
15922 if (p->owner && !p->restartpending) {
15923 if (ast_channel_trylock(p->owner)) {
15924 if (DEBUG_ATLEAST(3))
15925 ast_verbose("Avoiding deadlock\n");
15926 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15929 goto retry;
15930 }
15931 if (DEBUG_ATLEAST(3))
15932 ast_verbose("Softhanging up on %s\n", ast_channel_name(p->owner));
15934 p->restartpending = 1;
15937 }
15939 }
15941}
15942
15943static int dahdi_restart(void)
15944{
15945#if defined(HAVE_PRI) || defined(HAVE_SS7)
15946 int i, j;
15947#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15948 int cancel_code;
15949 struct dahdi_pvt *p;
15950
15952 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15954 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15955#ifdef HAVE_OPENR2
15956 dahdi_r2_destroy_links();
15957#endif
15958
15959#if defined(HAVE_PRI)
15960 for (i = 0; i < NUM_SPANS; i++) {
15961 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
15962 cancel_code = pthread_cancel(pris[i].pri.master);
15963 pthread_kill(pris[i].pri.master, SIGURG);
15964 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);
15965 pthread_join(pris[i].pri.master, NULL);
15966 ast_debug(4, "Joined thread of span %d\n", i);
15967 }
15968 }
15969#endif
15970
15971#if defined(HAVE_SS7)
15972 for (i = 0; i < NUM_SPANS; i++) {
15973 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
15974 cancel_code = pthread_cancel(linksets[i].ss7.master);
15975 pthread_kill(linksets[i].ss7.master, SIGURG);
15976 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);
15977 pthread_join(linksets[i].ss7.master, NULL);
15978 ast_debug(4, "Joined thread of span %d\n", i);
15979 }
15980 }
15981#endif /* defined(HAVE_SS7) */
15982
15985 cancel_code = pthread_cancel(monitor_thread);
15986 pthread_kill(monitor_thread, SIGURG);
15987 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
15988 pthread_join(monitor_thread, NULL);
15989 ast_debug(4, "Joined monitor thread\n");
15990 }
15991 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15992
15994 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15995 int x = DAHDI_FLASH;
15996 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
15997
15999 for (p = iflist; p; p = p->next) {
16000 if (p->owner) {
16001 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
16002 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
16003 }
16004 }
16007 }
16008
16009 /* ensure any created channels before monitor threads were stopped are hungup */
16011 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
16013 memset(round_robin, 0, sizeof(round_robin));
16014 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
16015
16017
16018#ifdef HAVE_PRI
16019 for (i = 0; i < NUM_SPANS; i++) {
16020 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++)
16021 dahdi_close_pri_fd(&(pris[i]), j);
16022 }
16023
16024 memset(pris, 0, sizeof(pris));
16025 for (i = 0; i < NUM_SPANS; i++) {
16026 sig_pri_init_pri(&pris[i].pri);
16027 }
16028 pri_set_error(dahdi_pri_error);
16029 pri_set_message(dahdi_pri_message);
16030#endif
16031#if defined(HAVE_SS7)
16032 for (i = 0; i < NUM_SPANS; i++) {
16033 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++)
16034 dahdi_close_ss7_fd(&(linksets[i]), j);
16035 }
16036
16037 memset(linksets, 0, sizeof(linksets));
16038 for (i = 0; i < NUM_SPANS; i++) {
16039 sig_ss7_init_linkset(&linksets[i].ss7);
16040 }
16041 ss7_set_error(dahdi_ss7_error);
16042 ss7_set_message(dahdi_ss7_message);
16043 ss7_set_hangup(sig_ss7_cb_hangup);
16044 ss7_set_notinservice(sig_ss7_cb_notinservice);
16045 ss7_set_call_null(sig_ss7_cb_call_null);
16046#endif /* defined(HAVE_SS7) */
16047
16048 if (setup_dahdi(2) != 0) {
16049 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
16051 return 1;
16052 }
16055 return 0;
16056}
16057
16058static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16059{
16060 switch (cmd) {
16061 case CLI_INIT:
16062 e->command = "dahdi restart";
16063 e->usage =
16064 "Usage: dahdi restart\n"
16065 " Restarts the DAHDI channels: destroys them all and then\n"
16066 " re-reads them from chan_dahdi.conf.\n"
16067 " Note that this will STOP any running CALL on DAHDI channels.\n"
16068 "";
16069 return NULL;
16070 case CLI_GENERATE:
16071 return NULL;
16072 }
16073 if (a->argc != 2)
16074 return CLI_SHOWUSAGE;
16075
16076 if (dahdi_restart() != 0)
16077 return CLI_FAILURE;
16078 return CLI_SUCCESS;
16079}
16080
16081static int action_dahdirestart(struct mansession *s, const struct message *m)
16082{
16083 if (dahdi_restart() != 0) {
16084 astman_send_error(s, m, "Failed rereading DAHDI configuration");
16085 return 1;
16086 }
16087 astman_send_ack(s, m, "DAHDIRestart: Success");
16088 return 0;
16089}
16090
16091static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16092{
16093#define FORMAT "%7s %4d %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16094#define FORMAT2 "%7s %4s %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16095 ast_group_t targetnum = 0;
16096 int filtertype = 0;
16097 struct dahdi_pvt *tmp = NULL;
16098 char tmps[20];
16099 char blockstr[20];
16100
16101 switch (cmd) {
16102 case CLI_INIT:
16103 e->command = "dahdi show channels [group|context]";
16104 e->usage =
16105 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
16106 " Shows a list of available channels with optional filtering\n"
16107 " <group> must be a number between 0 and 63\n";
16108 return NULL;
16109 case CLI_GENERATE:
16110 return NULL;
16111 }
16112
16113 /* syntax: dahdi show channels [ group <group> | context <context> ] */
16114
16115 if (!((a->argc == 3) || (a->argc == 5))) {
16116 return CLI_SHOWUSAGE;
16117 }
16118
16119 if (a->argc == 5) {
16120 if (!strcasecmp(a->argv[3], "group")) {
16121 targetnum = atoi(a->argv[4]);
16122 if (63 < targetnum) {
16123 return CLI_SHOWUSAGE;
16124 }
16125 targetnum = ((ast_group_t) 1) << targetnum;
16126 filtertype = 1;
16127 } else if (!strcasecmp(a->argv[3], "context")) {
16128 filtertype = 2;
16129 }
16130 }
16131
16132 ast_cli(a->fd, FORMAT2, "Chan", "Span", "Signalling", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Alarms", "Description");
16134 for (tmp = iflist; tmp; tmp = tmp->next) {
16135 int alm = 0;
16136 if (filtertype) {
16137 switch(filtertype) {
16138 case 1: /* dahdi show channels group <group> */
16139 if (!(tmp->group & targetnum)) {
16140 continue;
16141 }
16142 break;
16143 case 2: /* dahdi show channels context <context> */
16144 if (strcasecmp(tmp->context, a->argv[4])) {
16145 continue;
16146 }
16147 break;
16148 default:
16149 break;
16150 }
16151 }
16152 if (tmp->channel > 0) {
16153 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
16154 alm = get_alarms(tmp);
16155 } else {
16156 ast_copy_string(tmps, "pseudo", sizeof(tmps));
16157 }
16158
16159 blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
16160 blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
16161 blockstr[2] = '\0';
16162
16163 ast_cli(a->fd, FORMAT, tmps, tmp->span, sig2str(tmp->sig), tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No",
16164 alarm2str(alm), tmp->description);
16165 }
16167 return CLI_SUCCESS;
16168#undef FORMAT
16169#undef FORMAT2
16170}
16171
16172static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16173{
16174 int channel;
16175 struct dahdi_pvt *tmp = NULL;
16176 struct dahdi_confinfo ci;
16177 struct dahdi_params ps;
16178 int x;
16179 char hwrxgain[15];
16180 char hwtxgain[15];
16181
16182 switch (cmd) {
16183 case CLI_INIT:
16184 e->command = "dahdi show channel";
16185 e->usage =
16186 "Usage: dahdi show channel <chan num>\n"
16187 " Detailed information about a given channel\n";
16188 return NULL;
16189 case CLI_GENERATE:
16190 return NULL;
16191 }
16192
16193 if (a->argc != 4)
16194 return CLI_SHOWUSAGE;
16195
16196 channel = atoi(a->argv[3]);
16197
16199 for (tmp = iflist; tmp; tmp = tmp->next) {
16200 if (tmp->channel == channel) {
16201 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
16202 ast_cli(a->fd, "Description: %s\n", tmp->description);
16203 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
16204 ast_cli(a->fd, "Span: %d\n", tmp->span);
16205 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
16206 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
16207 ast_cli(a->fd, "Context: %s\n", tmp->context);
16208 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
16209 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
16210#if defined(HAVE_PRI)
16211#if defined(HAVE_PRI_SUBADDR)
16212 ast_cli(a->fd, "Caller ID subaddress: %s\n", tmp->cid_subaddr);
16213#endif /* defined(HAVE_PRI_SUBADDR) */
16214#endif /* defined(HAVE_PRI) */
16215 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
16216 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
16217 if (tmp->vars) {
16218 struct ast_variable *v;
16219 ast_cli(a->fd, "Variables:\n");
16220 for (v = tmp->vars ; v ; v = v->next)
16221 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
16222 }
16223 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
16224 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
16225 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
16226 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
16227 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? ast_channel_name(tmp->owner) : "<None>");
16228 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)" : "");
16229 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)" : "");
16230 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)" : "");
16231 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
16232 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
16233 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
16234 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
16235 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
16236 if (tmp->busydetect) {
16237#if defined(BUSYDETECT_TONEONLY)
16238 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16239#elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16240 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16241#endif
16242#ifdef BUSYDETECT_DEBUG
16243 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
16244#endif
16245 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
16246 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);
16247 }
16248 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
16249 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
16250 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
16251 ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
16252 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
16253 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
16254 if (tmp->hwrxgain_enabled) {
16255 snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
16256 } else {
16257 ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
16258 }
16259 if (tmp->hwtxgain_enabled) {
16260 snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
16261 } else {
16262 ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
16263 }
16264 ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
16265 ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
16266 ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
16267 ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
16268 ast_cli(a->fd, "Echo Cancellation:\n");
16269
16270 if (tmp->echocancel.head.tap_length) {
16271 ast_cli(a->fd, "\t%u taps\n", tmp->echocancel.head.tap_length);
16272 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
16273 ast_cli(a->fd, "\t\t%s: %dd\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
16274 }
16275 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
16276 } else {
16277 ast_cli(a->fd, "\tnone\n");
16278 }
16279 ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone);
16280 if (tmp->master)
16281 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
16282 for (x = 0; x < MAX_SLAVES; x++) {
16283 if (tmp->slaves[x])
16284 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
16285 }
16286#ifdef HAVE_OPENR2
16287 if (tmp->mfcr2) {
16288 char calldir[OR2_MAX_PATH];
16289 openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
16290 openr2_variant_t r2variant = openr2_context_get_variant(r2context);
16291 ast_cli(a->fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
16292 ast_cli(a->fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
16293 ast_cli(a->fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
16294 ast_cli(a->fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
16295 ast_cli(a->fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
16296 ast_cli(a->fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
16297 ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
16298 ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
16299#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16300 ast_cli(a->fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
16301 ast_cli(a->fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
16302#endif
16303 ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
16304#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16305 ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
16306#endif
16307 ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
16308 ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
16309 ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
16310 ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
16311 ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
16312 ast_cli(a->fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
16313 ast_cli(a->fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
16314 ast_cli(a->fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
16315 ast_cli(a->fd, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
16316 ast_cli(a->fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
16317 ast_cli(a->fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
16318 ast_cli(a->fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
16319 }
16320#endif
16321#if defined(HAVE_SS7)
16322 if (tmp->ss7) {
16323 struct sig_ss7_chan *chan = tmp->sig_pvt;
16324
16325 ast_cli(a->fd, "CIC: %d\n", chan->cic);
16326 }
16327#endif /* defined(HAVE_SS7) */
16328#ifdef HAVE_PRI
16329 if (tmp->pri) {
16330 struct sig_pri_chan *chan = tmp->sig_pvt;
16331
16332 ast_cli(a->fd, "PRI Flags: ");
16333 if (chan->resetting != SIG_PRI_RESET_IDLE) {
16334 ast_cli(a->fd, "Resetting=%u ", chan->resetting);
16335 }
16336 if (chan->call)
16337 ast_cli(a->fd, "Call ");
16338 if (chan->allocated) {
16339 ast_cli(a->fd, "Allocated ");
16340 }
16341 ast_cli(a->fd, "\n");
16342 if (tmp->logicalspan)
16343 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
16344 else
16345 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
16346 }
16347#endif
16348 memset(&ci, 0, sizeof(ci));
16349 ps.channo = tmp->channel;
16350 if (tmp->subs[SUB_REAL].dfd > -1) {
16351 memset(&ci, 0, sizeof(ci));
16352 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
16353 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, (unsigned)ci.confmode);
16354 }
16355 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
16356 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
16357 }
16358 memset(&ps, 0, sizeof(ps));
16359 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
16360 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
16361 } else {
16362 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
16363 }
16364 }
16366 return CLI_SUCCESS;
16367 }
16368 }
16370
16371 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16372 return CLI_FAILURE;
16373}
16374
16375static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16376{
16377 int i, j;
16378 switch (cmd) {
16379 case CLI_INIT:
16380 e->command = "dahdi show cadences";
16381 e->usage =
16382 "Usage: dahdi show cadences\n"
16383 " Shows all cadences currently defined\n";
16384 return NULL;
16385 case CLI_GENERATE:
16386 return NULL;
16387 }
16388 for (i = 0; i < num_cadence; i++) {
16389 char output[1024];
16390 char tmp[16], tmp2[64];
16391 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
16392 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
16393
16394 for (j = 0; j < 16; j++) {
16395 if (cadences[i].ringcadence[j] == 0)
16396 break;
16397 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
16398 if (cidrings[i] * 2 - 1 == j)
16399 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
16400 else
16401 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
16402 if (j != 0)
16403 strncat(output, ",", sizeof(output) - strlen(output) - 1);
16404 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
16405 }
16406 ast_cli(a->fd,"%s\n",output);
16407 }
16408 return CLI_SUCCESS;
16409}
16410
16411static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
16412{
16413 alarmstr[0] = '\0';
16414 if (spaninfo->alarms > 0) {
16415 if (spaninfo->alarms & DAHDI_ALARM_BLUE) {
16416 strcat(alarmstr, "BLU/");
16417 }
16418 if (spaninfo->alarms & DAHDI_ALARM_YELLOW) {
16419 strcat(alarmstr, "YEL/");
16420 }
16421 if (spaninfo->alarms & DAHDI_ALARM_RED) {
16422 strcat(alarmstr, "RED/");
16423 }
16424 if (spaninfo->alarms & DAHDI_ALARM_LOOPBACK) {
16425 strcat(alarmstr, "LB/");
16426 }
16427 if (spaninfo->alarms & DAHDI_ALARM_RECOVER) {
16428 strcat(alarmstr, "REC/");
16429 }
16430 if (spaninfo->alarms & DAHDI_ALARM_NOTOPEN) {
16431 strcat(alarmstr, "NOP/");
16432 }
16433 if (!strlen(alarmstr)) {
16434 strcat(alarmstr, "UUU/");
16435 }
16436 if (strlen(alarmstr)) {
16437 /* Strip trailing / */
16438 alarmstr[strlen(alarmstr) - 1] = '\0';
16439 }
16440 } else {
16441 if (spaninfo->numchans) {
16442 strcpy(alarmstr, "OK");
16443 } else {
16444 strcpy(alarmstr, "UNCONFIGURED");
16445 }
16446 }
16447}
16448
16449/* Based on irqmiss.c */
16450static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16451{
16452 #define FORMAT "%4d %-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16453 #define FORMAT2 "%4s %-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16454 int span;
16455 int res;
16456 char alarmstr[50];
16457
16458 int ctl;
16459 struct dahdi_spaninfo s;
16460
16461 switch (cmd) {
16462 case CLI_INIT:
16463 e->command = "dahdi show status";
16464 e->usage =
16465 "Usage: dahdi show status\n"
16466 " Shows a list of DAHDI cards with status\n";
16467 return NULL;
16468 case CLI_GENERATE:
16469 return NULL;
16470 }
16471 ctl = open("/dev/dahdi/ctl", O_RDWR);
16472 if (ctl < 0) {
16473 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
16474 return CLI_FAILURE;
16475 }
16476 ast_cli(a->fd, FORMAT2, "Span", "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16477
16478 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
16479 s.spanno = span;
16480 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
16481 if (res) {
16482 continue;
16483 }
16484 build_alarm_info(alarmstr, &s);
16485 ast_cli(a->fd, FORMAT, span, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count,
16486 s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
16487 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
16488 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
16489 "CAS",
16490 s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
16491 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
16492 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
16493 "Unknown",
16494 s.lineconfig & DAHDI_CONFIG_CRC4 ?
16495 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
16496 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
16497 lbostr[s.lbo]
16498 );
16499 }
16500 close(ctl);
16501
16502 return CLI_SUCCESS;
16503#undef FORMAT
16504#undef FORMAT2
16505}
16506
16507static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16508{
16509 int pseudo_fd = -1;
16510 struct dahdi_versioninfo vi;
16511
16512 switch (cmd) {
16513 case CLI_INIT:
16514 e->command = "dahdi show version";
16515 e->usage =
16516 "Usage: dahdi show version\n"
16517 " Shows the DAHDI version in use\n";
16518 return NULL;
16519 case CLI_GENERATE:
16520 return NULL;
16521 }
16522 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
16523 ast_cli(a->fd, "Failed to open control file to get version.\n");
16524 return CLI_SUCCESS;
16525 }
16526
16527 strcpy(vi.version, "Unknown");
16528 strcpy(vi.echo_canceller, "Unknown");
16529
16530 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
16531 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
16532 else
16533 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
16534
16535 close(pseudo_fd);
16536
16537 return CLI_SUCCESS;
16538}
16539
16540static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16541{
16542 int channel;
16543 float gain;
16544 int tx;
16545 struct dahdi_pvt *tmp = NULL;
16546
16547 switch (cmd) {
16548 case CLI_INIT:
16549 e->command = "dahdi set hwgain {rx|tx}";
16550 e->usage =
16551 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16552 " Sets the hardware gain on a given channel and overrides the\n"
16553 " value provided at module loadtime. Changes take effect\n"
16554 " immediately whether the channel is in use or not.\n"
16555 "\n"
16556 " <rx|tx> which direction do you want to change (relative to our module)\n"
16557 " <chan num> is the channel number relative to the device\n"
16558 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16559 "\n"
16560 " Please note:\n"
16561 " * hwgain is only supportable by hardware with analog ports because\n"
16562 " hwgain works on the analog side of an analog-digital conversion.\n";
16563 return NULL;
16564 case CLI_GENERATE:
16565 return NULL;
16566 }
16567
16568 if (a->argc != 6)
16569 return CLI_SHOWUSAGE;
16570
16571 if (!strcasecmp("rx", a->argv[3]))
16572 tx = 0; /* rx */
16573 else if (!strcasecmp("tx", a->argv[3]))
16574 tx = 1; /* tx */
16575 else
16576 return CLI_SHOWUSAGE;
16577
16578 channel = atoi(a->argv[4]);
16579 gain = atof(a->argv[5]);
16580
16582
16583 for (tmp = iflist; tmp; tmp = tmp->next) {
16584
16585 if (tmp->channel != channel)
16586 continue;
16587
16588 if (tmp->subs[SUB_REAL].dfd == -1)
16589 break;
16590
16591 if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
16592 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
16594 return CLI_FAILURE;
16595 }
16596 ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
16597 tx ? "tx" : "rx", gain, channel);
16598
16599 if (tx) {
16600 tmp->hwtxgain_enabled = 1;
16601 tmp->hwtxgain = gain;
16602 } else {
16603 tmp->hwrxgain_enabled = 1;
16604 tmp->hwrxgain = gain;
16605 }
16606 break;
16607 }
16608
16610
16611 if (tmp)
16612 return CLI_SUCCESS;
16613
16614 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16615 return CLI_FAILURE;
16616
16617}
16618
16619static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16620{
16621 int channel;
16622 float gain;
16623 int tx;
16624 int res;
16625 struct dahdi_pvt *tmp = NULL;
16626
16627 switch (cmd) {
16628 case CLI_INIT:
16629 e->command = "dahdi set swgain {rx|tx}";
16630 e->usage =
16631 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16632 " Sets the software gain on a given channel and overrides the\n"
16633 " value provided at module loadtime. Changes take effect\n"
16634 " immediately whether the channel is in use or not.\n"
16635 "\n"
16636 " <rx|tx> which direction do you want to change (relative to our module)\n"
16637 " <chan num> is the channel number relative to the device\n"
16638 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16639 return NULL;
16640 case CLI_GENERATE:
16641 return NULL;
16642 }
16643
16644 if (a->argc != 6)
16645 return CLI_SHOWUSAGE;
16646
16647 if (!strcasecmp("rx", a->argv[3]))
16648 tx = 0; /* rx */
16649 else if (!strcasecmp("tx", a->argv[3]))
16650 tx = 1; /* tx */
16651 else
16652 return CLI_SHOWUSAGE;
16653
16654 channel = atoi(a->argv[4]);
16655 gain = atof(a->argv[5]);
16656
16658 for (tmp = iflist; tmp; tmp = tmp->next) {
16659
16660 if (tmp->channel != channel)
16661 continue;
16662
16663 if (tmp->subs[SUB_REAL].dfd == -1)
16664 break;
16665
16666 if (tx)
16667 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, gain, tmp->txdrc, tmp->law);
16668 else
16669 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, gain, tmp->rxdrc, tmp->law);
16670
16671 if (res) {
16672 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
16674 return CLI_FAILURE;
16675 }
16676
16677 ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
16678 tx ? "tx" : "rx", gain, channel);
16679
16680 if (tx) {
16681 tmp->txgain = gain;
16682 } else {
16683 tmp->rxgain = gain;
16684 }
16685 break;
16686 }
16688
16689 if (tmp)
16690 return CLI_SUCCESS;
16691
16692 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16693 return CLI_FAILURE;
16694
16695}
16696
16697static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16698{
16699 int channel;
16700 int on;
16701 struct dahdi_pvt *dahdi_chan = NULL;
16702
16703 switch (cmd) {
16704 case CLI_INIT:
16705 e->command = "dahdi set dnd";
16706 e->usage =
16707 "Usage: dahdi set dnd <chan#> <on|off>\n"
16708 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16709 " Changes take effect immediately.\n"
16710 " <chan num> is the channel number\n"
16711 " <on|off> Enable or disable DND mode?\n"
16712 ;
16713 return NULL;
16714 case CLI_GENERATE:
16715 return NULL;
16716 }
16717
16718 if (a->argc != 5)
16719 return CLI_SHOWUSAGE;
16720
16721 if ((channel = atoi(a->argv[3])) <= 0) {
16722 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16723 return CLI_SHOWUSAGE;
16724 }
16725
16726 if (ast_true(a->argv[4]))
16727 on = 1;
16728 else if (ast_false(a->argv[4]))
16729 on = 0;
16730 else {
16731 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
16732 return CLI_SHOWUSAGE;
16733 }
16734
16736 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16737 if (dahdi_chan->channel != channel)
16738 continue;
16739
16740 /* Found the channel. Actually set it */
16741 dahdi_dnd(dahdi_chan, on);
16742 break;
16743 }
16745
16746 if (!dahdi_chan) {
16747 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16748 return CLI_FAILURE;
16749 }
16750
16751 return CLI_SUCCESS;
16752}
16753
16754static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16755{
16756 int channel;
16757 int on;
16758 int override = 1;
16759 struct dahdi_pvt *dahdi_chan = NULL;
16760
16761 switch (cmd) {
16762 case CLI_INIT:
16763 e->command = "dahdi set mwi";
16764 e->usage =
16765 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16766 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16767 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16768 " When active, this setting will override the voicemail status to set MWI.\n"
16769 " Once cleared, the voicemail status will resume control of MWI.\n"
16770 " Changes are queued for when the channel is idle and persist until cleared.\n"
16771 " <chan num> is the channel number\n"
16772 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16773 ;
16774 return NULL;
16775 case CLI_GENERATE:
16776 return NULL;
16777 }
16778
16779 if (a->argc != 5)
16780 return CLI_SHOWUSAGE;
16781
16782 if ((channel = atoi(a->argv[3])) <= 0) {
16783 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16784 return CLI_SHOWUSAGE;
16785 }
16786
16787 if (ast_true(a->argv[4])) {
16788 on = 1;
16789 } else if (ast_false(a->argv[4])) {
16790 on = 0;
16791 } else if (!strcmp(a->argv[4], "reset")) {
16792 override = 0;
16793 } else {
16794 ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
16795 return CLI_SHOWUSAGE;
16796 }
16797
16799 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16800 if (dahdi_chan->channel != channel)
16801 continue;
16802
16803 /* Found the channel. Actually set it */
16804 if (override) {
16805 dahdi_chan->mwioverride_disposition = on;
16806 ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
16807 }
16808 dahdi_chan->mwioverride_active = override;
16809 /* The do_monitor thread will take care of actually sending the MWI
16810 * at an appropriate time for the channel. */
16811 break;
16812 }
16814
16815 if (!dahdi_chan) {
16816 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16817 return CLI_FAILURE;
16818 }
16819
16820 return CLI_SUCCESS;
16821}
16822
16823static struct ast_cli_entry dahdi_cli[] = {
16825 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
16826 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
16827 AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
16828 AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
16829 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
16830 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
16831 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
16832 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
16833 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
16834 AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16835 AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16836};
16837
16838#define TRANSFER 0
16839#define HANGUP 1
16840
16841static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
16842{
16843 if (p) {
16844 switch (mode) {
16845 case TRANSFER:
16846 p->fake_event = DAHDI_EVENT_WINKFLASH;
16847 break;
16848 case HANGUP:
16849 p->fake_event = DAHDI_EVENT_ONHOOK;
16850 break;
16851 default:
16852 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));
16853 }
16854 }
16855 return 0;
16856}
16857static struct dahdi_pvt *find_channel(int channel)
16858{
16859 struct dahdi_pvt *p;
16860
16862 for (p = iflist; p; p = p->next) {
16863 if (p->channel == channel) {
16864 break;
16865 }
16866 }
16868 return p;
16869}
16870
16871/*!
16872 * \internal
16873 * \brief Get private struct using given numeric channel string.
16874 *
16875 * \param channel Numeric channel number string get private struct.
16876 *
16877 * \retval pvt on success.
16878 * \retval NULL on error.
16879 */
16880static struct dahdi_pvt *find_channel_from_str(const char *channel)
16881{
16882 int chan_num;
16883
16884 if (sscanf(channel, "%30d", &chan_num) != 1) {
16885 /* Not numeric string. */
16886 return NULL;
16887 }
16888
16889 return find_channel(chan_num);
16890}
16891
16892static int action_dahdidndon(struct mansession *s, const struct message *m)
16893{
16894 struct dahdi_pvt *p;
16895 const char *channel = astman_get_header(m, "DAHDIChannel");
16896
16897 if (ast_strlen_zero(channel)) {
16898 astman_send_error(s, m, "No channel specified");
16899 return 0;
16900 }
16902 if (!p) {
16903 astman_send_error(s, m, "No such channel");
16904 return 0;
16905 }
16906 dahdi_dnd(p, 1);
16907 astman_send_ack(s, m, "DND Enabled");
16908 return 0;
16909}
16910
16911static int action_dahdidndoff(struct mansession *s, const struct message *m)
16912{
16913 struct dahdi_pvt *p;
16914 const char *channel = astman_get_header(m, "DAHDIChannel");
16915
16916 if (ast_strlen_zero(channel)) {
16917 astman_send_error(s, m, "No channel specified");
16918 return 0;
16919 }
16921 if (!p) {
16922 astman_send_error(s, m, "No such channel");
16923 return 0;
16924 }
16925 dahdi_dnd(p, 0);
16926 astman_send_ack(s, m, "DND Disabled");
16927 return 0;
16928}
16929
16930static int action_transfer(struct mansession *s, const struct message *m)
16931{
16932 struct dahdi_pvt *p;
16933 const char *channel = astman_get_header(m, "DAHDIChannel");
16934
16935 if (ast_strlen_zero(channel)) {
16936 astman_send_error(s, m, "No channel specified");
16937 return 0;
16938 }
16940 if (!p) {
16941 astman_send_error(s, m, "No such channel");
16942 return 0;
16943 }
16944 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16945 astman_send_error(s, m, "Channel signaling is not analog");
16946 return 0;
16947 }
16949 astman_send_ack(s, m, "DAHDITransfer");
16950 return 0;
16951}
16952
16953static int action_transferhangup(struct mansession *s, const struct message *m)
16954{
16955 struct dahdi_pvt *p;
16956 const char *channel = astman_get_header(m, "DAHDIChannel");
16957
16958 if (ast_strlen_zero(channel)) {
16959 astman_send_error(s, m, "No channel specified");
16960 return 0;
16961 }
16963 if (!p) {
16964 astman_send_error(s, m, "No such channel");
16965 return 0;
16966 }
16967 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
16968 astman_send_error(s, m, "Channel signaling is not analog");
16969 return 0;
16970 }
16972 astman_send_ack(s, m, "DAHDIHangup");
16973 return 0;
16974}
16975
16976static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
16977{
16978 struct dahdi_pvt *p;
16979 const char *channel = astman_get_header(m, "DAHDIChannel");
16980 const char *number = astman_get_header(m, "Number");
16981 int i;
16982
16983 if (ast_strlen_zero(channel)) {
16984 astman_send_error(s, m, "No channel specified");
16985 return 0;
16986 }
16987 if (ast_strlen_zero(number)) {
16988 astman_send_error(s, m, "No number specified");
16989 return 0;
16990 }
16992 if (!p) {
16993 astman_send_error(s, m, "No such channel");
16994 return 0;
16995 }
16996 if (!p->owner) {
16997 astman_send_error(s, m, "Channel does not have it's owner");
16998 return 0;
16999 }
17000 for (i = 0; i < strlen(number); i++) {
17001 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = number[i] };
17002 dahdi_queue_frame(p, &f);
17003 }
17004 astman_send_ack(s, m, "DAHDIDialOffhook");
17005 return 0;
17006}
17007
17008static int action_dahdishowchannels(struct mansession *s, const struct message *m)
17009{
17010 struct dahdi_pvt *tmp = NULL;
17011 const char *id = astman_get_header(m, "ActionID");
17012 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
17013 char idText[256];
17014 int channels = 0;
17015 int dahdichanquery;
17016
17017 if (!dahdichannel || sscanf(dahdichannel, "%30d", &dahdichanquery) != 1) {
17018 /* Not numeric string. */
17019 dahdichanquery = -1;
17020 }
17021
17022 idText[0] = '\0';
17023 if (!ast_strlen_zero(id)) {
17024 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17025 }
17026
17027 astman_send_listack(s, m, "DAHDI channel status will follow", "start");
17028
17030
17031 for (tmp = iflist; tmp; tmp = tmp->next) {
17032 if (tmp->channel > 0) {
17033 int alm;
17034
17035 /* If a specific channel is queried for, only deliver status for that channel */
17036 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
17037 continue;
17038
17039 alm = get_alarms(tmp);
17040 channels++;
17041 if (tmp->owner) {
17042 /* Add data if we have a current call */
17043 astman_append(s,
17044 "Event: DAHDIShowChannels\r\n"
17045 "DAHDIChannel: %d\r\n"
17046 "Channel: %s\r\n"
17047 "Uniqueid: %s\r\n"
17048 "AccountCode: %s\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,
17058 ast_channel_name(tmp->owner),
17061 sig2str(tmp->sig),
17062 tmp->sig,
17063 tmp->context,
17064 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17065 alarm2str(alm),
17066 tmp->description, idText);
17067 } else {
17068 astman_append(s,
17069 "Event: DAHDIShowChannels\r\n"
17070 "DAHDIChannel: %d\r\n"
17071 "Signalling: %s\r\n"
17072 "SignallingCode: %d\r\n"
17073 "Context: %s\r\n"
17074 "DND: %s\r\n"
17075 "Alarm: %s\r\n"
17076 "Description: %s\r\n"
17077 "%s"
17078 "\r\n",
17079 tmp->channel, sig2str(tmp->sig), tmp->sig,
17080 tmp->context,
17081 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17082 alarm2str(alm),
17083 tmp->description, idText);
17084 }
17085 }
17086 }
17087
17089
17090 astman_send_list_complete_start(s, m, "DAHDIShowChannelsComplete", channels);
17091 astman_append(s, "Items: %d\r\n", channels);
17093 return 0;
17094}
17095
17096static int action_dahdishowstatus(struct mansession *s, const struct message *m)
17097{
17098 const char *id = astman_get_header(m, "ActionID");
17099 int span;
17100 int res;
17101 char alarmstr[50];
17102 int ctl;
17103 char idText[256];
17104 int numspans = 0;
17105 struct dahdi_spaninfo spaninfo;
17106
17107 ctl = open("/dev/dahdi/ctl", O_RDWR);
17108 if (ctl < 0) {
17109 astman_send_error(s, m, "No DAHDI detected");
17110 return 0;
17111 }
17112
17113 idText[0] = '\0';
17114 if (!ast_strlen_zero(id)) {
17115 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17116 }
17117 astman_send_listack(s, m, "DAHDI span statuses will follow", "start");
17118
17119 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
17120 spaninfo.spanno = span;
17121 res = ioctl(ctl, DAHDI_SPANSTAT, &spaninfo);
17122 if (res) {
17123 continue;
17124 }
17125 numspans++;
17126 build_alarm_info(alarmstr, &spaninfo);
17127 astman_append(s,
17128 "Event: DAHDIShowStatus\r\n"
17129 "Span: %d\r\n"
17130 "Description: %s\r\n"
17131 "Alarms: %s\r\n"
17132 "IRQ: %d\r\n"
17133 "bpviol: %d\r\n"
17134 "CRC: %d\r\n"
17135 "Framing: %s\r\n"
17136 "Coding: %s\r\n"
17137 "Options: %s\r\n"
17138 "LBO: %s\r\n"
17139 "%s"
17140 "\r\n",
17141 span, spaninfo.desc, alarmstr, spaninfo.irqmisses, spaninfo.bpvcount, spaninfo.crc4count,
17142 spaninfo.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
17143 spaninfo.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
17144 spaninfo.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
17145 "CAS",
17146 spaninfo.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
17147 spaninfo.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
17148 spaninfo.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
17149 "Unk",
17150 spaninfo.lineconfig & DAHDI_CONFIG_CRC4 ?
17151 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
17152 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
17153 lbostr[spaninfo.lbo],
17154 idText);
17155 }
17156 close(ctl);
17157
17158 astman_send_list_complete_start(s, m, "DAHDIShowStatusComplete", numspans);
17159 astman_append(s, "Items: %d\r\n", numspans);
17161 return 0;
17162}
17163
17164#if defined(HAVE_PRI)
17165static int action_prishowspans(struct mansession *s, const struct message *m)
17166{
17167 int count;
17168 int idx;
17169 int span_query;
17170 struct dahdi_pri *dspan;
17171 const char *id = astman_get_header(m, "ActionID");
17172 const char *span_str = astman_get_header(m, "Span");
17173 char action_id[256];
17174 const char *show_cmd = "PRIShowSpans";
17175
17176 /* NOTE: Asking for span 0 gets all spans. */
17177 if (!ast_strlen_zero(span_str)) {
17178 span_query = atoi(span_str);
17179 } else {
17180 span_query = 0;
17181 }
17182
17183 if (!ast_strlen_zero(id)) {
17184 snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
17185 } else {
17186 action_id[0] = '\0';
17187 }
17188
17189 astman_send_listack(s, m, "Span status will follow", "start");
17190
17191 count = 0;
17192 for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
17193 dspan = &pris[idx];
17194
17195 /* If a specific span is asked for, only deliver status for that span. */
17196 if (0 < span_query && dspan->pri.span != span_query) {
17197 continue;
17198 }
17199
17200 if (dspan->pri.pri) {
17201 count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
17202 action_id);
17203 }
17204 }
17205
17206 astman_send_list_complete_start(s, m, "PRIShowSpansComplete", count);
17207 astman_append(s, "Items: %d\r\n", count);
17209 return 0;
17210}
17211#endif /* defined(HAVE_PRI) */
17212
17213#if defined(HAVE_SS7)
17214static int linkset_addsigchan(int sigchan)
17215{
17216 struct dahdi_ss7 *link;
17217 int res;
17218 int curfd;
17219 struct dahdi_params params;
17220 struct dahdi_bufferinfo bi;
17221 struct dahdi_spaninfo si;
17222
17223 if (sigchan < 0) {
17224 ast_log(LOG_ERROR, "Invalid sigchan!\n");
17225 return -1;
17226 }
17227 if (cur_ss7type < 0) {
17228 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
17229 return -1;
17230 }
17231 if (cur_pointcode < 0) {
17232 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
17233 return -1;
17234 }
17235 if (cur_adjpointcode < 0) {
17236 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
17237 return -1;
17238 }
17239 if (cur_defaultdpc < 0) {
17240 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
17241 return -1;
17242 }
17243 if (cur_networkindicator < 0) {
17244 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
17245 return -1;
17246 }
17247 link = ss7_resolve_linkset(cur_linkset);
17248 if (!link) {
17249 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
17250 return -1;
17251 }
17252 if (link->ss7.numsigchans >= SIG_SS7_NUM_DCHANS) {
17253 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
17254 return -1;
17255 }
17256
17257 curfd = link->ss7.numsigchans;
17258
17259 /* Open signaling channel */
17260 link->ss7.fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
17261 if (link->ss7.fds[curfd] < 0) {
17262 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan,
17263 strerror(errno));
17264 return -1;
17265 }
17266 if (ioctl(link->ss7.fds[curfd], DAHDI_SPECIFY, &sigchan) == -1) {
17267 dahdi_close_ss7_fd(link, curfd);
17268 ast_log(LOG_ERROR, "Unable to specify SS7 sigchan %d (%s)\n", sigchan,
17269 strerror(errno));
17270 return -1;
17271 }
17272
17273 /* Get signaling channel parameters */
17274 memset(&params, 0, sizeof(params));
17275 res = ioctl(link->ss7.fds[curfd], DAHDI_GET_PARAMS, &params);
17276 if (res) {
17277 dahdi_close_ss7_fd(link, curfd);
17278 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan,
17279 strerror(errno));
17280 return -1;
17281 }
17282 if (params.sigtype != DAHDI_SIG_HDLCFCS
17283 && params.sigtype != DAHDI_SIG_HARDHDLC
17284 && params.sigtype != DAHDI_SIG_MTP2) {
17285 dahdi_close_ss7_fd(link, curfd);
17286 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
17287 return -1;
17288 }
17289
17290 /* Set signaling channel buffer policy. */
17291 memset(&bi, 0, sizeof(bi));
17292 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
17293 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
17294 bi.numbufs = 32;
17295 bi.bufsize = 512;
17296 if (ioctl(link->ss7.fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
17297 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n",
17298 sigchan, strerror(errno));
17299 dahdi_close_ss7_fd(link, curfd);
17300 return -1;
17301 }
17302
17303 /* Get current signaling channel alarm status. */
17304 memset(&si, 0, sizeof(si));
17305 res = ioctl(link->ss7.fds[curfd], DAHDI_SPANSTAT, &si);
17306 if (res) {
17307 dahdi_close_ss7_fd(link, curfd);
17308 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan,
17309 strerror(errno));
17310 }
17311
17312 res = sig_ss7_add_sigchan(&link->ss7, curfd, cur_ss7type,
17313 (params.sigtype == DAHDI_SIG_MTP2)
17314 ? SS7_TRANSPORT_DAHDIMTP2
17315 : SS7_TRANSPORT_DAHDIDCHAN,
17316 si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
17317 if (res) {
17318 dahdi_close_ss7_fd(link, curfd);
17319 return -1;
17320 }
17321
17322 ++link->ss7.numsigchans;
17323
17324 return 0;
17325}
17326#endif /* defined(HAVE_SS7) */
17327
17328#if defined(HAVE_SS7)
17329static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17330{
17331 int span;
17332 switch (cmd) {
17333 case CLI_INIT:
17334 e->command = "ss7 set debug {on|off} linkset";
17335 e->usage =
17336 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17337 " Enables debugging on a given SS7 linkset\n";
17338 return NULL;
17339 case CLI_GENERATE:
17340 return NULL;
17341 }
17342
17343 if (a->argc < 6) {
17344 return CLI_SHOWUSAGE;
17345 }
17346
17347 span = atoi(a->argv[5]);
17348 if ((span < 1) || (span > NUM_SPANS)) {
17349 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
17350 return CLI_SUCCESS;
17351 }
17352 if (!linksets[span-1].ss7.ss7) {
17353 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
17354 } else {
17355 if (!strcasecmp(a->argv[3], "on")) {
17356 linksets[span - 1].ss7.debug = 1;
17357 ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
17358 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
17359 } else {
17360 linksets[span - 1].ss7.debug = 0;
17361 ss7_set_debug(linksets[span-1].ss7.ss7, 0);
17362 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
17363 }
17364 }
17365
17366 return CLI_SUCCESS;
17367}
17368#endif /* defined(HAVE_SS7) */
17369
17370#if defined(HAVE_SS7)
17371static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17372{
17373 int linkset, cic;
17374 int blocked, i;
17375 int do_block = 0;
17376 unsigned int dpc;
17377
17378 switch (cmd) {
17379 case CLI_INIT:
17380 e->command = "ss7 {block|unblock} cic";
17381 e->usage =
17382 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17383 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17384 return NULL;
17385 case CLI_GENERATE:
17386 return NULL;
17387 }
17388
17389 if (a->argc == 6) {
17390 linkset = atoi(a->argv[3]);
17391 } else {
17392 return CLI_SHOWUSAGE;
17393 }
17394
17395 if (!strcasecmp(a->argv[1], "block")) {
17396 do_block = 1;
17397 } else if (strcasecmp(a->argv[1], "unblock")) {
17398 return CLI_SHOWUSAGE;
17399 }
17400
17401 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17402 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17403 return CLI_SUCCESS;
17404 }
17405
17406 if (!linksets[linkset-1].ss7.ss7) {
17407 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17408 return CLI_SUCCESS;
17409 }
17410
17411 cic = atoi(a->argv[5]);
17412 if (cic < 1) {
17413 ast_cli(a->fd, "Invalid CIC specified!\n");
17414 return CLI_SUCCESS;
17415 }
17416
17417 dpc = atoi(a->argv[4]);
17418 if (dpc < 1) {
17419 ast_cli(a->fd, "Invalid DPC specified!\n");
17420 return CLI_SUCCESS;
17421 }
17422
17423 for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
17424 if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
17425 blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
17426 if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
17427 if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
17428 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17429 } else {
17430 ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
17431 }
17432 } else if (!do_block && blocked) {
17433 ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
17434 } else {
17435 ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
17436 }
17437 return CLI_SUCCESS;
17438 }
17439 }
17440
17441 ast_cli(a->fd, "Invalid CIC specified!\n");
17442 return CLI_SUCCESS;
17443}
17444#endif /* defined(HAVE_SS7) */
17445
17446#if defined(HAVE_SS7)
17447static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17448{
17449 int linkset, i;
17450 enum {
17451 DO_BLOCK,
17452 DO_UNBLOCK,
17453 DO_RESET,
17454 } do_what;
17455
17456 switch (cmd) {
17457 case CLI_INIT:
17458 e->command = "ss7 {reset|block|unblock} linkset";
17459 e->usage =
17460 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17461 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17462 return NULL;
17463 case CLI_GENERATE:
17464 return NULL;
17465 }
17466
17467 if (a->argc == 4) {
17468 linkset = atoi(a->argv[3]);
17469 } else {
17470 return CLI_SHOWUSAGE;
17471 }
17472
17473 if (!strcasecmp(a->argv[1], "block")) {
17474 do_what = DO_BLOCK;
17475 } else if (!strcasecmp(a->argv[1], "unblock")) {
17476 do_what = DO_UNBLOCK;
17477 } else if (!strcasecmp(a->argv[1], "reset")) {
17478 do_what = DO_RESET;
17479 } else {
17480 return CLI_SHOWUSAGE;
17481 }
17482
17483 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17484 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17485 return CLI_SUCCESS;
17486 }
17487
17488 if (!linksets[linkset - 1].ss7.ss7) {
17489 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17490 return CLI_SUCCESS;
17491 }
17492
17493 for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
17494 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17495 if (linksets[linkset - 1].ss7.pvts[i]) {
17496 switch (do_what) {
17497 case DO_BLOCK:
17498 case DO_UNBLOCK:
17499 if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
17500 ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
17501 (do_what == DO_BLOCK) ? "blocking" : "unblocking",
17502 linksets[linkset - 1].ss7.pvts[i]->cic);
17503 }
17504 break;
17505 case DO_RESET:
17506 if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
17507 linksets[linkset - 1].ss7.pvts[i]->cic,
17508 linksets[linkset - 1].ss7.pvts[i]->dpc)) {
17509 ast_cli(a->fd, "Sent reset request on CIC %d\n",
17510 linksets[linkset - 1].ss7.pvts[i]->cic);
17511 }
17512 break;
17513 }
17514 }
17515 }
17516
17517 return CLI_SUCCESS;
17518}
17519#endif /* defined(HAVE_SS7) */
17520
17521#if defined(HAVE_SS7)
17522static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17523{
17524 int linkset, cic, range, chanpos;
17525 int i, dpc, orient = 0;
17526 int do_block = 0;
17527 unsigned char state[255];
17528
17529 switch (cmd) {
17530 case CLI_INIT:
17531 e->command = "ss7 {block|unblock} group";
17532 e->usage =
17533 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17534 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17535 return NULL;
17536 case CLI_GENERATE:
17537 return NULL;
17538 }
17539
17540 if (a->argc == 7 || a->argc == 8) {
17541 linkset = atoi(a->argv[3]);
17542 } else {
17543 return CLI_SHOWUSAGE;
17544 }
17545
17546 if (!strcasecmp(a->argv[1], "block")) {
17547 do_block = 1;
17548 } else if (strcasecmp(a->argv[1], "unblock")) {
17549 return CLI_SHOWUSAGE;
17550 }
17551
17552 if (a->argc == 8) {
17553 if (!strcasecmp(a->argv[7], "H")) {
17554 orient = 1;
17555 } else {
17556 return CLI_SHOWUSAGE;
17557 }
17558 }
17559
17560 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17561 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17562 return CLI_SUCCESS;
17563 }
17564
17565 if (!linksets[linkset-1].ss7.ss7) {
17566 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17567 return CLI_SUCCESS;
17568 }
17569
17570 cic = atoi(a->argv[5]);
17571 if (cic < 1) {
17572 ast_cli(a->fd, "Invalid CIC specified!\n");
17573 return CLI_SUCCESS;
17574 }
17575
17576 range = atoi(a->argv[6]);
17577 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17578 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17579 ast_cli(a->fd, "Invalid range specified!\n");
17580 return CLI_SUCCESS;
17581 }
17582
17583 dpc = atoi(a->argv[4]);
17584 if (dpc < 1) {
17585 ast_cli(a->fd, "Invalid DPC specified!\n");
17586 return CLI_SUCCESS;
17587 }
17588
17589 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17590 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17591 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17592 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17593 return CLI_SHOWUSAGE;
17594 }
17595
17596 memset(state, 0, sizeof(state));
17597 for (i = 0; i <= range; ++i) {
17598 state[i] = 1;
17599 }
17600
17601 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17602 chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
17603 if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
17604 ast_cli(a->fd, "Unable allocate new ss7call\n");
17605 } else {
17606 ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17607 orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
17608 }
17609
17610 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17611
17612 /* Break poll on the linkset so it sends our messages */
17613 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17614 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17615 }
17616 return CLI_SUCCESS;
17617}
17618#endif /* defined(HAVE_SS7) */
17619
17620#if defined(HAVE_SS7)
17621static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17622{
17623 int linkset, cic, range;
17624 unsigned int dpc;
17625
17626 switch (cmd) {
17627 case CLI_INIT:
17628 e->command = "ss7 reset group";
17629 e->usage =
17630 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17631 " Send a GRS for the given CIC range on the specified linkset\n";
17632 return NULL;
17633 case CLI_GENERATE:
17634 return NULL;
17635 }
17636
17637 if (a->argc == 7) {
17638 linkset = atoi(a->argv[3]);
17639 } else {
17640 return CLI_SHOWUSAGE;
17641 }
17642
17643 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17644 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17645 return CLI_SUCCESS;
17646 }
17647
17648 if (!linksets[linkset-1].ss7.ss7) {
17649 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17650 return CLI_SUCCESS;
17651 }
17652
17653 cic = atoi(a->argv[5]);
17654
17655 if (cic < 1) {
17656 ast_cli(a->fd, "Invalid CIC specified!\n");
17657 return CLI_SUCCESS;
17658 }
17659
17660 range = atoi(a->argv[6]);
17661 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17662 ast_cli(a->fd, "Invalid range specified!\n");
17663 return CLI_SUCCESS;
17664 }
17665
17666 dpc = atoi(a->argv[4]);
17667 if (dpc < 1) {
17668 ast_cli(a->fd, "Invalid DPC specified!\n");
17669 return CLI_SUCCESS;
17670 }
17671
17672 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17673 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17674 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17675 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17676 return CLI_SHOWUSAGE;
17677 }
17678
17679 if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
17680 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17681 } else {
17682 ast_cli(a->fd, "GRS sent ... \n");
17683 }
17684
17685 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17686
17687 /* Break poll on the linkset so it sends our messages */
17688 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17689 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17690 }
17691 return CLI_SUCCESS;
17692}
17693#endif /* defined(HAVE_SS7) */
17694
17695#if defined(HAVE_SS7)
17696static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17697{
17698 int linkset;
17699
17700 switch (cmd) {
17701 case CLI_INIT:
17702 e->command = "ss7 show calls";
17703 e->usage =
17704 "Usage: ss7 show calls <linkset>\n"
17705 " Show SS7 calls on the specified linkset\n";
17706 return NULL;
17707 case CLI_GENERATE:
17708 return NULL;
17709 }
17710
17711 if (a->argc == 4) {
17712 linkset = atoi(a->argv[3]);
17713 } else {
17714 return CLI_SHOWUSAGE;
17715 }
17716
17717 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17718 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17719 return CLI_SUCCESS;
17720 }
17721
17722 if (!linksets[linkset-1].ss7.ss7) {
17723 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17724 return CLI_SUCCESS;
17725 }
17726
17727 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17728 isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
17729 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17730
17731 return CLI_SUCCESS;
17732}
17733#endif /* defined(HAVE_SS7) */
17734
17735#if defined(HAVE_SS7)
17736static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17737{
17738 int linkset, cic, res;
17739 unsigned int dpc;
17740
17741 switch (cmd) {
17742 case CLI_INIT:
17743 e->command = "ss7 reset cic";
17744 e->usage =
17745 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17746 " Send a RSC for the given CIC on the specified linkset\n";
17747 return NULL;
17748 case CLI_GENERATE:
17749 return NULL;
17750 }
17751
17752 if (a->argc == 6) {
17753 linkset = atoi(a->argv[3]);
17754 } else {
17755 return CLI_SHOWUSAGE;
17756 }
17757
17758 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17759 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17760 return CLI_SUCCESS;
17761 }
17762
17763 if (!linksets[linkset-1].ss7.ss7) {
17764 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17765 return CLI_SUCCESS;
17766 }
17767
17768 cic = atoi(a->argv[5]);
17769
17770 if (cic < 1) {
17771 ast_cli(a->fd, "Invalid CIC specified!\n");
17772 return CLI_SUCCESS;
17773 }
17774
17775 dpc = atoi(a->argv[4]);
17776 if (dpc < 1) {
17777 ast_cli(a->fd, "Invalid DPC specified!\n");
17778 return CLI_SUCCESS;
17779 }
17780
17781 res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
17782
17783 ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
17784
17785 return CLI_SUCCESS;
17786}
17787#endif /* defined(HAVE_SS7) */
17788
17789#if defined(HAVE_SS7)
17790static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17791{
17792 int linkset;
17793 unsigned int slc;
17794 unsigned int arg = 0;
17795 const char *res;
17796
17797 switch (cmd) {
17798 case CLI_INIT:
17799 e->command = "ss7 mtp3";
17800 e->usage =
17801 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
17802 " Send a NET MNG message\n"
17803 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
17804 return NULL;
17805 case CLI_GENERATE:
17806 return NULL;
17807 }
17808
17809 if (a->argc < 5) {
17810 return CLI_SHOWUSAGE;
17811 }
17812
17813 linkset = atoi(a->argv[2]);
17814 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17815 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17816 return CLI_SUCCESS;
17817 }
17818 if (!linksets[linkset-1].ss7.ss7) {
17819 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17820 return CLI_SUCCESS;
17821 }
17822
17823 slc = atoi(a->argv[3]);
17824
17825 if (a->argc == 6) {
17826 arg = atoi(a->argv[5]);
17827 }
17828
17829 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17830 res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
17831 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17832
17833 /* Break poll on the linkset so it sends our messages */
17834 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17835 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17836 }
17837
17838 ast_cli(a->fd, "%s", res);
17839
17840 return CLI_SUCCESS;
17841}
17842#endif /* defined(HAVE_SS7) */
17843
17844#if defined(HAVE_SS7)
17845static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17846{
17847 int linkset;
17848 unsigned int slc = 0;
17849
17850 switch (cmd) {
17851 case CLI_INIT:
17852 e->command = "ss7 restart mtp3";
17853 e->usage =
17854 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
17855 " Restart link\n";
17856 return NULL;
17857 case CLI_GENERATE:
17858 return NULL;
17859 }
17860
17861 if (a->argc < 5) {
17862 return CLI_SHOWUSAGE;
17863 }
17864
17865 linkset = atoi(a->argv[3]);
17866 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17867 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
17868 return CLI_SUCCESS;
17869 }
17870 if (!linksets[linkset-1].ss7.ss7) {
17871 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17872 return CLI_SUCCESS;
17873 }
17874
17875 slc = atoi(a->argv[4]);
17876
17877 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17878 mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
17879 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17880
17881 /* Break poll on the linkset so it sends our messages */
17882 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17883 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17884 }
17885
17886 return CLI_SUCCESS;
17887}
17888#endif /* defined(HAVE_SS7) */
17889
17890#if defined(HAVE_SS7)
17891static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17892{
17893 int linkset;
17894 struct sig_ss7_linkset *ss7;
17895 switch (cmd) {
17896 case CLI_INIT:
17897 e->command = "ss7 show linkset";
17898 e->usage =
17899 "Usage: ss7 show linkset <span>\n"
17900 " Shows the status of an SS7 linkset.\n";
17901 return NULL;
17902 case CLI_GENERATE:
17903 return NULL;
17904 }
17905
17906 if (a->argc < 4) {
17907 return CLI_SHOWUSAGE;
17908 }
17909
17910 linkset = atoi(a->argv[3]);
17911 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17912 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17913 return CLI_SUCCESS;
17914 }
17915 ss7 = &linksets[linkset - 1].ss7;
17916 if (!ss7->ss7) {
17917 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17918 return CLI_SUCCESS;
17919 }
17920
17921 ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
17922 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
17923 ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
17924 ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
17925 ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
17926 ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
17927 ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
17928 ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
17929 ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
17930 ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
17931
17932 return CLI_SUCCESS;
17933}
17934#endif /* defined(HAVE_SS7) */
17935
17936#if defined(HAVE_SS7)
17937static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17938{
17939 int linkset;
17940
17941 switch (cmd) {
17942 case CLI_INIT:
17943 e->command = "ss7 show channels";
17944 e->usage =
17945 "Usage: ss7 show channels\n"
17946 " Displays SS7 channel information at a glance.\n";
17947 return NULL;
17948 case CLI_GENERATE:
17949 return NULL;
17950 }
17951
17952 if (a->argc != 3) {
17953 return CLI_SHOWUSAGE;
17954 }
17955
17957 for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
17958 if (linksets[linkset].ss7.ss7) {
17959 sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
17960 }
17961 }
17962 return CLI_SUCCESS;
17963}
17964#endif /* defined(HAVE_SS7) */
17965
17966#if defined(HAVE_SS7)
17967static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17968{
17969#define FORMAT "%5s %5s %6s %12s %-12s\n"
17970#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
17971 int i, linkset, dpc = 0;
17972 struct sig_ss7_linkset *ss7;
17973 char *state;
17974 char blocking[12];
17975
17976 switch (cmd) {
17977 case CLI_INIT:
17978 e->command = "ss7 show cics";
17979 e->usage =
17980 "Usage: ss7 show cics <linkset> [dpc]\n"
17981 " Shows the cics of an SS7 linkset.\n";
17982 return NULL;
17983 case CLI_GENERATE:
17984 return NULL;
17985 }
17986
17987 if (a->argc < 4 || a->argc > 5) {
17988 return CLI_SHOWUSAGE;
17989 }
17990
17991 linkset = atoi(a->argv[3]);
17992
17993 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17994 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17995 return CLI_SUCCESS;
17996 }
17997
17998 if (!linksets[linkset-1].ss7.ss7) {
17999 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18000 return CLI_SUCCESS;
18001 }
18002 ss7 = &linksets[linkset-1].ss7;
18003
18004 if (a->argc == 5) {
18005 dpc = atoi(a->argv[4]);
18006 if (dpc < 1) {
18007 ast_cli(a->fd, "Invalid DPC specified!\n");
18008 return CLI_SUCCESS;
18009 }
18010 }
18011
18012 ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
18013
18014 for (i = 0; i < ss7->numchans; i++) {
18015 if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
18016 struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
18017
18018 if (ss7->pvts[i]->owner) {
18019 state = "Used";
18020 } else if (ss7->pvts[i]->ss7call) {
18021 state = "Pending";
18022 } else if (!p->inservice) {
18023 state = "NotInServ";
18024 } else {
18025 state = "Idle";
18026 }
18027
18028 if (p->locallyblocked) {
18029 strcpy(blocking, "L:");
18031 strcat(blocking, "M");
18032 } else {
18033 strcat(blocking, " ");
18034 }
18035
18037 strcat(blocking, "H");
18038 } else {
18039 strcat(blocking, " ");
18040 }
18041 } else {
18042 strcpy(blocking, " ");
18043 }
18044
18045 if (p->remotelyblocked) {
18046 strcat(blocking, " R:");
18048 strcat(blocking, "M");
18049 } else {
18050 strcat(blocking, " ");
18051 }
18052
18054 strcat(blocking, "H");
18055 } else {
18056 strcat(blocking, " ");
18057 }
18058 }
18059
18060 ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
18061 }
18062 }
18063
18064 return CLI_SUCCESS;
18065#undef FORMAT
18066#undef FORMAT2
18067}
18068#endif /* defined(HAVE_SS7) */
18069
18070#if defined(HAVE_SS7)
18071static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18072{
18073 switch (cmd) {
18074 case CLI_INIT:
18075 e->command = "ss7 show version";
18076 e->usage =
18077 "Usage: ss7 show version\n"
18078 " Show the libss7 version\n";
18079 return NULL;
18080 case CLI_GENERATE:
18081 return NULL;
18082 }
18083
18084 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
18085
18086 return CLI_SUCCESS;
18087}
18088#endif /* defined(HAVE_SS7) */
18089
18090#if defined(HAVE_SS7)
18091static struct ast_cli_entry dahdi_ss7_cli[] = {
18092 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
18093 AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
18094 AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
18095 AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
18096 AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
18097 AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
18098 AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
18099 AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
18100 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
18101 AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
18102 AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
18103 AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
18104 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
18105};
18106#endif /* defined(HAVE_SS7) */
18107
18108#if defined(HAVE_PRI)
18109#if defined(HAVE_PRI_CCSS)
18110/*!
18111 * \internal
18112 * \brief CC agent initialization.
18113 * \since 1.8
18114 *
18115 * \param agent CC core agent control.
18116 * \param chan Original channel the agent will attempt to recall.
18117 *
18118 * \details
18119 * This callback is called when the CC core is initialized. Agents should allocate
18120 * any private data necessary for the call and assign it to the private_data
18121 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
18122 * specific agent type, they should be set in this function as well.
18123 *
18124 * \retval 0 on success.
18125 * \retval -1 on error.
18126 */
18127static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
18128{
18129 struct dahdi_pvt *pvt;
18130 struct sig_pri_chan *pvt_chan;
18131 int res;
18132
18133 ast_assert(!strcmp(ast_channel_tech(chan)->type, "DAHDI"));
18134
18135 pvt = ast_channel_tech_pvt(chan);
18136 if (dahdi_sig_pri_lib_handles(pvt->sig)) {
18137 pvt_chan = pvt->sig_pvt;
18138 } else {
18139 pvt_chan = NULL;
18140 }
18141 if (!pvt_chan) {
18142 return -1;
18143 }
18144
18146
18147 res = sig_pri_cc_agent_init(agent, pvt_chan);
18148 if (res) {
18150 }
18151 return res;
18152}
18153#endif /* defined(HAVE_PRI_CCSS) */
18154#endif /* defined(HAVE_PRI) */
18155
18156#if defined(HAVE_PRI)
18157#if defined(HAVE_PRI_CCSS)
18158/*!
18159 * \internal
18160 * \brief Destroy private data on the agent.
18161 * \since 1.8
18162 *
18163 * \param agent CC core agent control.
18164 *
18165 * \details
18166 * The core will call this function upon completion
18167 * or failure of CC.
18168 */
18169static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
18170{
18172
18174}
18175#endif /* defined(HAVE_PRI_CCSS) */
18176#endif /* defined(HAVE_PRI) */
18177
18178#if defined(HAVE_PRI)
18179#if defined(HAVE_PRI_CCSS)
18180static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
18181 .type = dahdi_pri_cc_type,
18182 .init = dahdi_pri_cc_agent_init,
18183 .start_offer_timer = sig_pri_cc_agent_start_offer_timer,
18184 .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
18185 .respond = sig_pri_cc_agent_req_rsp,
18186 .status_request = sig_pri_cc_agent_status_req,
18187 .stop_ringing = sig_pri_cc_agent_stop_ringing,
18188 .party_b_free = sig_pri_cc_agent_party_b_free,
18189 .start_monitoring = sig_pri_cc_agent_start_monitoring,
18190 .callee_available = sig_pri_cc_agent_callee_available,
18191 .destructor = dahdi_pri_cc_agent_destructor,
18192};
18193#endif /* defined(HAVE_PRI_CCSS) */
18194#endif /* defined(HAVE_PRI) */
18195
18196#if defined(HAVE_PRI)
18197#if defined(HAVE_PRI_CCSS)
18198static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
18199 .type = dahdi_pri_cc_type,
18200 .request_cc = sig_pri_cc_monitor_req_cc,
18201 .suspend = sig_pri_cc_monitor_suspend,
18202 .unsuspend = sig_pri_cc_monitor_unsuspend,
18203 .status_response = sig_pri_cc_monitor_status_rsp,
18204 .cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
18205 .destructor = sig_pri_cc_monitor_destructor,
18206};
18207#endif /* defined(HAVE_PRI_CCSS) */
18208#endif /* defined(HAVE_PRI) */
18209
18210static int __unload_module(void)
18211{
18212 struct dahdi_pvt *p;
18213#if defined(HAVE_PRI) || defined(HAVE_SS7)
18214 int i, j;
18215#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18216
18217#ifdef HAVE_PRI
18218 for (i = 0; i < NUM_SPANS; i++) {
18219 if (pris[i].pri.master != AST_PTHREADT_NULL) {
18220 pthread_cancel(pris[i].pri.master);
18221 pthread_kill(pris[i].pri.master, SIGURG);
18222 }
18223 }
18224 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
18225 ast_unregister_application(dahdi_send_keypad_facility_app);
18226#ifdef HAVE_PRI_PROG_W_CAUSE
18227 ast_unregister_application(dahdi_send_callrerouting_facility_app);
18228#endif
18229#endif
18230#if defined(HAVE_SS7)
18231 for (i = 0; i < NUM_SPANS; i++) {
18232 if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
18233 pthread_cancel(linksets[i].ss7.master);
18234 pthread_kill(linksets[i].ss7.master, SIGURG);
18235 }
18236 }
18237 ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
18238#endif /* defined(HAVE_SS7) */
18239#if defined(HAVE_OPENR2)
18240 dahdi_r2_destroy_links();
18241 ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
18242 ast_unregister_application(dahdi_accept_r2_call_app);
18243#endif
18244
18246
18248 ast_manager_unregister("DAHDIDialOffhook");
18249 ast_manager_unregister("DAHDIHangup");
18250 ast_manager_unregister("DAHDITransfer");
18251 ast_manager_unregister("DAHDIDNDoff");
18252 ast_manager_unregister("DAHDIDNDon");
18253 ast_manager_unregister("DAHDIShowChannels");
18254 ast_manager_unregister("DAHDIShowStatus");
18255 ast_manager_unregister("DAHDIRestart");
18256#if defined(HAVE_PRI)
18257 ast_manager_unregister("PRIShowSpans");
18258 ast_manager_unregister("PRIDebugSet");
18259 ast_manager_unregister("PRIDebugFileSet");
18260 ast_manager_unregister("PRIDebugFileUnset");
18261#endif /* defined(HAVE_PRI) */
18263
18264 /* Hangup all interfaces if they have an owner */
18266 for (p = iflist; p; p = p->next) {
18267 if (p->owner)
18269 }
18271
18274 pthread_cancel(monitor_thread);
18275 pthread_kill(monitor_thread, SIGURG);
18276 pthread_join(monitor_thread, NULL);
18277 }
18280
18282
18283#if defined(HAVE_PRI)
18284 for (i = 0; i < NUM_SPANS; i++) {
18285 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
18286 pthread_join(pris[i].pri.master, NULL);
18287 }
18288 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
18289 dahdi_close_pri_fd(&(pris[i]), j);
18290 }
18291 sig_pri_stop_pri(&pris[i].pri);
18292 }
18293#if defined(HAVE_PRI_CCSS)
18294 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
18295 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
18296#endif /* defined(HAVE_PRI_CCSS) */
18298#endif
18299
18300#if defined(HAVE_SS7)
18301 for (i = 0; i < NUM_SPANS; i++) {
18302 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
18303 pthread_join(linksets[i].ss7.master, NULL);
18304 }
18305 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
18306 dahdi_close_ss7_fd(&(linksets[i]), j);
18307 }
18308 if (linksets[i].ss7.ss7) {
18309 ss7_destroy(linksets[i].ss7.ss7);
18310 linksets[i].ss7.ss7 = NULL;
18311 }
18312 }
18313#endif /* defined(HAVE_SS7) */
18315
18317
18320 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
18321 return 0;
18322}
18323
18324static int unload_module(void)
18325{
18326#if defined(HAVE_PRI) || defined(HAVE_SS7)
18327 int y;
18328#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18329#ifdef HAVE_PRI
18330 for (y = 0; y < NUM_SPANS; y++)
18331 ast_mutex_destroy(&pris[y].pri.lock);
18332#endif
18333#if defined(HAVE_SS7)
18334 for (y = 0; y < NUM_SPANS; y++)
18335 ast_mutex_destroy(&linksets[y].ss7.lock);
18336#endif /* defined(HAVE_SS7) */
18337 return __unload_module();
18338}
18339
18340static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
18341{
18342 char *c, *chan;
18343 int x, start, finish;
18344 struct dahdi_pvt *tmp;
18345
18346 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
18347 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
18348 return -1;
18349 }
18350
18351 c = ast_strdupa(value);
18352
18353 while ((chan = strsep(&c, ","))) {
18354 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
18355 /* Range */
18356 } else if (sscanf(chan, "%30d", &start)) {
18357 /* Just one */
18358 finish = start;
18359 } else if (!strcasecmp(chan, "pseudo")) {
18360 finish = start = CHAN_PSEUDO;
18361 } else {
18362 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
18363 return -1;
18364 }
18365 if (finish < start) {
18366 ast_log(LOG_WARNING, "Silliness: %d < %d\n", start, finish);
18367 x = finish;
18368 finish = start;
18369 start = x;
18370 }
18371
18372 for (x = start; x <= finish; x++) {
18373 if (conf->wanted_channels_start &&
18374 (x < conf->wanted_channels_start ||
18375 x > conf->wanted_channels_end)
18376 ) {
18377 continue;
18378 }
18379 tmp = mkintf(x, conf, reload);
18380
18381 if (tmp) {
18382 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
18383 } else {
18384 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
18385 (reload == 1) ? "reconfigure" : "register", value);
18386 return -1;
18387 }
18388 if (x == CHAN_PSEUDO) {
18389 has_pseudo = 1;
18390 }
18391 }
18392 }
18393
18394 return 0;
18395}
18396
18397/** The length of the parameters list of 'dahdichan'.
18398 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18399#define MAX_CHANLIST_LEN 80
18400
18401static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
18402{
18403 char *parse = ast_strdupa(data);
18404 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
18405 unsigned int param_count;
18406 unsigned int x;
18407
18408 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
18409 return;
18410
18411 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
18412
18413 /* first parameter is tap length, process it here */
18414
18415 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
18416
18417 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
18418 confp->chan.echocancel.head.tap_length = x;
18419 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
18420 confp->chan.echocancel.head.tap_length = 128;
18421
18422 /* now process any remaining parameters */
18423
18424 for (x = 1; x < param_count; x++) {
18425 struct {
18426 char *name;
18427 char *value;
18428 } param;
18429
18430 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
18431 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, params[x]);
18432 continue;
18433 }
18434
18435 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
18436 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, param.name);
18437 continue;
18438 }
18439
18440 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
18441
18442 if (param.value) {
18443 if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
18444 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line, param.value);
18445 continue;
18446 }
18447 }
18448 confp->chan.echocancel.head.param_count++;
18449 }
18450}
18451
18452#if defined(HAVE_PRI)
18453#if defined(HAVE_PRI_DISPLAY_TEXT)
18454/*!
18455 * \internal
18456 * \brief Determine the configured display text options.
18457 * \since 10.0
18458 *
18459 * \param value Configuration value string.
18460 *
18461 * \return Configured display text option flags.
18462 */
18463static unsigned long dahdi_display_text_option(const char *value)
18464{
18465 char *val_str;
18466 char *opt_str;
18467 unsigned long options;
18468
18469 options = 0;
18470 val_str = ast_strdupa(value);
18471
18472 for (;;) {
18473 opt_str = strsep(&val_str, ",");
18474 if (!opt_str) {
18475 break;
18476 }
18477 opt_str = ast_strip(opt_str);
18478 if (!*opt_str) {
18479 continue;
18480 }
18481
18482 if (!strcasecmp(opt_str, "block")) {
18483 options |= PRI_DISPLAY_OPTION_BLOCK;
18484 } else if (!strcasecmp(opt_str, "name_initial")) {
18485 options |= PRI_DISPLAY_OPTION_NAME_INITIAL;
18486 } else if (!strcasecmp(opt_str, "name_update")) {
18487 options |= PRI_DISPLAY_OPTION_NAME_UPDATE;
18488 } else if (!strcasecmp(opt_str, "name")) {
18489 options |= (PRI_DISPLAY_OPTION_NAME_INITIAL | PRI_DISPLAY_OPTION_NAME_UPDATE);
18490 } else if (!strcasecmp(opt_str, "text")) {
18491 options |= PRI_DISPLAY_OPTION_TEXT;
18492 }
18493 }
18494 return options;
18495}
18496#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18497#endif /* defined(HAVE_PRI) */
18498
18499#if defined(HAVE_PRI)
18500#if defined(HAVE_PRI_DATETIME_SEND)
18501/*!
18502 * \internal
18503 * \brief Determine the configured date/time send policy option.
18504 * \since 10.0
18505 *
18506 * \param value Configuration value string.
18507 *
18508 * \return Configured date/time send policy option.
18509 */
18510static int dahdi_datetime_send_option(const char *value)
18511{
18512 int option;
18513
18514 option = PRI_DATE_TIME_SEND_DEFAULT;
18515
18516 if (ast_false(value)) {
18517 option = PRI_DATE_TIME_SEND_NO;
18518 } else if (!strcasecmp(value, "date")) {
18519 option = PRI_DATE_TIME_SEND_DATE;
18520 } else if (!strcasecmp(value, "date_hh")) {
18521 option = PRI_DATE_TIME_SEND_DATE_HH;
18522 } else if (!strcasecmp(value, "date_hhmm")) {
18523 option = PRI_DATE_TIME_SEND_DATE_HHMM;
18524 } else if (!strcasecmp(value, "date_hhmmss")) {
18525 option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
18526 }
18527
18528 return option;
18529}
18530#endif /* defined(HAVE_PRI_DATETIME_SEND) */
18531#endif /* defined(HAVE_PRI) */
18532
18533/*! process_dahdi() - ignore keyword 'channel' and similar */
18534#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18535/*! process_dahdi() - No warnings on non-existing configuration keywords */
18536#define PROC_DAHDI_OPT_NOWARN (1 << 1)
18537
18538static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
18539{
18540 int count_pattern = 0;
18541 int norval = 0;
18542 char *temp = NULL;
18543
18544 for (; ;) {
18545 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18546 if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
18547 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18548 break;
18549 }
18550
18551 busy_cadence->pattern[count_pattern] = norval;
18552
18553 count_pattern++;
18554 if (count_pattern == 4) {
18555 break;
18556 }
18557
18558 temp = strchr(v->value, ',');
18559 if (temp == NULL) {
18560 break;
18561 }
18562 v->value = temp + 1;
18563 }
18564 busy_cadence->length = count_pattern;
18565
18566 if (count_pattern % 2 != 0) {
18567 /* The pattern length must be divisible by two */
18568 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18569 }
18570
18571}
18572
18573static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
18574{
18575 struct dahdi_pvt *tmp;
18576 int y;
18577 struct ast_variable *dahdichan = NULL;
18578
18579 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18581
18582 for (; v; v = v->next) {
18584 continue;
18585
18586 /* Create the interface list */
18587 if (!strcasecmp(v->name, "channel") || !strcasecmp(v->name, "channels")) {
18589 ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
18590 continue;
18591 }
18592 if (build_channels(confp, v->value, reload, v->lineno)) {
18593 if (confp->ignore_failed_channels) {
18594 ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
18595 continue;
18596 } else {
18597 return -1;
18598 }
18599 }
18600 ast_debug(1, "Channel '%s' configured.\n", v->value);
18601 } else if (!strcasecmp(v->name, "ignore_failed_channels")) {
18603 } else if (!strcasecmp(v->name, "buffers")) {
18604 if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
18605 ast_log(LOG_WARNING, "Using default buffer policy.\n");
18606 confp->chan.buf_no = numbufs;
18607 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
18608 }
18609 } else if (!strcasecmp(v->name, "faxbuffers")) {
18610 if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
18611 confp->chan.usefaxbuffers = 1;
18612 }
18613 } else if (!strcasecmp(v->name, "dahdichan")) {
18614 /* Only process the last dahdichan value. */
18615 dahdichan = v;
18616 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
18618 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
18620 } else if (!strcasecmp(v->name, "dring1context")) {
18622 } else if (!strcasecmp(v->name, "dring2context")) {
18624 } else if (!strcasecmp(v->name, "dring3context")) {
18626 } else if (!strcasecmp(v->name, "dring1range")) {
18627 confp->chan.drings.ringnum[0].range = atoi(v->value);
18628 } else if (!strcasecmp(v->name, "dring2range")) {
18629 confp->chan.drings.ringnum[1].range = atoi(v->value);
18630 } else if (!strcasecmp(v->name, "dring3range")) {
18631 confp->chan.drings.ringnum[2].range = atoi(v->value);
18632 } else if (!strcasecmp(v->name, "dring1")) {
18633 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]);
18634 } else if (!strcasecmp(v->name, "dring2")) {
18635 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]);
18636 } else if (!strcasecmp(v->name, "dring3")) {
18637 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]);
18638 } else if (!strcasecmp(v->name, "usecallerid")) {
18639 confp->chan.use_callerid = ast_true(v->value);
18640 } else if (!strcasecmp(v->name, "cidsignalling")) {
18641 if (!strcasecmp(v->value, "bell"))
18643 else if (!strcasecmp(v->value, "v23"))
18645 else if (!strcasecmp(v->value, "dtmf"))
18647 else if (!strcasecmp(v->value, "smdi"))
18649 else if (!strcasecmp(v->value, "v23_jp"))
18651 else if (ast_true(v->value))
18653 } else if (!strcasecmp(v->name, "cidstart")) {
18654 if (!strcasecmp(v->value, "ring"))
18655 confp->chan.cid_start = CID_START_RING;
18656 else if (!strcasecmp(v->value, "polarity_in"))
18658 else if (!strcasecmp(v->value, "polarity"))
18660 else if (!strcasecmp(v->value, "dtmf"))
18662 else if (ast_true(v->value))
18663 confp->chan.cid_start = CID_START_RING;
18664 } else if (!strcasecmp(v->name, "threewaycalling")) {
18665 confp->chan.threewaycalling = ast_true(v->value);
18666 } else if (!strcasecmp(v->name, "threewaysilenthold")) {
18668 } else if (!strcasecmp(v->name, "cancallforward")) {
18669 confp->chan.cancallforward = ast_true(v->value);
18670 } else if (!strcasecmp(v->name, "relaxdtmf")) {
18671 if (ast_true(v->value))
18673 else
18674 confp->chan.dtmfrelax = 0;
18675 } else if (!strcasecmp(v->name, "mailbox")) {
18676 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
18677 } else if (!strcasecmp(v->name, "description")) {
18678 ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
18679 } else if (!strcasecmp(v->name, "hasvoicemail")) {
18680 if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
18681 /*
18682 * hasvoicemail is a users.conf legacy voicemail enable method.
18683 * hasvoicemail is only going to work for app_voicemail mailboxes.
18684 */
18685 if (strchr(cat, '@')) {
18686 ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
18687 } else {
18688 snprintf(confp->chan.mailbox, sizeof(confp->chan.mailbox),
18689 "%s@default", cat);
18690 }
18691 }
18692 } else if (!strcasecmp(v->name, "adsi")) {
18693 confp->chan.adsi = ast_true(v->value);
18694 } else if (!strcasecmp(v->name, "usesmdi")) {
18695 confp->chan.use_smdi = ast_true(v->value);
18696 } else if (!strcasecmp(v->name, "smdiport")) {
18697 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
18698 } else if (!strcasecmp(v->name, "transfer")) {
18699 confp->chan.transfer = ast_true(v->value);
18700 } else if (!strcasecmp(v->name, "canpark")) {
18701 confp->chan.canpark = ast_true(v->value);
18702 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
18703 confp->chan.echocanbridged = ast_true(v->value);
18704 } else if (!strcasecmp(v->name, "busydetect")) {
18705 confp->chan.busydetect = ast_true(v->value);
18706 } else if (!strcasecmp(v->name, "busycount")) {
18707 confp->chan.busycount = atoi(v->value);
18708 } else if (!strcasecmp(v->name, "busypattern")) {
18710 } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18712 } else if (!strcasecmp(v->name, "lastnumredial")) {
18713 confp->chan.lastnumredial = ast_true(v->value);
18714 } else if (!strcasecmp(v->name, "callprogress")) {
18715 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
18716 if (ast_true(v->value))
18718 } else if (!strcasecmp(v->name, "waitfordialtone")) {
18719 confp->chan.waitfordialtone = atoi(v->value);
18720 } else if (!strcasecmp(v->name, "dialtone_detect")) {
18721 if (!strcasecmp(v->value, "always")) {
18722 confp->chan.dialtone_detect = -1;
18723 } else if (ast_true(v->value)) {
18725 } else if (ast_false(v->value)) {
18726 confp->chan.dialtone_detect = 0;
18727 } else {
18728 confp->chan.dialtone_detect = ast_strlen_zero(v->value) ? 0 : (8 * atoi(v->value)) / READ_SIZE;
18729 }
18730 } else if (!strcasecmp(v->name, "faxdetect")) {
18731 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
18732 if (!strcasecmp(v->value, "incoming")) {
18734 } else if (!strcasecmp(v->value, "outgoing")) {
18736 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
18738 } else if (!strcasecmp(v->name, "faxdetect_timeout")) {
18739 if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) {
18740 confp->chan.faxdetect_timeout = 0;
18741 }
18742 } else if (!strcasecmp(v->name, "firstdigit_timeout")) {
18743 if (sscanf(v->value, "%30d", &confp->chan.firstdigit_timeout) != 1
18744 || confp->chan.firstdigit_timeout <= 0) {
18746 }
18747 } else if (!strcasecmp(v->name, "interdigit_timeout")) {
18748 if (sscanf(v->value, "%30d", &confp->chan.interdigit_timeout) != 1
18749 || confp->chan.interdigit_timeout <= 0) {
18751 }
18752 } else if (!strcasecmp(v->name, "matchdigit_timeout")) {
18753 if (sscanf(v->value, "%30d", &confp->chan.matchdigit_timeout) != 1
18754 || confp->chan.matchdigit_timeout <= 0) {
18756 }
18757 } else if (!strcasecmp(v->name, "echocancel")) {
18758 process_echocancel(confp, v->value, v->lineno);
18759 } else if (!strcasecmp(v->name, "echotraining")) {
18760 if (sscanf(v->value, "%30d", &y) == 1) {
18761 if ((y < 10) || (y > 4000)) {
18762 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
18763 } else {
18764 confp->chan.echotraining = y;
18765 }
18766 } else if (ast_true(v->value)) {
18767 confp->chan.echotraining = 400;
18768 } else
18769 confp->chan.echotraining = 0;
18770 } else if (!strcasecmp(v->name, "hidecallerid")) {
18771 confp->chan.hidecallerid = ast_true(v->value);
18772 } else if (!strcasecmp(v->name, "hidecalleridname")) {
18773 confp->chan.hidecalleridname = ast_true(v->value);
18774 } else if (!strcasecmp(v->name, "pulsedial")) {
18775 confp->chan.pulse = ast_true(v->value);
18776 } else if (!strcasecmp(v->name, "callreturn")) {
18777 confp->chan.callreturn = ast_true(v->value);
18778 } else if (!strcasecmp(v->name, "callwaiting")) {
18779 confp->chan.callwaiting = ast_true(v->value);
18780 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
18782 } else if (!strcasecmp(v->name, "callwaitingdeluxe")) {
18783 confp->chan.callwaitingdeluxe = ast_true(v->value);
18784 } else if (!strcasecmp(v->name, "context")) {
18785 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
18786 } else if (!strcasecmp(v->name, "language")) {
18787 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
18788 } else if (!strcasecmp(v->name, "progzone")) {
18789 ast_copy_string(progzone, v->value, sizeof(progzone));
18790 } else if (!strcasecmp(v->name, "mohinterpret")
18791 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
18792 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
18793 } else if (!strcasecmp(v->name, "mohsuggest")) {
18794 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
18795 } else if (!strcasecmp(v->name, "parkinglot")) {
18796 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
18797 } else if (!strcasecmp(v->name, "stripmsd")) {
18798 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
18799 confp->chan.stripmsd = atoi(v->value);
18800 } else if (!strcasecmp(v->name, "jitterbuffers")) {
18801 numbufs = atoi(v->value);
18802 } else if (!strcasecmp(v->name, "group")) {
18803 confp->chan.group = ast_get_group(v->value);
18804 } else if (!strcasecmp(v->name, "callgroup")) {
18805 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18806 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
18807 }
18808 if (!strcasecmp(v->value, "none"))
18809 confp->chan.callgroup = 0;
18810 else
18811 confp->chan.callgroup = ast_get_group(v->value);
18812 } else if (!strcasecmp(v->name, "pickupgroup")) {
18813 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18814 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
18815 }
18816 if (!strcasecmp(v->value, "none"))
18817 confp->chan.pickupgroup = 0;
18818 else
18819 confp->chan.pickupgroup = ast_get_group(v->value);
18820 } else if (!strcasecmp(v->name, "namedcallgroup")) {
18821 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18822 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
18823 }
18825 } else if (!strcasecmp(v->name, "namedpickupgroup")) {
18826 if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
18827 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
18828 }
18830 } else if (!strcasecmp(v->name, "setvar")) {
18831 if (v->value) {
18832 char *varval = NULL;
18833 struct ast_variable *tmpvar;
18834 char varname[strlen(v->value) + 1];
18835 strcpy(varname, v->value); /* safe */
18836 if ((varval = strchr(varname, '='))) {
18837 *varval++ = '\0';
18838 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
18839 if (ast_variable_list_replace(&confp->chan.vars, tmpvar)) {
18840 tmpvar->next = confp->chan.vars;
18841 confp->chan.vars = tmpvar;
18842 }
18843 }
18844 }
18845 }
18846 } else if (!strcasecmp(v->name, "immediate")) {
18847 confp->chan.immediate = ast_true(v->value);
18848 } else if (!strcasecmp(v->name, "immediatering")) {
18849 confp->chan.immediatering = ast_true(v->value);
18850 } else if (!strcasecmp(v->name, "transfertobusy")) {
18851 confp->chan.transfertobusy = ast_true(v->value);
18852 } else if (!strcasecmp(v->name, "dialmode")) {
18853 if (!strcasecmp(v->value, "pulse")) {
18855 } else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
18857 } else if (!strcasecmp(v->value, "none")) {
18859 } else {
18861 }
18862 } else if (!strcasecmp(v->name, "mwimonitor")) {
18863 confp->chan.mwimonitor_neon = 0;
18864 confp->chan.mwimonitor_fsk = 0;
18865 confp->chan.mwimonitor_rpas = 0;
18866 if (strcasestr(v->value, "fsk")) {
18867 confp->chan.mwimonitor_fsk = 1;
18868 }
18869 if (strcasestr(v->value, "rpas")) {
18870 confp->chan.mwimonitor_rpas = 1;
18871 }
18872 if (strcasestr(v->value, "neon")) {
18873 confp->chan.mwimonitor_neon = 1;
18874 }
18875 /* If set to true or yes, assume that simple fsk is desired */
18876 if (ast_true(v->value)) {
18877 confp->chan.mwimonitor_fsk = 1;
18878 }
18879 } else if (!strcasecmp(v->name, "hwrxgain")) {
18880 confp->chan.hwrxgain_enabled = 0;
18881 if (strcasecmp(v->value, "disabled")) {
18882 if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
18883 confp->chan.hwrxgain_enabled = 1;
18884 } else {
18885 ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
18886 }
18887 }
18888 } else if (!strcasecmp(v->name, "hwtxgain")) {
18889 confp->chan.hwtxgain_enabled = 0;
18890 if (strcasecmp(v->value, "disabled")) {
18891 if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
18892 confp->chan.hwtxgain_enabled = 1;
18893 } else {
18894 ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
18895 }
18896 }
18897 } else if (!strcasecmp(v->name, "cid_rxgain")) {
18898 if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
18899 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
18900 }
18901 } else if (!strcasecmp(v->name, "rxgain")) {
18902 if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
18903 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
18904 }
18905 } else if (!strcasecmp(v->name, "txgain")) {
18906 if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
18907 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
18908 }
18909 } else if (!strcasecmp(v->name, "txdrc")) {
18910 if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) {
18911 ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value);
18912 }
18913 } else if (!strcasecmp(v->name, "rxdrc")) {
18914 if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) {
18915 ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value);
18916 }
18917 } else if (!strcasecmp(v->name, "tonezone")) {
18918 if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
18919 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
18920 }
18921 } else if (!strcasecmp(v->name, "callerid")) {
18922 if (!strcasecmp(v->value, "asreceived")) {
18923 confp->chan.cid_num[0] = '\0';
18924 confp->chan.cid_name[0] = '\0';
18925 } else {
18926 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
18927 }
18928 } else if (!strcasecmp(v->name, "fullname")) {
18929 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
18930 } else if (!strcasecmp(v->name, "cid_number")) {
18931 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
18932 } else if (!strcasecmp(v->name, "cid_tag")) {
18933 ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
18934 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
18935 confp->chan.dahditrcallerid = ast_true(v->value);
18936 } else if (!strcasecmp(v->name, "restrictcid")) {
18937 confp->chan.restrictcid = ast_true(v->value);
18938 } else if (!strcasecmp(v->name, "usecallingpres")) {
18939 confp->chan.use_callingpres = ast_true(v->value);
18940 } else if (!strcasecmp(v->name, "accountcode")) {
18941 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
18942 } else if (!strcasecmp(v->name, "amaflags")) {
18944 if (y < 0)
18945 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
18946 else
18947 confp->chan.amaflags = y;
18948 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
18949 confp->chan.polarityonanswerdelay = atoi(v->value);
18950 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
18952 } else if (!strcasecmp(v->name, "ani_info_digits")) {
18953 confp->chan.ani_info_digits = atoi(v->value);
18954 } else if (!strcasecmp(v->name, "ani_wink_time")) {
18955 confp->chan.ani_wink_time = atoi(v->value);
18956 } else if (!strcasecmp(v->name, "ani_timeout")) {
18957 confp->chan.ani_timeout = atoi(v->value);
18958 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
18960 } else if (!strcasecmp(v->name, "autoreoriginate")) {
18961 confp->chan.reoriginate = ast_true(v->value);
18962 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
18963 confp->chan.sendcalleridafter = atoi(v->value);
18964 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
18966 } else if (ast_cc_is_config_param(v->name)) {
18967 ast_cc_set_param(confp->chan.cc_params, v->name, v->value);
18968 } else if (!strcasecmp(v->name, "mwisendtype")) {
18969#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
18970 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
18971 mwisend_rpas = 1;
18972 } else {
18973 mwisend_rpas = 0;
18974 }
18975#else
18976 /* Default is fsk, to turn it off you must specify nofsk */
18977 memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
18978 if (strcasestr(v->value, "nofsk")) { /* NoFSK */
18979 confp->chan.mwisend_fsk = 0;
18980 } else { /* Default FSK */
18981 confp->chan.mwisend_fsk = 1;
18982 }
18983 if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
18984 confp->chan.mwisend_rpas = 1;
18985 } else {
18986 confp->chan.mwisend_rpas = 0;
18987 }
18988 if (strcasestr(v->value, "lrev")) { /* Line Reversal */
18989 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
18990 }
18991 if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
18992 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
18993 }
18994 if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
18995 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
18996 }
18997#endif
18998 } else if (reload != 1) {
18999 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
19000 int orig_radio = confp->chan.radio;
19001 int orig_outsigmod = confp->chan.outsigmod;
19002 int orig_auto = confp->is_sig_auto;
19003
19004 confp->chan.radio = 0;
19005 confp->chan.outsigmod = -1;
19006 confp->is_sig_auto = 0;
19007 if (!strcasecmp(v->value, "em")) {
19008 confp->chan.sig = SIG_EM;
19009 } else if (!strcasecmp(v->value, "em_e1")) {
19010 confp->chan.sig = SIG_EM_E1;
19011 } else if (!strcasecmp(v->value, "em_w")) {
19012 confp->chan.sig = SIG_EMWINK;
19013 } else if (!strcasecmp(v->value, "fxs_ls")) {
19014 confp->chan.sig = SIG_FXSLS;
19015 } else if (!strcasecmp(v->value, "fxs_gs")) {
19016 confp->chan.sig = SIG_FXSGS;
19017 } else if (!strcasecmp(v->value, "fxs_ks")) {
19018 confp->chan.sig = SIG_FXSKS;
19019 } else if (!strcasecmp(v->value, "fxo_ls")) {
19020 confp->chan.sig = SIG_FXOLS;
19021 } else if (!strcasecmp(v->value, "fxo_gs")) {
19022 confp->chan.sig = SIG_FXOGS;
19023 } else if (!strcasecmp(v->value, "fxo_ks")) {
19024 confp->chan.sig = SIG_FXOKS;
19025 } else if (!strcasecmp(v->value, "fxs_rx")) {
19026 confp->chan.sig = SIG_FXSKS;
19027 confp->chan.radio = 1;
19028 } else if (!strcasecmp(v->value, "fxo_rx")) {
19029 confp->chan.sig = SIG_FXOLS;
19030 confp->chan.radio = 1;
19031 } else if (!strcasecmp(v->value, "fxs_tx")) {
19032 confp->chan.sig = SIG_FXSLS;
19033 confp->chan.radio = 1;
19034 } else if (!strcasecmp(v->value, "fxo_tx")) {
19035 confp->chan.sig = SIG_FXOGS;
19036 confp->chan.radio = 1;
19037 } else if (!strcasecmp(v->value, "em_rx")) {
19038 confp->chan.sig = SIG_EM;
19039 confp->chan.radio = 1;
19040 } else if (!strcasecmp(v->value, "em_tx")) {
19041 confp->chan.sig = SIG_EM;
19042 confp->chan.radio = 1;
19043 } else if (!strcasecmp(v->value, "em_rxtx")) {
19044 confp->chan.sig = SIG_EM;
19045 confp->chan.radio = 2;
19046 } else if (!strcasecmp(v->value, "em_txrx")) {
19047 confp->chan.sig = SIG_EM;
19048 confp->chan.radio = 2;
19049 } else if (!strcasecmp(v->value, "sf")) {
19050 confp->chan.sig = SIG_SF;
19051 } else if (!strcasecmp(v->value, "sf_w")) {
19052 confp->chan.sig = SIG_SFWINK;
19053 } else if (!strcasecmp(v->value, "sf_featd")) {
19054 confp->chan.sig = SIG_FEATD;
19055 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19056 confp->chan.sig = SIG_FEATDMF;
19057 } else if (!strcasecmp(v->value, "sf_featb")) {
19058 confp->chan.sig = SIG_SF_FEATB;
19059 } else if (!strcasecmp(v->value, "sf")) {
19060 confp->chan.sig = SIG_SF;
19061 } else if (!strcasecmp(v->value, "sf_rx")) {
19062 confp->chan.sig = SIG_SF;
19063 confp->chan.radio = 1;
19064 } else if (!strcasecmp(v->value, "sf_tx")) {
19065 confp->chan.sig = SIG_SF;
19066 confp->chan.radio = 1;
19067 } else if (!strcasecmp(v->value, "sf_rxtx")) {
19068 confp->chan.sig = SIG_SF;
19069 confp->chan.radio = 2;
19070 } else if (!strcasecmp(v->value, "sf_txrx")) {
19071 confp->chan.sig = SIG_SF;
19072 confp->chan.radio = 2;
19073 } else if (!strcasecmp(v->value, "featd")) {
19074 confp->chan.sig = SIG_FEATD;
19075 } else if (!strcasecmp(v->value, "featdmf")) {
19076 confp->chan.sig = SIG_FEATDMF;
19077 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19078 confp->chan.sig = SIG_FEATDMF_TA;
19079 } else if (!strcasecmp(v->value, "e911")) {
19080 confp->chan.sig = SIG_E911;
19081 } else if (!strcasecmp(v->value, "fgccama")) {
19082 confp->chan.sig = SIG_FGC_CAMA;
19083 } else if (!strcasecmp(v->value, "fgccamamf")) {
19084 confp->chan.sig = SIG_FGC_CAMAMF;
19085 } else if (!strcasecmp(v->value, "featb")) {
19086 confp->chan.sig = SIG_FEATB;
19087#ifdef HAVE_PRI
19088 } else if (!strcasecmp(v->value, "pri_net")) {
19089 confp->chan.sig = SIG_PRI;
19090 confp->pri.pri.nodetype = PRI_NETWORK;
19091 } else if (!strcasecmp(v->value, "pri_cpe")) {
19092 confp->chan.sig = SIG_PRI;
19093 confp->pri.pri.nodetype = PRI_CPE;
19094 } else if (!strcasecmp(v->value, "bri_cpe")) {
19095 confp->chan.sig = SIG_BRI;
19096 confp->pri.pri.nodetype = PRI_CPE;
19097 } else if (!strcasecmp(v->value, "bri_net")) {
19098 confp->chan.sig = SIG_BRI;
19099 confp->pri.pri.nodetype = PRI_NETWORK;
19100 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
19101 confp->chan.sig = SIG_BRI_PTMP;
19102 confp->pri.pri.nodetype = PRI_CPE;
19103 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
19104#if defined(HAVE_PRI_CALL_HOLD)
19105 confp->chan.sig = SIG_BRI_PTMP;
19106 confp->pri.pri.nodetype = PRI_NETWORK;
19107#else
19108 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
19109#endif /* !defined(HAVE_PRI_CALL_HOLD) */
19110#endif
19111#if defined(HAVE_SS7)
19112 } else if (!strcasecmp(v->value, "ss7")) {
19113 confp->chan.sig = SIG_SS7;
19114#endif /* defined(HAVE_SS7) */
19115#ifdef HAVE_OPENR2
19116 } else if (!strcasecmp(v->value, "mfcr2")) {
19117 confp->chan.sig = SIG_MFCR2;
19118#endif
19119 } else if (!strcasecmp(v->value, "auto")) {
19120 confp->is_sig_auto = 1;
19121 } else {
19122 confp->chan.outsigmod = orig_outsigmod;
19123 confp->chan.radio = orig_radio;
19124 confp->is_sig_auto = orig_auto;
19125 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19126 }
19127 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
19128 if (!strcasecmp(v->value, "em")) {
19129 confp->chan.outsigmod = SIG_EM;
19130 } else if (!strcasecmp(v->value, "em_e1")) {
19131 confp->chan.outsigmod = SIG_EM_E1;
19132 } else if (!strcasecmp(v->value, "em_w")) {
19133 confp->chan.outsigmod = SIG_EMWINK;
19134 } else if (!strcasecmp(v->value, "sf")) {
19135 confp->chan.outsigmod = SIG_SF;
19136 } else if (!strcasecmp(v->value, "sf_w")) {
19137 confp->chan.outsigmod = SIG_SFWINK;
19138 } else if (!strcasecmp(v->value, "sf_featd")) {
19139 confp->chan.outsigmod = SIG_FEATD;
19140 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19141 confp->chan.outsigmod = SIG_FEATDMF;
19142 } else if (!strcasecmp(v->value, "sf_featb")) {
19143 confp->chan.outsigmod = SIG_SF_FEATB;
19144 } else if (!strcasecmp(v->value, "sf")) {
19145 confp->chan.outsigmod = SIG_SF;
19146 } else if (!strcasecmp(v->value, "featd")) {
19147 confp->chan.outsigmod = SIG_FEATD;
19148 } else if (!strcasecmp(v->value, "featdmf")) {
19149 confp->chan.outsigmod = SIG_FEATDMF;
19150 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19151 confp->chan.outsigmod = SIG_FEATDMF_TA;
19152 } else if (!strcasecmp(v->value, "e911")) {
19153 confp->chan.outsigmod = SIG_E911;
19154 } else if (!strcasecmp(v->value, "fgccama")) {
19155 confp->chan.outsigmod = SIG_FGC_CAMA;
19156 } else if (!strcasecmp(v->value, "fgccamamf")) {
19157 confp->chan.outsigmod = SIG_FGC_CAMAMF;
19158 } else if (!strcasecmp(v->value, "featb")) {
19159 confp->chan.outsigmod = SIG_FEATB;
19160 } else {
19161 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19162 }
19163#ifdef HAVE_PRI
19164 } else if (!strcasecmp(v->name, "pridialplan")) {
19165 if (!strcasecmp(v->value, "national")) {
19166 confp->pri.pri.dialplan = PRI_NATIONAL_ISDN + 1;
19167 } else if (!strcasecmp(v->value, "unknown")) {
19168 confp->pri.pri.dialplan = PRI_UNKNOWN + 1;
19169 } else if (!strcasecmp(v->value, "private")) {
19170 confp->pri.pri.dialplan = PRI_PRIVATE + 1;
19171 } else if (!strcasecmp(v->value, "international")) {
19172 confp->pri.pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
19173 } else if (!strcasecmp(v->value, "local")) {
19174 confp->pri.pri.dialplan = PRI_LOCAL_ISDN + 1;
19175 } else if (!strcasecmp(v->value, "dynamic")) {
19176 confp->pri.pri.dialplan = -1;
19177 } else if (!strcasecmp(v->value, "redundant")) {
19178 confp->pri.pri.dialplan = -2;
19179 } else {
19180 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
19181 }
19182 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
19183 if (!strcasecmp(v->value, "national")) {
19184 confp->pri.pri.localdialplan = PRI_NATIONAL_ISDN + 1;
19185 } else if (!strcasecmp(v->value, "unknown")) {
19186 confp->pri.pri.localdialplan = PRI_UNKNOWN + 1;
19187 } else if (!strcasecmp(v->value, "private")) {
19188 confp->pri.pri.localdialplan = PRI_PRIVATE + 1;
19189 } else if (!strcasecmp(v->value, "international")) {
19190 confp->pri.pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
19191 } else if (!strcasecmp(v->value, "local")) {
19192 confp->pri.pri.localdialplan = PRI_LOCAL_ISDN + 1;
19193 } else if (!strcasecmp(v->value, "from_channel")) {
19194 confp->pri.pri.localdialplan = 0;
19195 } else if (!strcasecmp(v->value, "dynamic")) {
19196 confp->pri.pri.localdialplan = -1;
19197 } else if (!strcasecmp(v->value, "redundant")) {
19198 confp->pri.pri.localdialplan = -2;
19199 } else {
19200 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
19201 }
19202 } else if (!strcasecmp(v->name, "pricpndialplan")) {
19203 if (!strcasecmp(v->value, "national")) {
19204 confp->pri.pri.cpndialplan = PRI_NATIONAL_ISDN + 1;
19205 } else if (!strcasecmp(v->value, "unknown")) {
19206 confp->pri.pri.cpndialplan = PRI_UNKNOWN + 1;
19207 } else if (!strcasecmp(v->value, "private")) {
19208 confp->pri.pri.cpndialplan = PRI_PRIVATE + 1;
19209 } else if (!strcasecmp(v->value, "international")) {
19210 confp->pri.pri.cpndialplan = PRI_INTERNATIONAL_ISDN + 1;
19211 } else if (!strcasecmp(v->value, "local")) {
19212 confp->pri.pri.cpndialplan = PRI_LOCAL_ISDN + 1;
19213 } else if (!strcasecmp(v->value, "from_channel")) {
19214 confp->pri.pri.cpndialplan = 0;
19215 } else if (!strcasecmp(v->value, "dynamic")) {
19216 confp->pri.pri.cpndialplan = -1;
19217 } else if (!strcasecmp(v->value, "redundant")) {
19218 confp->pri.pri.cpndialplan = -2;
19219 } else {
19220 ast_log(LOG_WARNING, "Unknown PRI cpndialplan '%s' at line %d.\n", v->value, v->lineno);
19221 }
19222 } else if (!strcasecmp(v->name, "switchtype")) {
19223 if (!strcasecmp(v->value, "national"))
19224 confp->pri.pri.switchtype = PRI_SWITCH_NI2;
19225 else if (!strcasecmp(v->value, "ni1"))
19226 confp->pri.pri.switchtype = PRI_SWITCH_NI1;
19227 else if (!strcasecmp(v->value, "dms100"))
19228 confp->pri.pri.switchtype = PRI_SWITCH_DMS100;
19229 else if (!strcasecmp(v->value, "4ess"))
19230 confp->pri.pri.switchtype = PRI_SWITCH_ATT4ESS;
19231 else if (!strcasecmp(v->value, "5ess"))
19232 confp->pri.pri.switchtype = PRI_SWITCH_LUCENT5E;
19233 else if (!strcasecmp(v->value, "euroisdn"))
19234 confp->pri.pri.switchtype = PRI_SWITCH_EUROISDN_E1;
19235 else if (!strcasecmp(v->value, "qsig"))
19236 confp->pri.pri.switchtype = PRI_SWITCH_QSIG;
19237 else {
19238 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
19239 return -1;
19240 }
19241 } else if (!strcasecmp(v->name, "msn")) {
19242 ast_copy_string(confp->pri.pri.msn_list, v->value,
19243 sizeof(confp->pri.pri.msn_list));
19244 } else if (!strcasecmp(v->name, "nsf")) {
19245 if (!strcasecmp(v->value, "sdn"))
19246 confp->pri.pri.nsf = PRI_NSF_SDN;
19247 else if (!strcasecmp(v->value, "megacom"))
19248 confp->pri.pri.nsf = PRI_NSF_MEGACOM;
19249 else if (!strcasecmp(v->value, "tollfreemegacom"))
19250 confp->pri.pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
19251 else if (!strcasecmp(v->value, "accunet"))
19252 confp->pri.pri.nsf = PRI_NSF_ACCUNET;
19253 else if (!strcasecmp(v->value, "none"))
19254 confp->pri.pri.nsf = PRI_NSF_NONE;
19255 else {
19256 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
19257 confp->pri.pri.nsf = PRI_NSF_NONE;
19258 }
19259 } else if (!strcasecmp(v->name, "priindication")) {
19260 if (!strcasecmp(v->value, "outofband"))
19261 confp->chan.priindication_oob = 1;
19262 else if (!strcasecmp(v->value, "inband"))
19263 confp->chan.priindication_oob = 0;
19264 else
19265 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
19266 v->value, v->lineno);
19267 } else if (!strcasecmp(v->name, "priexclusive")) {
19268 confp->chan.priexclusive = ast_true(v->value);
19269 } else if (!strcasecmp(v->name, "internationalprefix")) {
19270 ast_copy_string(confp->pri.pri.internationalprefix, v->value, sizeof(confp->pri.pri.internationalprefix));
19271 } else if (!strcasecmp(v->name, "nationalprefix")) {
19272 ast_copy_string(confp->pri.pri.nationalprefix, v->value, sizeof(confp->pri.pri.nationalprefix));
19273 } else if (!strcasecmp(v->name, "localprefix")) {
19274 ast_copy_string(confp->pri.pri.localprefix, v->value, sizeof(confp->pri.pri.localprefix));
19275 } else if (!strcasecmp(v->name, "privateprefix")) {
19276 ast_copy_string(confp->pri.pri.privateprefix, v->value, sizeof(confp->pri.pri.privateprefix));
19277 } else if (!strcasecmp(v->name, "unknownprefix")) {
19278 ast_copy_string(confp->pri.pri.unknownprefix, v->value, sizeof(confp->pri.pri.unknownprefix));
19279 } else if (!strcasecmp(v->name, "resetinterval")) {
19280 if (!strcasecmp(v->value, "never"))
19281 confp->pri.pri.resetinterval = -1;
19282 else if (atoi(v->value) >= 60)
19283 confp->pri.pri.resetinterval = atoi(v->value);
19284 else
19285 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19286 v->value, v->lineno);
19287 } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
19288 confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
19289 } else if (!strcasecmp(v->name, "minunused")) {
19290 confp->pri.pri.minunused = atoi(v->value);
19291 } else if (!strcasecmp(v->name, "minidle")) {
19292 confp->pri.pri.minidle = atoi(v->value);
19293 } else if (!strcasecmp(v->name, "idleext")) {
19294 ast_copy_string(confp->pri.pri.idleext, v->value, sizeof(confp->pri.pri.idleext));
19295 } else if (!strcasecmp(v->name, "idledial")) {
19296 ast_copy_string(confp->pri.pri.idledial, v->value, sizeof(confp->pri.pri.idledial));
19297 } else if (!strcasecmp(v->name, "overlapdial")) {
19298 if (ast_true(v->value)) {
19299 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19300 } else if (!strcasecmp(v->value, "incoming")) {
19301 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
19302 } else if (!strcasecmp(v->value, "outgoing")) {
19303 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
19304 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
19305 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19306 } else {
19307 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
19308 }
19309#ifdef HAVE_PRI_PROG_W_CAUSE
19310 } else if (!strcasecmp(v->name, "qsigchannelmapping")) {
19311 if (!strcasecmp(v->value, "logical")) {
19312 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL;
19313 } else if (!strcasecmp(v->value, "physical")) {
19314 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19315 } else {
19316 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19317 }
19318#endif
19319 } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
19320 confp->pri.pri.discardremoteholdretrieval = ast_true(v->value);
19321#if defined(HAVE_PRI_SERVICE_MESSAGES)
19322 } else if (!strcasecmp(v->name, "service_message_support")) {
19323 /* assuming switchtype for this channel group has been configured already */
19324 if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
19325 || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
19326 || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
19327 confp->pri.pri.enable_service_message_support = 1;
19328 } else {
19329 confp->pri.pri.enable_service_message_support = 0;
19330 }
19331#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19332#ifdef HAVE_PRI_INBANDDISCONNECT
19333 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
19334 confp->pri.pri.inbanddisconnect = ast_true(v->value);
19335#endif
19336 } else if (!strcasecmp(v->name, "pritimer")) {
19337#ifdef PRI_GETSET_TIMERS
19338 char tmp[20];
19339 char *timerc;
19340 char *c;
19341 int timer;
19342 int timeridx;
19343
19344 ast_copy_string(tmp, v->value, sizeof(tmp));
19345 c = tmp;
19346 timerc = strsep(&c, ",");
19347 if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
19348 timeridx = pri_timer2idx(timerc);
19349 timer = atoi(c);
19350 if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
19352 "'%s' is not a valid ISDN timer at line %d.\n", timerc,
19353 v->lineno);
19354 } else if (!timer) {
19356 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19357 c, timerc, v->lineno);
19358 } else {
19359 confp->pri.pri.pritimers[timeridx] = timer;
19360 }
19361 } else {
19363 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19364 v->value, v->lineno);
19365 }
19366#endif /* PRI_GETSET_TIMERS */
19367 } else if (!strcasecmp(v->name, "facilityenable")) {
19368 confp->pri.pri.facilityenable = ast_true(v->value);
19369#if defined(HAVE_PRI_AOC_EVENTS)
19370 } else if (!strcasecmp(v->name, "aoc_enable")) {
19371 confp->pri.pri.aoc_passthrough_flag = 0;
19372 if (strchr(v->value, 's') || strchr(v->value, 'S')) {
19373 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
19374 }
19375 if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
19376 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
19377 }
19378 if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
19379 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
19380 }
19381 } else if (!strcasecmp(v->name, "aoce_delayhangup")) {
19382 confp->pri.pri.aoce_delayhangup = ast_true(v->value);
19383#endif /* defined(HAVE_PRI_AOC_EVENTS) */
19384#if defined(HAVE_PRI_CALL_HOLD)
19385 } else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
19386 confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
19387#endif /* defined(HAVE_PRI_CALL_HOLD) */
19388 } else if (!strcasecmp(v->name, "moh_signaling")
19389 || !strcasecmp(v->name, "moh_signalling")) {
19390 if (!strcasecmp(v->value, "moh")) {
19391 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19392 } else if (!strcasecmp(v->value, "notify")) {
19393 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_NOTIFY;
19394#if defined(HAVE_PRI_CALL_HOLD)
19395 } else if (!strcasecmp(v->value, "hold")) {
19396 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_HOLD;
19397#endif /* defined(HAVE_PRI_CALL_HOLD) */
19398 } else {
19399 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19400 }
19401#if defined(HAVE_PRI_CCSS)
19402 } else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
19403 if (!strcasecmp(v->value, "global")) {
19404 confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
19405 } else if (!strcasecmp(v->value, "specific")) {
19406 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19407 } else {
19408 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19409 }
19410 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
19411 if (!strcasecmp(v->value, "release")) {
19412 confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
19413 } else if (!strcasecmp(v->value, "retain")) {
19414 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19415 } else if (!strcasecmp(v->value, "do_not_care")) {
19416 confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
19417 } else {
19418 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19419 }
19420 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
19421 if (!strcasecmp(v->value, "release")) {
19422 confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
19423 } else if (!strcasecmp(v->value, "retain")) {
19424 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19425 } else {
19426 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19427 }
19428#endif /* defined(HAVE_PRI_CCSS) */
19429#if defined(HAVE_PRI_CALL_WAITING)
19430 } else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
19431 confp->pri.pri.max_call_waiting_calls = atoi(v->value);
19432 if (confp->pri.pri.max_call_waiting_calls < 0) {
19433 /* Negative values are not allowed. */
19434 confp->pri.pri.max_call_waiting_calls = 0;
19435 }
19436 } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
19437 confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
19438#endif /* defined(HAVE_PRI_CALL_WAITING) */
19439#if defined(HAVE_PRI_MWI)
19440 } else if (!strcasecmp(v->name, "mwi_mailboxes")) {
19441 ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
19442 sizeof(confp->pri.pri.mwi_mailboxes));
19443 } else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
19444 ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
19445 sizeof(confp->pri.pri.mwi_vm_boxes));
19446 } else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
19447 ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
19448 sizeof(confp->pri.pri.mwi_vm_numbers));
19449#endif /* defined(HAVE_PRI_MWI) */
19450 } else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
19451 confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
19452 } else if (!strcasecmp(v->name, "inband_on_setup_ack")) {
19453 confp->pri.pri.inband_on_setup_ack = ast_true(v->value);
19454 } else if (!strcasecmp(v->name, "inband_on_proceeding")) {
19455 confp->pri.pri.inband_on_proceeding = ast_true(v->value);
19456#if defined(HAVE_PRI_DISPLAY_TEXT)
19457 } else if (!strcasecmp(v->name, "display_send")) {
19458 confp->pri.pri.display_flags_send = dahdi_display_text_option(v->value);
19459 } else if (!strcasecmp(v->name, "display_receive")) {
19460 confp->pri.pri.display_flags_receive = dahdi_display_text_option(v->value);
19461#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19462#if defined(HAVE_PRI_MCID)
19463 } else if (!strcasecmp(v->name, "mcid_send")) {
19464 confp->pri.pri.mcid_send = ast_true(v->value);
19465#endif /* defined(HAVE_PRI_MCID) */
19466#if defined(HAVE_PRI_DATETIME_SEND)
19467 } else if (!strcasecmp(v->name, "datetime_send")) {
19468 confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
19469#endif /* defined(HAVE_PRI_DATETIME_SEND) */
19470 } else if (!strcasecmp(v->name, "layer1_presence")) {
19471 if (!strcasecmp(v->value, "required")) {
19472 confp->pri.pri.layer1_ignored = 0;
19473 } else if (!strcasecmp(v->value, "ignore")) {
19474 confp->pri.pri.layer1_ignored = 1;
19475 } else {
19476 /* Default */
19477 confp->pri.pri.layer1_ignored = 0;
19478 }
19479#if defined(HAVE_PRI_L2_PERSISTENCE)
19480 } else if (!strcasecmp(v->name, "layer2_persistence")) {
19481 if (!strcasecmp(v->value, "keep_up")) {
19482 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_KEEP_UP;
19483 } else if (!strcasecmp(v->value, "leave_down")) {
19484 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_LEAVE_DOWN;
19485 } else {
19486 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_DEFAULT;
19487 }
19488#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19489 } else if (!strcasecmp(v->name, "colp_send")) {
19490 if (!strcasecmp(v->value, "block")) {
19491 confp->pri.pri.colp_send = SIG_PRI_COLP_BLOCK;
19492 } else if (!strcasecmp(v->value, "connect")) {
19493 confp->pri.pri.colp_send = SIG_PRI_COLP_CONNECT;
19494 } else if (!strcasecmp(v->value, "update")) {
19495 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19496 } else {
19497 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19498 }
19499#endif /* HAVE_PRI */
19500#if defined(HAVE_SS7)
19501 } else if (!strcasecmp(v->name, "ss7type")) {
19502 if (!strcasecmp(v->value, "itu")) {
19503 cur_ss7type = SS7_ITU;
19504 } else if (!strcasecmp(v->value, "ansi")) {
19505 cur_ss7type = SS7_ANSI;
19506 } else {
19507 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
19508 }
19509 } else if (!strcasecmp(v->name, "slc")) {
19510 cur_slc = atoi(v->value);
19511 } else if (!strcasecmp(v->name, "linkset")) {
19512 cur_linkset = atoi(v->value);
19513 } else if (!strcasecmp(v->name, "pointcode")) {
19514 cur_pointcode = parse_pointcode(v->value);
19515 } else if (!strcasecmp(v->name, "adjpointcode")) {
19516 cur_adjpointcode = parse_pointcode(v->value);
19517 } else if (!strcasecmp(v->name, "defaultdpc")) {
19518 cur_defaultdpc = parse_pointcode(v->value);
19519 } else if (!strcasecmp(v->name, "cicbeginswith")) {
19520 cur_cicbeginswith = atoi(v->value);
19521 } else if (!strcasecmp(v->name, "networkindicator")) {
19522 if (!strcasecmp(v->value, "national")) {
19523 cur_networkindicator = SS7_NI_NAT;
19524 } else if (!strcasecmp(v->value, "national_spare")) {
19525 cur_networkindicator = SS7_NI_NAT_SPARE;
19526 } else if (!strcasecmp(v->value, "international")) {
19527 cur_networkindicator = SS7_NI_INT;
19528 } else if (!strcasecmp(v->value, "international_spare")) {
19529 cur_networkindicator = SS7_NI_INT_SPARE;
19530 } else {
19531 cur_networkindicator = -1;
19532 }
19533 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
19534 ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
19535 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
19536 ast_copy_string(confp->ss7.ss7.nationalprefix, v->value, sizeof(confp->ss7.ss7.nationalprefix));
19537 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
19538 ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
19539 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
19540 ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
19541 } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
19542 ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
19543 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
19544 if (!strcasecmp(v->value, "national")) {
19545 confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
19546 } else if (!strcasecmp(v->value, "international")) {
19547 confp->ss7.ss7.called_nai = SS7_NAI_INTERNATIONAL;
19548 } else if (!strcasecmp(v->value, "subscriber")) {
19549 confp->ss7.ss7.called_nai = SS7_NAI_SUBSCRIBER;
19550 } else if (!strcasecmp(v->value, "unknown")) {
19551 confp->ss7.ss7.called_nai = SS7_NAI_UNKNOWN;
19552 } else if (!strcasecmp(v->value, "dynamic")) {
19553 confp->ss7.ss7.called_nai = SS7_NAI_DYNAMIC;
19554 } else {
19555 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
19556 }
19557 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
19558 if (!strcasecmp(v->value, "national")) {
19559 confp->ss7.ss7.calling_nai = SS7_NAI_NATIONAL;
19560 } else if (!strcasecmp(v->value, "international")) {
19561 confp->ss7.ss7.calling_nai = SS7_NAI_INTERNATIONAL;
19562 } else if (!strcasecmp(v->value, "subscriber")) {
19563 confp->ss7.ss7.calling_nai = SS7_NAI_SUBSCRIBER;
19564 } else if (!strcasecmp(v->value, "unknown")) {
19565 confp->ss7.ss7.calling_nai = SS7_NAI_UNKNOWN;
19566 } else if (!strcasecmp(v->value, "dynamic")) {
19567 confp->ss7.ss7.calling_nai = SS7_NAI_DYNAMIC;
19568 } else {
19569 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
19570 }
19571 } else if (!strcasecmp(v->name, "sigchan")) {
19572 int sigchan, res;
19573 sigchan = atoi(v->value);
19574 res = linkset_addsigchan(sigchan);
19575 if (res < 0) {
19576 return -1;
19577 }
19578 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
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_EXPLICITACM;
19587 } else {
19588 link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
19589 }
19590 } else if (!strcasecmp(v->name, "ss7_autoacm")) {
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_AUTOACM;
19599 } else {
19600 link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
19601 }
19602 } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
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_INITIALHWBLO;
19611 } else {
19612 link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
19613 }
19614 } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
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 (ast_true(v->value)) {
19622 link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
19623 } else {
19624 link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
19625 }
19626 } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
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 (ast_true(v->value)) {
19634 link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
19635 } else {
19636 link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
19637 }
19638 } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
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 isup timers after sigchan!\n");
19647 } else if (!ss7_set_isup_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19648 ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
19649 }
19650 } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
19651 struct dahdi_ss7 *link;
19652 link = ss7_resolve_linkset(cur_linkset);
19653 if (!link) {
19654 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19655 return -1;
19656 }
19657 if (!link->ss7.ss7) {
19658 ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
19659 } else if (!ss7_set_mtp3_timer(link->ss7.ss7, strstr(v->name, ".") + 1, atoi(v->value))) {
19660 ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
19661 }
19662 } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
19663 struct dahdi_ss7 *link;
19664 link = ss7_resolve_linkset(cur_linkset);
19665 if (!link) {
19666 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19667 return -1;
19668 }
19669 if (!link->ss7.ss7) {
19670 ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
19671 } else if (ast_true(v->value)) {
19672 ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19673 } else {
19674 ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19675 }
19676 } else if (!strcasecmp(v->name, "non_isdn_access")) {
19677 struct dahdi_ss7 *link;
19678 link = ss7_resolve_linkset(cur_linkset);
19679 if (!link) {
19680 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19681 return -1;
19682 }
19683 if (!link->ss7.ss7) {
19684 ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
19685 } else if (ast_true(v->value)) {
19686 ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19687 } else {
19688 ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19689 }
19690 } else if (!strcasecmp(v->name, "sls_shift")) {
19691 struct dahdi_ss7 *link;
19692 int sls_shift = atoi(v->value);
19693
19694 if (sls_shift < 0 || sls_shift > 7) {
19695 ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
19696 return -1;
19697 }
19698
19699 link = ss7_resolve_linkset(cur_linkset);
19700 if (!link) {
19701 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19702 return -1;
19703 }
19704 if (!link->ss7.ss7) {
19705 ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
19706 } else {
19707 ss7_set_sls_shift(link->ss7.ss7, sls_shift);
19708 }
19709 } else if (!strcasecmp(v->name, "cause_location")) {
19710 struct dahdi_ss7 *link;
19711 int cause_location = atoi(v->value);
19712
19713 if (cause_location < 0 || cause_location > 15) {
19714 ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
19715 return -1;
19716 }
19717 link = ss7_resolve_linkset(cur_linkset);
19718 if (!link) {
19719 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19720 return -1;
19721 }
19722 if (!link->ss7.ss7) {
19723 ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
19724 } else {
19725 ss7_set_cause_location(link->ss7.ss7, cause_location);
19726 }
19727#endif /* defined(HAVE_SS7) */
19728#ifdef HAVE_OPENR2
19729 } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
19730 ast_copy_string(confp->mfcr2.r2proto_file, v->value, sizeof(confp->mfcr2.r2proto_file));
19731 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);
19732 } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
19733 ast_copy_string(confp->mfcr2.logdir, v->value, sizeof(confp->mfcr2.logdir));
19734 } else if (!strcasecmp(v->name, "mfcr2_variant")) {
19735 confp->mfcr2.variant = openr2_proto_get_variant(v->value);
19736 if (OR2_VAR_UNKNOWN == confp->mfcr2.variant) {
19737 ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v->value, v->lineno);
19738 confp->mfcr2.variant = OR2_VAR_ITU;
19739 }
19740 } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
19741 confp->mfcr2.mfback_timeout = atoi(v->value);
19742 if (!confp->mfcr2.mfback_timeout) {
19743 ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19744 confp->mfcr2.mfback_timeout = -1;
19745 } else if (confp->mfcr2.mfback_timeout > 0 && confp->mfcr2.mfback_timeout < 500) {
19746 ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19747 }
19748 } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
19749 confp->mfcr2.metering_pulse_timeout = atoi(v->value);
19750 if (confp->mfcr2.metering_pulse_timeout > 500) {
19751 ast_log(LOG_WARNING, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19752 }
19753#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19754 } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
19755 confp->mfcr2.dtmf_detection = ast_true(v->value) ? 1 : 0;
19756 } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
19757 confp->mfcr2.dtmf_dialing = ast_true(v->value) ? 1 : 0;
19758 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
19759 confp->mfcr2.dtmf_time_on = atoi(v->value);
19760 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
19761 confp->mfcr2.dtmf_time_off = atoi(v->value);
19762#endif
19763#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19764 } else if (!strcasecmp(v->name, "mfcr2_dtmf_end_timeout")) {
19765 confp->mfcr2.dtmf_end_timeout = atoi(v->value);
19766#endif
19767 } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
19768 confp->mfcr2.get_ani_first = ast_true(v->value) ? 1 : 0;
19769 } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
19770 confp->mfcr2.double_answer = ast_true(v->value) ? 1 : 0;
19771 } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
19772 confp->mfcr2.charge_calls = ast_true(v->value) ? 1 : 0;
19773 } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
19774 confp->mfcr2.accept_on_offer = ast_true(v->value) ? 1 : 0;
19775 } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
19776 confp->mfcr2.allow_collect_calls = ast_true(v->value) ? 1 : 0;
19777 } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
19778 confp->mfcr2.forced_release = ast_true(v->value) ? 1 : 0;
19779 } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
19780 confp->mfcr2.immediate_accept = ast_true(v->value) ? 1 : 0;
19781#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19782 } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
19783 confp->mfcr2.skip_category_request = ast_true(v->value) ? 1 : 0;
19784#endif
19785 } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
19786 confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
19787 } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
19788 confp->mfcr2.max_ani = atoi(v->value);
19789 if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
19790 confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
19791 }
19792 } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
19793 confp->mfcr2.max_dnis = atoi(v->value);
19794 if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
19795 confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
19796 }
19797 } else if (!strcasecmp(v->name, "mfcr2_category")) {
19798 confp->mfcr2.category = openr2_proto_get_category(v->value);
19799 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == confp->mfcr2.category) {
19800 confp->mfcr2.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
19801 ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19802 v->value, v->lineno);
19803 }
19804 } else if (!strcasecmp(v->name, "mfcr2_logging")) {
19805 openr2_log_level_t tmplevel;
19806 char *clevel;
19807 char *logval;
19808 char copy[strlen(v->value) + 1];
19809 strcpy(copy, v->value); /* safe */
19810 logval = copy;
19811 while (logval) {
19812 clevel = strsep(&logval,",");
19813 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
19814 ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", clevel, v->lineno);
19815 continue;
19816 }
19817 confp->mfcr2.loglevel |= tmplevel;
19818 }
19819#endif /* HAVE_OPENR2 */
19820 } else if (!strcasecmp(v->name, "cadence")) {
19821 /* setup to scan our argument */
19822 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
19823 int i;
19824 struct dahdi_ring_cadence new_cadence;
19825 int cid_location = -1;
19826 int firstcadencepos = 0;
19827 char original_args[80];
19828 int cadence_is_ok = 1;
19829
19830 ast_copy_string(original_args, v->value, sizeof(original_args));
19831 /* 16 cadences allowed (8 pairs) */
19832 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]);
19833
19834 /* Cadence must be even (on/off) */
19835 if (element_count % 2 == 1) {
19836 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
19837 cadence_is_ok = 0;
19838 }
19839
19840 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
19841 if (element_count > ARRAY_LEN(c)) {
19842 element_count = ARRAY_LEN(c);
19843 }
19844
19845 /* Ring cadences cannot be negative */
19846 for (i = 0; i < element_count; i++) {
19847 if (c[i] == 0) {
19848 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
19849 cadence_is_ok = 0;
19850 break;
19851 } else if (c[i] < 0) {
19852 if (i % 2 == 1) {
19853 /* Silence duration, negative possibly okay */
19854 if (cid_location == -1) {
19855 cid_location = i;
19856 c[i] *= -1;
19857 } else {
19858 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
19859 cadence_is_ok = 0;
19860 break;
19861 }
19862 } else {
19863 if (firstcadencepos == 0) {
19864 firstcadencepos = i; /* only recorded to avoid duplicate specification */
19865 /* duration will be passed negative to the DAHDI driver */
19866 } else {
19867 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
19868 cadence_is_ok = 0;
19869 break;
19870 }
19871 }
19872 }
19873 }
19874
19875 /* Substitute our scanned cadence */
19876 for (i = 0; i < 16; i++) {
19877 new_cadence.ringcadence[i] = c[i];
19878 }
19879
19880 if (cadence_is_ok) {
19881 /* ---we scanned it without getting annoyed; now some sanity checks--- */
19882 if (element_count < 2) {
19883 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
19884 } else {
19885 if (cid_location == -1) {
19886 /* user didn't say; default to first pause */
19887 cid_location = 1;
19888 } else {
19889 /* convert element_index to cidrings value */
19890 cid_location = (cid_location + 1) / 2;
19891 }
19892 /* ---we like their cadence; try to install it--- */
19894 /* this is the first user-defined cadence; clear the default user cadences */
19895 num_cadence = 0;
19896 if ((num_cadence+1) >= NUM_CADENCE_MAX)
19897 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
19898 else {
19899 cadences[num_cadence] = new_cadence;
19900 cidrings[num_cadence++] = cid_location;
19901 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
19902 }
19903 }
19904 }
19905 } else if (!strcasecmp(v->name, "ringtimeout")) {
19906 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
19907 } else if (!strcasecmp(v->name, "prewink")) {
19908 confp->timing.prewinktime = atoi(v->value);
19909 } else if (!strcasecmp(v->name, "preflash")) {
19910 confp->timing.preflashtime = atoi(v->value);
19911 } else if (!strcasecmp(v->name, "wink")) {
19912 confp->timing.winktime = atoi(v->value);
19913 } else if (!strcasecmp(v->name, "flash")) {
19914 confp->timing.flashtime = atoi(v->value);
19915 } else if (!strcasecmp(v->name, "start")) {
19916 confp->timing.starttime = atoi(v->value);
19917 } else if (!strcasecmp(v->name, "rxwink")) {
19918 confp->timing.rxwinktime = atoi(v->value);
19919 } else if (!strcasecmp(v->name, "rxflash")) {
19920 confp->timing.rxflashtime = atoi(v->value);
19921 } else if (!strcasecmp(v->name, "debounce")) {
19922 confp->timing.debouncetime = atoi(v->value);
19923 } else if (!strcasecmp(v->name, "toneduration")) {
19924 int toneduration;
19925 int ctlfd;
19926 int res;
19927 struct dahdi_dialparams dps;
19928
19929 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
19930 if (ctlfd == -1) {
19931 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
19932 return -1;
19933 }
19934
19935 toneduration = atoi(v->value);
19936 if (toneduration > -1) {
19937 memset(&dps, 0, sizeof(dps));
19938
19939 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
19940 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
19941 if (res < 0) {
19942 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
19943 close(ctlfd);
19944 return -1;
19945 }
19946 }
19947 close(ctlfd);
19948 } else if (!strcasecmp(v->name, "defaultcic")) {
19950 } else if (!strcasecmp(v->name, "defaultozz")) {
19952 } else if (!strcasecmp(v->name, "mwilevel")) {
19953 mwilevel = atoi(v->value);
19954 } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
19955 dtmfcid_level = atoi(v->value);
19956 } else if (!strcasecmp(v->name, "reportalarms")) {
19957 if (!strcasecmp(v->value, "all"))
19959 if (!strcasecmp(v->value, "none"))
19960 report_alarms = 0;
19961 else if (!strcasecmp(v->value, "channels"))
19963 else if (!strcasecmp(v->value, "spans"))
19965 }
19966 } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
19967 ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
19968 }
19969
19970 if (dahdichan) {
19971 /* Process the deferred dahdichan value. */
19972 if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
19973 if (confp->ignore_failed_channels) {
19975 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
19976 dahdichan->value);
19977 } else {
19978 return -1;
19979 }
19980 }
19981 }
19982
19983 /*
19984 * Since confp has already filled individual dahdi_pvt objects with channels
19985 * at this point, clear the variables in confp's pvt.
19986 */
19987 if (confp->chan.vars) {
19989 confp->chan.vars = NULL;
19990 }
19991
19992 /* mark the first channels of each DAHDI span to watch for their span alarms */
19993 for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
19994 if (!tmp->destroy && tmp->span != y) {
19995 tmp->manages_span_alarms = 1;
19996 y = tmp->span;
19997 } else {
19998 tmp->manages_span_alarms = 0;
19999 }
20000 }
20001
20002 /*< \todo why check for the pseudo in the per-channel section.
20003 * Any actual use for manual setup of the pseudo channel? */
20004 if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
20005 /* use the default configuration for a channel, so
20006 that any settings from real configured channels
20007 don't "leak" into the pseudo channel config
20008 */
20010
20011 if (conf.chan.cc_params) {
20012 tmp = mkintf(CHAN_PSEUDO, &conf, reload);
20013 } else {
20014 tmp = NULL;
20015 }
20016 if (tmp) {
20017 ast_verb(3, "Automatically generated pseudo channel\n");
20018 has_pseudo = 1;
20019 } else {
20020 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
20021 }
20022 ast_cc_config_params_destroy(conf.chan.cc_params);
20023 }
20024
20025 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
20028
20029 return 0;
20030}
20031
20032/*!
20033 * \internal
20034 * \brief Deep copy struct dahdi_chan_conf.
20035 * \since 1.8
20036 *
20037 * \param dest Destination.
20038 * \param src Source.
20039 */
20040static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
20041{
20042 struct ast_cc_config_params *cc_params;
20043
20044 cc_params = dest->chan.cc_params;
20045 *dest = *src;
20046 dest->chan.cc_params = cc_params;
20048}
20049
20050/*!
20051 * \internal
20052 * \brief Setup DAHDI channel driver.
20053 *
20054 * \param reload enum: load_module(0), reload(1), restart(2).
20055 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
20056 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
20057 * \param conf Local config parameters. So cc_params can be properly destroyed.
20058 *
20059 * \retval 0 on success.
20060 * \retval -1 on error.
20061 */
20062static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
20063{
20064 struct ast_config *cfg;
20065 struct ast_config *ucfg;
20066 struct ast_variable *v;
20067 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
20068 const char *chans;
20069 const char *cat;
20070 int res;
20071
20072#ifdef HAVE_PRI
20073 char *c;
20074 int spanno;
20075 int i;
20076 int logicalspan;
20077 int trunkgroup;
20078 int dchannels[SIG_PRI_NUM_DCHANS];
20079#endif
20080 int have_cfg_now;
20081 static int had_cfg_before = 1;/* So initial load will complain if we don't have cfg. */
20082
20083 cfg = ast_config_load(config, config_flags);
20084 have_cfg_now = !!cfg;
20085 if (!cfg) {
20086 /* Error if we have no config file */
20087 if (had_cfg_before) {
20088 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
20090 }
20091 cfg = ast_config_new();/* Dummy config */
20092 if (!cfg) {
20093 return 0;
20094 }
20095 ucfg = ast_config_load("users.conf", config_flags);
20096 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
20097 ast_config_destroy(cfg);
20098 return 0;
20099 }
20100 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20101 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20102 ast_config_destroy(cfg);
20103 return 0;
20104 }
20105 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
20106 ucfg = ast_config_load("users.conf", config_flags);
20107 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
20108 return 0;
20109 }
20110 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20111 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20112 return 0;
20113 }
20115 cfg = ast_config_load(config, config_flags);
20116 have_cfg_now = !!cfg;
20117 if (!cfg) {
20118 if (had_cfg_before) {
20119 /* We should have been able to load the config. */
20120 ast_log(LOG_ERROR, "Bad. Unable to load config %s\n", config);
20121 ast_config_destroy(ucfg);
20122 return 0;
20123 }
20124 cfg = ast_config_new();/* Dummy config */
20125 if (!cfg) {
20126 ast_config_destroy(ucfg);
20127 return 0;
20128 }
20129 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20130 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20131 ast_config_destroy(ucfg);
20132 return 0;
20133 }
20134 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20135 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20136 return 0;
20137 } else {
20139 ucfg = ast_config_load("users.conf", config_flags);
20140 if (ucfg == CONFIG_STATUS_FILEINVALID) {
20141 ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n");
20142 ast_config_destroy(cfg);
20143 return 0;
20144 }
20145 }
20146 had_cfg_before = have_cfg_now;
20147
20148 /* It's a little silly to lock it, but we might as well just to be sure */
20150#ifdef HAVE_PRI
20151 if (reload != 1) {
20152 /* Process trunkgroups first */
20153 v = ast_variable_browse(cfg, "trunkgroups");
20154 while (v) {
20155 if (!strcasecmp(v->name, "trunkgroup")) {
20156 trunkgroup = atoi(v->value);
20157 if (trunkgroup > 0) {
20158 if ((c = strchr(v->value, ','))) {
20159 i = 0;
20160 memset(dchannels, 0, sizeof(dchannels));
20161 while (c && (i < SIG_PRI_NUM_DCHANS)) {
20162 dchannels[i] = atoi(c + 1);
20163 if (dchannels[i] < 0) {
20164 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);
20165 } else
20166 i++;
20167 c = strchr(c + 1, ',');
20168 }
20169 if (i) {
20170 if (pri_create_trunkgroup(trunkgroup, dchannels)) {
20171 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);
20172 } else
20173 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");
20174 } else
20175 ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20176 } else
20177 ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20178 } else
20179 ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20180 } else if (!strcasecmp(v->name, "spanmap")) {
20181 spanno = atoi(v->value);
20182 if (spanno > 0) {
20183 if ((c = strchr(v->value, ','))) {
20184 trunkgroup = atoi(c + 1);
20185 if (trunkgroup > 0) {
20186 if ((c = strchr(c + 1, ',')))
20187 logicalspan = atoi(c + 1);
20188 else
20189 logicalspan = 0;
20190 if (logicalspan >= 0) {
20191 if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
20192 ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20193 } else
20194 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20195 } else
20196 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);
20197 } else
20198 ast_log(LOG_WARNING, "Trunk group must be a positive number at line %d of chan_dahdi.conf\n", v->lineno);
20199 } else
20200 ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
20201 } else
20202 ast_log(LOG_WARNING, "Span number must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20203 } else {
20204 ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
20205 }
20206 v = v->next;
20207 }
20208 }
20209#endif
20210
20211 /* Copy the default jb config over global_jbconf */
20212 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
20213
20214 mwimonitornotify[0] = '\0';
20215
20216 v = ast_variable_browse(cfg, "channels");
20217 if ((res = process_dahdi(base_conf,
20218 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
20219 v, reload, 0))) {
20221 ast_config_destroy(cfg);
20222 if (ucfg) {
20223 ast_config_destroy(ucfg);
20224 }
20225 return res;
20226 }
20227
20228 /* Now get configuration from all normal sections in chan_dahdi.conf: */
20229 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
20230 /* [channels] and [trunkgroups] are used. Let's also reserve
20231 * [globals] and [general] for future use
20232 */
20233 if (!strcasecmp(cat, "general") ||
20234 !strcasecmp(cat, "trunkgroups") ||
20235 !strcasecmp(cat, "globals") ||
20236 !strcasecmp(cat, "channels")) {
20237 continue;
20238 }
20239
20240 chans = ast_variable_retrieve(cfg, cat, "dahdichan");
20241 if (ast_strlen_zero(chans)) {
20242 /* Section is useless without a dahdichan value present. */
20243 continue;
20244 }
20245
20246 /* Copy base_conf to conf. */
20247 deep_copy_dahdi_chan_conf(conf, base_conf);
20248
20249 if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
20251 ast_config_destroy(cfg);
20252 if (ucfg) {
20253 ast_config_destroy(ucfg);
20254 }
20255 return res;
20256 }
20257 }
20258
20259 ast_config_destroy(cfg);
20260
20261 if (ucfg) {
20262 /* Reset base_conf, so things don't leak from chan_dahdi.conf */
20263 deep_copy_dahdi_chan_conf(base_conf, default_conf);
20264 process_dahdi(base_conf,
20265 "" /* Must be empty for the general category. Silly voicemail mailbox. */,
20266 ast_variable_browse(ucfg, "general"), 1, 0);
20267
20268 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
20269 if (!strcasecmp(cat, "general")) {
20270 continue;
20271 }
20272
20273 chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
20274 if (ast_strlen_zero(chans)) {
20275 /* Section is useless without a dahdichan value present. */
20276 continue;
20277 }
20278
20279 /* Copy base_conf to conf. */
20280 deep_copy_dahdi_chan_conf(conf, base_conf);
20281
20283 ast_config_destroy(ucfg);
20285 return res;
20286 }
20287 }
20288 ast_config_destroy(ucfg);
20289 }
20291
20292#ifdef HAVE_PRI
20293 if (reload != 1) {
20294 int x;
20295 for (x = 0; x < NUM_SPANS; x++) {
20296 if (pris[x].pri.pvts[0] &&
20297 pris[x].pri.master == AST_PTHREADT_NULL) {
20298 prepare_pri(pris + x);
20299 if (sig_pri_start_pri(&pris[x].pri)) {
20300 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
20301 return -1;
20302 } else
20303 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
20304 }
20305 }
20306 }
20307#endif
20308#if defined(HAVE_SS7)
20309 if (reload != 1) {
20310 int x;
20311 for (x = 0; x < NUM_SPANS; x++) {
20312 if (linksets[x].ss7.ss7) {
20313 if (ast_pthread_create(&linksets[x].ss7.master, NULL, ss7_linkset, &linksets[x].ss7)) {
20314 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
20315 return -1;
20316 } else
20317 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
20318 }
20319 }
20320 }
20321#endif /* defined(HAVE_SS7) */
20322#ifdef HAVE_OPENR2
20323 if (reload != 1) {
20324 struct r2link_entry *cur;
20325 int x = 0;
20326 AST_LIST_LOCK(&r2links);
20327 AST_LIST_TRAVERSE(&r2links, cur, list) {
20328 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
20329 if (r2->r2master == AST_PTHREADT_NULL) {
20330 if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
20331 ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
20332 return -1;
20333 } else {
20334 ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
20335 }
20336 x++;
20337 }
20338 }
20339 AST_LIST_UNLOCK(&r2links);
20340 }
20341#endif
20342 /* And start the monitor for the first time */
20344 return 0;
20345}
20346
20347/*!
20348 * \internal
20349 * \brief Setup DAHDI channel driver.
20350 *
20351 * \param reload enum: load_module(0), reload(1), restart(2).
20352 *
20353 * \retval 0 on success.
20354 * \retval -1 on error.
20355 */
20356static int setup_dahdi(int reload)
20357{
20358 int res;
20359 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
20360 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
20362
20363 if (default_conf.chan.cc_params && base_conf.chan.cc_params && conf.chan.cc_params) {
20364 res = setup_dahdi_int(reload, &default_conf, &base_conf, &conf);
20365 } else {
20366 res = -1;
20367 }
20370 ast_cc_config_params_destroy(conf.chan.cc_params);
20371
20372 return res;
20373}
20374
20375/*!
20376 * \brief Load the module
20377 *
20378 * Module loading including tests for configuration or dependencies.
20379 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20380 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20381 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20382 * configuration file or other non-critical problem return
20383 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20384 */
20385static int load_module(void)
20386{
20387 int res;
20388#if defined(HAVE_PRI) || defined(HAVE_SS7)
20389 int y;
20390#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20391
20392 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
20394 }
20395
20398 }
20402
20406 }
20407
20408#ifdef HAVE_PRI
20409 memset(pris, 0, sizeof(pris));
20410 for (y = 0; y < NUM_SPANS; y++) {
20411 sig_pri_init_pri(&pris[y].pri);
20412 }
20413 pri_set_error(dahdi_pri_error);
20414 pri_set_message(dahdi_pri_message);
20415 ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
20416#ifdef HAVE_PRI_PROG_W_CAUSE
20417 ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
20418#endif
20419#if defined(HAVE_PRI_CCSS)
20420 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
20421 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
20424 }
20425#endif /* defined(HAVE_PRI_CCSS) */
20426 if (sig_pri_load(
20427#if defined(HAVE_PRI_CCSS)
20428 dahdi_pri_cc_type
20429#else
20430 NULL
20431#endif /* defined(HAVE_PRI_CCSS) */
20432 )) {
20435 }
20436#endif
20437#if defined(HAVE_SS7)
20438 memset(linksets, 0, sizeof(linksets));
20439 for (y = 0; y < NUM_SPANS; y++) {
20440 sig_ss7_init_linkset(&linksets[y].ss7);
20441 }
20442 ss7_set_error(dahdi_ss7_error);
20443 ss7_set_message(dahdi_ss7_message);
20444 ss7_set_hangup(sig_ss7_cb_hangup);
20445 ss7_set_notinservice(sig_ss7_cb_notinservice);
20446 ss7_set_call_null(sig_ss7_cb_call_null);
20447#endif /* defined(HAVE_SS7) */
20448 res = setup_dahdi(0);
20449 /* Make sure we can register our DAHDI channel type */
20450 if (res) {
20453 }
20455 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
20458 }
20459#ifdef HAVE_PRI
20460 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
20461#endif
20462#if defined(HAVE_SS7)
20463 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
20464#endif /* defined(HAVE_SS7) */
20465#ifdef HAVE_OPENR2
20466 ast_cli_register_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
20467 ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
20468#endif
20469
20471
20473 memset(round_robin, 0, sizeof(round_robin));
20474 ast_manager_register_xml("DAHDITransfer", 0, action_transfer);
20476 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
20479 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
20480 ast_manager_register_xml("DAHDIShowStatus", 0, action_dahdishowstatus);
20482#if defined(HAVE_PRI)
20483 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
20484 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
20485 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
20486 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
20487#endif /* defined(HAVE_PRI) */
20488
20490
20491 return res;
20492}
20493
20494static int dahdi_sendtext(struct ast_channel *c, const char *text)
20495{
20496#define END_SILENCE_LEN 400
20497#define HEADER_MS 50
20498#define TRAILER_MS 5
20499#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20500#define ASCII_BYTES_PER_CHAR 80
20501
20502 unsigned char *buf,*mybuf;
20503 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
20504 struct pollfd fds[1];
20505 int size,res,fd,len,x;
20506 int bytes=0;
20507 int idx;
20508
20509 /*
20510 * Initial carrier (imaginary)
20511 *
20512 * Note: The following float variables are used by the
20513 * PUT_CLID_MARKMS and PUT_CLID() macros.
20514 */
20515 float cr = 1.0;
20516 float ci = 0.0;
20517 float scont = 0.0;
20518
20519 if (!text[0]) {
20520 return(0); /* if nothing to send, don't */
20521 }
20522 idx = dahdi_get_index(c, p, 0);
20523 if (idx < 0) {
20524 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
20525 return -1;
20526 }
20527 if ((!p->tdd) && (!p->mate)) {
20528#if defined(HAVE_PRI)
20529#if defined(HAVE_PRI_DISPLAY_TEXT)
20530 ast_mutex_lock(&p->lock);
20532 sig_pri_sendtext(p->sig_pvt, text);
20533 }
20535#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20536#endif /* defined(HAVE_PRI) */
20537 return(0); /* if not in TDD mode, just return */
20538 }
20539 if (p->mate)
20541 else
20542 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
20543 if (!buf)
20544 return -1;
20545 mybuf = buf;
20546 if (p->mate) {
20547 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20548 struct ast_format *codec = AST_LAW(p);
20549
20550 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
20552 }
20553 /* Put actual message */
20554 for (x = 0; text[x]; x++) {
20555 PUT_CLID(text[x]);
20556 }
20557 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
20559 }
20560 len = bytes;
20561 buf = mybuf;
20562 } else {
20563 len = tdd_generate(p->tdd, buf, text);
20564 if (len < 1) {
20565 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
20566 ast_free(mybuf);
20567 return -1;
20568 }
20569 }
20570 memset(buf + len, 0x7f, END_SILENCE_LEN);
20572 fd = p->subs[idx].dfd;
20573 while (len) {
20574 if (ast_check_hangup(c)) {
20575 ast_free(mybuf);
20576 return -1;
20577 }
20578 size = len;
20579 if (size > READ_SIZE)
20580 size = READ_SIZE;
20581 fds[0].fd = fd;
20582 fds[0].events = POLLOUT | POLLPRI;
20583 fds[0].revents = 0;
20584 res = poll(fds, 1, -1);
20585 if (!res) {
20586 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
20587 continue;
20588 }
20589 /* if got exception */
20590 if (fds[0].revents & POLLPRI) {
20591 ast_free(mybuf);
20592 return -1;
20593 }
20594 if (!(fds[0].revents & POLLOUT)) {
20595 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
20596 continue;
20597 }
20598 res = write(fd, buf, size);
20599 if (res != size) {
20600 if (res == -1) {
20601 ast_free(mybuf);
20602 return -1;
20603 }
20604 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
20605 break;
20606 }
20607 len -= size;
20608 buf += size;
20609 }
20610 ast_free(mybuf);
20611 return(0);
20612}
20613
20614
20615static int reload(void)
20616{
20617 int res = 0;
20618
20619 res = setup_dahdi(1);
20620 if (res) {
20621 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
20622 return -1;
20623 }
20624 return 0;
20625}
20626
20627/* This is a workaround so that menuselect displays a proper description
20628 * AST_MODULE_INFO(, , "DAHDI Telephony"
20629 */
20630
20632 .support_level = AST_MODULE_SUPPORT_CORE,
20633 .load = load_module,
20634 .unload = unload_module,
20635 .reload = reload,
20636 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
20637 .requires = "ccss",
20638 .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:11620
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:11182
#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:16839
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:16091
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:9442
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:12591
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:9889
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:13541
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:16450
#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:15822
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:14248
static struct dahdi_pvt * find_channel_from_str(const char *channel)
Definition: chan_dahdi.c:16880
static int __unload_module(void)
Definition: chan_dahdi.c:18210
static void dahdi_softhangup_all(void)
Definition: chan_dahdi.c:15915
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:18340
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:16838
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:9907
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:16540
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:9955
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:11538
static char * dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_dahdi.c:16172
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:13574
static int dahdi_devicestate(const char *data)
Definition: chan_dahdi.c:14186
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:11353
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:20062
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:16841
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:9982
static int dahdi_sendtext(struct ast_channel *c, const char *text)
Definition: chan_dahdi.c:20494
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:18534
static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
Definition: chan_dahdi.c:18538
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:15943
static int action_transfer(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16930
static int bump_gains(struct dahdi_pvt *p)
Definition: chan_dahdi.c:5225
static void * do_monitor(void *data)
Definition: chan_dahdi.c:11952
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:16697
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:9614
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:12266
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:11196
#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:12572
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:16375
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:20356
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:16754
static int action_dahdidndon(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16892
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:9870
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:9569
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:17008
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:18401
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:14005
#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:16619
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:15866
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:13780
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:9936
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:9623
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:16507
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:11406
#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:18536
#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:20385
#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:16081
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:13844
#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:16911
static int unload_module(void)
Definition: chan_dahdi.c:18324
static int reload(void)
Definition: chan_dahdi.c:20615
static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
Definition: chan_dahdi.c:18573
static struct ast_cli_entry dahdi_cli[]
Definition: chan_dahdi.c:16823
#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:16058
static struct dahdi_pvt * find_channel(int channel)
Definition: chan_dahdi.c:16857
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:16411
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:11494
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:20040
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:11688
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:11947
static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
Definition: chan_dahdi.c:16976
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:16953
#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:17096
DAHDI internal API definitions.
#define SIG_FEATB
Definition: chan_dahdi.h:787
#define SIG_FGC_CAMA
Definition: chan_dahdi.h:790
#define SIG_SFWINK
Definition: chan_dahdi.h:799
#define SIG_EMWINK
Definition: chan_dahdi.h:784
#define SIG_MFCR2
Definition: chan_dahdi.h:814
#define SIG_FXSLS
Definition: chan_dahdi.h:792
#define MAX_SLAVES
Definition: chan_dahdi.h:95
static int dahdi_sig_pri_lib_handles(int signaling)
Definition: chan_dahdi.h:831
#define SIG_SF_FEATB
Definition: chan_dahdi.h:802
#define SIG_FXSKS
Definition: chan_dahdi.h:794
#define SIG_FXOGS
Definition: chan_dahdi.h:796
#define SUB_REAL
Definition: chan_dahdi.h:57
#define SIG_SF_FEATDMF
Definition: chan_dahdi.h:801
static int dahdi_analog_lib_handles(int signalling, int radio, int oprmode)
Definition: chan_dahdi.h:847
#define SUB_THREEWAY
Definition: chan_dahdi.h:59
#define SUB_CALLWAIT
Definition: chan_dahdi.h:58
#define SIG_PRI_LIB_HANDLE_CASES
Definition: chan_dahdi.h:817
#define SIG_FXOKS
Definition: chan_dahdi.h:797
#define SIG_FGC_CAMAMF
Definition: chan_dahdi.h:791
#define SIG_FXSGS
Definition: chan_dahdi.h:793
#define SIG_FEATDMF
Definition: chan_dahdi.h:786
#define SIG_EM_E1
Definition: chan_dahdi.h:803
#define SIG_SF_FEATD
Definition: chan_dahdi.h:800
#define SIG_SS7
Definition: chan_dahdi.h:811
#define SIG_BRI
Definition: chan_dahdi.h:807
@ DAHDI_IFLIST_NONE
Definition: chan_dahdi.h:117
@ DAHDI_IFLIST_MAIN
Definition: chan_dahdi.h:118
#define SIG_FEATD
Definition: chan_dahdi.h:785
#define SIG_BRI_PTMP
Definition: chan_dahdi.h:808
#define SIG_FEATDMF_TA
Definition: chan_dahdi.h:789
@ MWI_SEND_SA
Definition: chan_dahdi.h:102
@ MWI_SEND_PAUSE
Definition: chan_dahdi.h:104
@ MWI_SEND_SA_WAIT
Definition: chan_dahdi.h:103
@ MWI_SEND_DONE
Definition: chan_dahdi.h:107
@ MWI_SEND_SPILL
Definition: chan_dahdi.h:105
@ MWI_SEND_CLEANUP
Definition: chan_dahdi.h:106
#define SIG_FXOLS
Definition: chan_dahdi.h:795
#define SIG_E911
Definition: chan_dahdi.h:788
#define SIG_PRI
Definition: chan_dahdi.h:806
#define SIG_EM
Definition: chan_dahdi.h:783
#define SIG_SF
Definition: chan_dahdi.h:798
#define dahdi_get_index(ast, p, nullok)
Definition: chan_dahdi.h:888
static struct ast_timer * timer
Definition: chan_iax2.c:388
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3143
const char * ast_channel_name(const struct ast_channel *chan)
static int ast_fdisset(struct pollfd *pfds, int fd, int maximum, int *start)
Helper function for migrating select to poll.
Definition: channel.h:2877
void ast_channel_rings_set(struct ast_channel *chan, int value)
void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
void ast_party_name_init(struct ast_party_name *init)
Initialize the given name structure.
Definition: channel.c:1558
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:1611
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2510
#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:10569
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1788
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition: channel.h:2921
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:569
unsigned short ast_channel_transfercapability(const struct ast_channel *chan)
struct ast_namedgroups * ast_ref_namedgroups(struct ast_namedgroups *groups)
Definition: channel.c:7711
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3130
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:10456
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
unsigned long long ast_group_t
Definition: channel.h:215
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
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:1169
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:1974
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4214
#define ast_channel_trylock(chan)
Definition: channel.h:2974
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition: channel.c:1276
@ 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:1966
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition: channel.c:1605
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:7307
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:1204
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:1982
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:498
struct ast_namedgroups * ast_get_namedgroups(const char *s)
Create an ast_namedgroups set with group names from comma separated string.
Definition: channel.c:7648
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:444
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:2468
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2440
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:4304
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1254
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition: channel.c:1229
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:538
void ast_channel_softhangup_internal_flag_add(struct ast_channel *chan, int value)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
@ 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:1658
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition: channel.c:2814
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:10587
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:2395
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2427
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition: channel.c:4318
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:7705
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:7395
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3019
void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
ast_group_t ast_get_group(const char *s)
Definition: channel.c:7591
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:1541
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
#define AST_MAX_EXTENSION
Definition: channel.h:134
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_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:7359
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define RESULT_SUCCESS
Definition: cli.h:40
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define RESULT_FAILURE
Definition: cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct channel_usage channels
#define container_of(ptr, type, member)
Definition: codec_dahdi.c:277
short word
Device state management.
@ AST_DEVSTATE_NOT_CACHABLE
Definition: devicestate.h:69
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:513
int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:474
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c: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:7699
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:499
#define DLA_UNLOCK(lock)
Definition: lock.h:497
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define ast_cond_wait(cond, mutex)
Definition: lock.h:212
#define AST_PTHREADT_NULL
Definition: lock.h:73
#define ast_cond_init(cond, attr)
Definition: lock.h:208
#define ast_mutex_init(pmutex)
Definition: lock.h:193
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:481
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:486
#define AST_PTHREADT_STOP
Definition: lock.h:74
#define ast_mutex_unlock(a)
Definition: lock.h:197
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:764
#define ast_mutex_trylock(a)
Definition: lock.h:198
pthread_cond_t ast_cond_t
Definition: lock.h:185
#define ast_mutex_destroy(a)
Definition: lock.h:195
#define ast_mutex_lock(a)
Definition: lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:527
#define ast_cond_signal(cond)
Definition: lock.h:210
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10239
#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:7739
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7749
Asterisk MWI API.
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
void * ast_mwi_unsubscribe(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic and MWI.
Definition: mwi.c:254
struct stasis_cache * ast_mwi_state_cache(void)
Backend cache for ast_mwi_topic_cached().
Definition: mwi.c:94
struct ast_mwi_subscriber * ast_mwi_subscribe_pool(const char *mailbox, stasis_subscription_cb callback, void *data)
Add an MWI state subscriber, and stasis subscription to the mailbox.
Definition: mwi.c:235
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
Definition: mwi.h:378
Call Parking API.
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
Perform a blind transfer to a parking extension.
Definition: parking.c:143
int ast_parking_is_exten_park(const char *context, const char *exten)
Determine if the context/exten is a "parking" extension.
Definition: parking.c:179
int ast_parking_provider_registered(void)
Check whether a parking provider is registered.
Definition: parking.c:241
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_LOG_DIR
Definition: options.c:160
Core PBX routines and definitions.
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c: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:3914
int analog_dnd(struct analog_pvt *p, int flag)
Definition: sig_analog.c:4407
int analog_callwaiting_deluxe(struct analog_pvt *p, int option)
Definition: sig_analog.c:1619
int analog_config_complete(struct analog_pvt *p)
Definition: sig_analog.c:4351
void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
Definition: sig_analog.c:1748
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:4346
struct analog_pvt * analog_new(enum analog_sigtype signallingtype, void *private_data)
Definition: sig_analog.c:4318
int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
Definition: sig_analog.c:4369
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:4034
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:2977
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 callwaitingdeluxepending
TRUE if a Call Waiting Deluxe action is currently pending.
Definition: sig_analog.h:355
unsigned int canpark
Definition: sig_analog.h:295
unsigned int dahditrcallerid
Definition: sig_analog.h:296
int polarityonanswerdelay
Definition: sig_analog.h:326
char cid_num[AST_MAX_EXTENSION]
Definition: sig_analog.h:330
int redirecting_reason
Definition: sig_analog.h:365
unsigned int permhidecallerid
Definition: sig_analog.h:303
struct timeval flashtime
Definition: sig_analog.h:373
unsigned int callwaitingcallerid
Definition: sig_analog.h:311
unsigned int ani_wink_time
Definition: sig_analog.h:289
enum analog_sigtype outsigmod
Definition: sig_analog.h:322
unsigned int usedistinctiveringdetection
Definition: sig_analog.h:310
unsigned int answeronpolarityswitch
Definition: sig_analog.h:291
unsigned int threewaycalling
Definition: sig_analog.h:305
unsigned int pulse
Definition: sig_analog.h:304
int echotraining
Definition: sig_analog.h:324
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
unsigned int callwaitingdeluxe
Definition: sig_analog.h:302
enum analog_cid_start cid_start
Definition: sig_analog.h:328
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:315
unsigned int call_qualifier
Definition: sig_analog.h:357
unsigned int ani_timeout
Definition: sig_analog.h:288
unsigned int lastnumredial
Definition: sig_analog.h:300
int ringt_base
Definition: sig_analog.h:385
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:323
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:325
unsigned int transfer
Definition: sig_analog.h:307
unsigned int transfertobusy
Definition: sig_analog.h:308
unsigned int inalarm
Definition: sig_analog.h:343
char cid_name[AST_MAX_EXTENSION]
Definition: sig_analog.h:331
int stripmsd
Definition: sig_analog.h:327
unsigned int calledsubscriberheld
Definition: sig_analog.h:292
char mohsuggest[MAX_MUSICCLASS]
Definition: sig_analog.h:329
unsigned int use_callerid
Definition: sig_analog.h:309
struct ast_channel * ss_astchan
Definition: sig_analog.h:381
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition: sig_analog.h:317
struct ast_party_caller caller
Definition: sig_analog.h:364
struct ast_channel * owner
Definition: sig_analog.h:264
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:606
Structure that contains information regarding a channel in a bridge.
struct ast_channel * chan
const char * type
Type of agent the callbacks belong to.
Definition: ccss.h:857
Callbacks defined by CC monitors.
Definition: ccss.h:542
const char * type
Type of monitor the callbacks belong to.
Definition: ccss.h:549
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
struct ast_format_cap * capabilities
Definition: channel.h:652
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
ast_callid callid
char exten[AST_MAX_EXTENSION]
const char * data
char x
Definition: extconf.c:81
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
struct ast_flags flags
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
char chan_name[AST_CHANNEL_NAME]
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
int pattern[4]
Definition: dsp.h:68
Configuration relating to call pickup.
Structure used to handle boolean flags.
Definition: utils.h: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:719
unsigned int immediate
TRUE if the channel should be answered immediately without attempting to gather any digits.
Definition: chan_dahdi.h:316
unsigned int immediatering
TRUE if audible ringback should be provided when immediate = yes.
Definition: chan_dahdi.h:322
unsigned int threewaysilenthold
TRUE if a three way dial tone should time out to silence.
Definition: chan_dahdi.h:377
enum DAHDI_IFLIST which_iflist
Definition: chan_dahdi.h:168
unsigned int permcallwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition: chan_dahdi.h:334
float cid_rxgain
Amount of gain to increase during caller id.
Definition: chan_dahdi.h:158
float txdrc
Definition: chan_dahdi.h:164
struct dahdi_distRings drings
Distinctive Ring data.
Definition: chan_dahdi.h:491
struct ast_variable * vars
Channel variable list with associated values to set when a channel is created.
Definition: chan_dahdi.h:590
char cid_subaddr[AST_MAX_EXTENSION]
Caller ID subaddress from an incoming call.
Definition: chan_dahdi.h:543
unsigned int canpark
TRUE if support for call parking is enabled.
Definition: chan_dahdi.h:243
unsigned int bufferoverrideinuse
Definition: chan_dahdi.h:278
int law
Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition: chan_dahdi.h:562
int bufsize
Definition: chan_dahdi.h:138
unsigned int hwtxgain_enabled
TRUE if hardware Tx gain set by Asterisk.
Definition: chan_dahdi.h:475
unsigned int dnd
TRUE if Do-Not-Disturb is enabled, present only for non sig_analog.
Definition: chan_dahdi.h:262
int faxbuf_policy
Definition: chan_dahdi.h:142
unsigned int ignoredtmf
TRUE if DTMF detection is disabled.
Definition: chan_dahdi.h:310
struct dahdi_dialoperation dop
DAHDI dial operation command struct for ioctl() call.
Definition: chan_dahdi.h:702
struct timeval dtmfcid_delay
Definition: chan_dahdi.h:597
unsigned int dahditrcallerid
TRUE if we should use the callerid from incoming call on dahdi transfer.
Definition: chan_dahdi.h:412
struct dahdi_pvt * next
Definition: chan_dahdi.h:169
unsigned int doreoriginate
Internal flag for if we should actually process a reorigination.
Definition: chan_dahdi.h:293
unsigned char * cidspill
Analog caller ID waveform sample buffer.
Definition: chan_dahdi.h:603
struct tdd_state * tdd
Definition: chan_dahdi.h:708
int waitfordialtonetemp
Transient variable. Same as waitfordialtone, but temporarily set for a specific call,...
Definition: chan_dahdi.h:666
int cidlen
Length of the cidspill buffer containing samples.
Definition: chan_dahdi.h:607
int polarityonanswerdelay
Minimal time period (ms) between the answer polarity switch and hangup polarity switch.
Definition: chan_dahdi.h:733
int busycount
Number of times to see "busy" tone before hanging up.
Definition: chan_dahdi.h:647
char cid_num[AST_MAX_EXTENSION]
Caller ID number from an incoming call.
Definition: chan_dahdi.h:532
int ringt
Ring timeout timer??
Definition: chan_dahdi.h:609
struct ast_mwi_subscriber * mwi_event_sub
Opaque event subscription parameters for message waiting indication support.
Definition: chan_dahdi.h:717
ast_group_t group
Bitmapped groups this belongs to.
Definition: chan_dahdi.h:558
int sendcalleridafter
Send caller ID on FXS after this many rings. Set to 1 for US.
Definition: chan_dahdi.h:740
struct dahdi_pvt * oprpeer
Definition: chan_dahdi.h:152
unsigned int permhidecallerid
TRUE if the outgoing caller ID is blocked/restricted/hidden.
Definition: chan_dahdi.h:343
unsigned int mwisendactive
TRUE if a MWI message sending thread is active.
Definition: chan_dahdi.h:437
char * origcid_name
Definition: chan_dahdi.h:545
struct mwisend_info mwisend_data
Definition: chan_dahdi.h:486
int cid_suppress_expire
Definition: chan_dahdi.h:601
struct timeval flashtime
Definition: chan_dahdi.h:698
int oprmode
Definition: chan_dahdi.h:151
int interdigit_timeout
Time (ms) to detect following digits (in an analog phone)
Definition: chan_dahdi.h:691
unsigned int mwimonitor_rpas
TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
Definition: chan_dahdi.h:433
struct dahdi_pvt * master
Definition: chan_dahdi.h:135
unsigned int confirmanswer
TRUE if to wait for a DTMF digit to confirm answer.
Definition: chan_dahdi.h:245
unsigned int restartpending
Definition: chan_dahdi.h:361
unsigned int mwimonitoractive
TRUE if an MWI monitor thread is currently active.
Definition: chan_dahdi.h:435
unsigned int outgoing
TRUE if we originated the call leg.
Definition: chan_dahdi.h:328
unsigned int faxdetect_timeout
The number of seconds into call to disable fax detection. (0 = disabled)
Definition: chan_dahdi.h:681
int whichwink
Definition: chan_dahdi.h:703
float rxdrc
Definition: chan_dahdi.h:165
unsigned int callwaitingcallerid
TRUE if send caller ID for Call Waiting.
Definition: chan_dahdi.h:231
char * origcid_num
Definition: chan_dahdi.h:544
unsigned int manages_span_alarms
TRUE if the channel alarms will be managed also as Span ones.
Definition: chan_dahdi.h:471
unsigned int ani_wink_time
INTEGER, length of time to wait before sending ANI wink in ms.
Definition: chan_dahdi.h:200
int waitfordialtone
Number of milliseconds to wait for dialtone.
Definition: chan_dahdi.h:662
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition: chan_dahdi.h:457
unsigned int adsi
TRUE if ADSI (Analog Display Services Interface) available.
Definition: chan_dahdi.h:178
int outsigmod
Definition: chan_dahdi.h:150
unsigned int usedistinctiveringdetection
TRUE if distinctive rings are to be detected.
Definition: chan_dahdi.h:407
unsigned int answeronpolarityswitch
TRUE if we can use a polarity reversal to mark when an outgoing call is answered by the remote party.
Definition: chan_dahdi.h:184
unsigned int threewaycalling
TRUE if three way calling is enabled.
Definition: chan_dahdi.h:372
struct dahdi_subchannel subs[3]
Definition: chan_dahdi.h:131
int distinctivering
Definition: chan_dahdi.h:725
struct dahdi_confinfo saveconf
Definition: chan_dahdi.h:132
unsigned int use_callingpres
TRUE if we will use the calling presentation setting from the Asterisk channel for outgoing calls.
Definition: chan_dahdi.h:401
int dtmfrelax
Definition: chan_dahdi.h:726
unsigned int pulse
TRUE if we will pulse dial.
Definition: chan_dahdi.h:358
int dialtone_scanning_time_elapsed
Definition: chan_dahdi.h:676
unsigned int priexclusive
TRUE if PRI B channels are always exclusively selected.
Definition: chan_dahdi.h:353
char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Voice mailbox location.
Definition: chan_dahdi.h:715
float hwrxgain
Hardware Rx gain set by chan_dahdi.conf.
Definition: chan_dahdi.h:154
int echotraining
Echo training time. 0 = disabled.
Definition: chan_dahdi.h:640
int tonezone
Definition: chan_dahdi.h:167
char callwait_num[AST_MAX_EXTENSION]
Call waiting number.
Definition: chan_dahdi.h:547
float hwtxgain
Hardware Tx gain set by chan_dahdi.conf.
Definition: chan_dahdi.h:156
int waitfordialtoneduration
Transient variable. Stored off waitfordialtone duration at runtime.
Definition: chan_dahdi.h:670
int dsp_features
DSP feature flags: DSP_FEATURE_xxx.
Definition: chan_dahdi.h:744
unsigned int callwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition: chan_dahdi.h:226
char exten[AST_MAX_EXTENSION]
Extension to use in the dialplan.
Definition: chan_dahdi.h:508
int callprogress
Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
Definition: chan_dahdi.h:657
int callwaitcas
TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
Definition: chan_dahdi.h:628
time_t guardtime
Definition: chan_dahdi.h:593
struct timeval polaritydelaytv
Start delay time if polarityonanswerdelay is nonzero.
Definition: chan_dahdi.h:735
unsigned int hanguponpolarityswitch
TRUE if the call will be considered "hung up" on a polarity reversal.
Definition: chan_dahdi.h:285
char dnid[AST_MAX_EXTENSION]
Dialed Number Identifier.
Definition: chan_dahdi.h:553
char dialstring[AST_CHANNEL_NAME]
Definition: chan_dahdi.h:778
unsigned int callwaitingdeluxe
TRUE if Call Waiting Deluxe options should be available.
Definition: chan_dahdi.h:338
char call_forward[AST_MAX_EXTENSION]
Accumulated call forwarding number.
Definition: chan_dahdi.h:710
char description[32]
A description for the channel configuration.
Definition: chan_dahdi.h:502
unsigned int firstradio
TRUE if over a radio and dahdi_read() has been called.
Definition: chan_dahdi.h:280
unsigned int remotelyblocked
Bitmask for the channel being remotely blocked. 1 maintenance, 2 blocked in hardware.
Definition: chan_dahdi.h:466
struct dahdi_pvt::@115 echocancel
Echo cancel parameters.
unsigned int hidecallerid
TRUE if the outgoing caller ID is blocked/hidden.
Definition: chan_dahdi.h:302
unsigned int echobreak
XXX BOOLEAN Purpose???
Definition: chan_dahdi.h:264
struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS]
Definition: chan_dahdi.h:634
int faxbuf_no
Definition: chan_dahdi.h:141
unsigned int callreturn
TRUE if call return is enabled. (*69, if your dialplan doesn't catch this first)
Definition: chan_dahdi.h:219
struct ast_namedgroups * named_pickupgroups
Named pickup groups this belongs to.
Definition: chan_dahdi.h:585
struct ast_channel * owner
Definition: chan_dahdi.h:127
char rdnis[AST_MAX_EXTENSION]
Redirecting Directory Number Information Service (RDNIS) number.
Definition: chan_dahdi.h:551
unsigned int faxhandled
TRUE if a fax tone has already been handled.
Definition: chan_dahdi.h:274
unsigned int use_smdi
TRUE if SMDI (Simplified Message Desk Interface) is enabled.
Definition: chan_dahdi.h:485
struct callerid_state * cs
Definition: chan_dahdi.h:126
int cid_ani2
Automatic Number Identification code from PRI.
Definition: chan_dahdi.h:530
struct ast_namedgroups * named_callgroups
Named call groups this belongs to.
Definition: chan_dahdi.h:580
int callwaitrings
Number of call waiting rings.
Definition: chan_dahdi.h:630
unsigned int mwimonitor_neon
TRUE if the FXO port monitors for neon type MWI indications from the other end.
Definition: chan_dahdi.h:422
unsigned int dialednone
TRUE if analog type line dialed no digits in Dial()
Definition: chan_dahdi.h:253
unsigned int hwrxgain_enabled
TRUE if hardware Rx gain set by Asterisk.
Definition: chan_dahdi.h:473
int law_default
Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition: chan_dahdi.h:560
int fake_event
Holding place for event injected from outside normal operation.
Definition: chan_dahdi.h:728
unsigned int didtdd
Definition: chan_dahdi.h:251
char echorest[20]
Filled with 'w'. XXX Purpose??
Definition: chan_dahdi.h:642
struct dahdi_pvt * slaves[MAX_SLAVES]
Definition: chan_dahdi.h:134
void * sig_pvt
Definition: chan_dahdi.h:770
int confno
Definition: chan_dahdi.h:563
unsigned int ani_timeout
INTEGER, length of ANI failure timeout in ms.
Definition: chan_dahdi.h:195
int dtmfcid_holdoff_state
Definition: chan_dahdi.h:596
unsigned int lastnumredial
TRUE if last number redial enabled.
Definition: chan_dahdi.h:448
unsigned int mwioverride_active
TRUE if a manual MWI override is active for a channel.
Definition: chan_dahdi.h:439
unsigned int mwimonitor_fsk
TRUE if the FXO port monitors for fsk type MWI indications from the other end.
Definition: chan_dahdi.h:427
int ringt_base
Ring timeout base.
Definition: chan_dahdi.h:614
int cid_start
Definition: chan_dahdi.h:595
unsigned int destroy
TRUE if the channel is to be destroyed on hangup. (Used by pseudo channels.)
Definition: chan_dahdi.h:250
unsigned int restrictcid
TRUE if caller ID is restricted.
Definition: chan_dahdi.h:367
char defcontext[AST_MAX_CONTEXT]
Default distinctive ring context.
Definition: chan_dahdi.h:506
unsigned int priindication_oob
TRUE if PRI congestion/busy indications are sent out-of-band.
Definition: chan_dahdi.h:348
unsigned int ani_info_digits
INTEGER, number of ANI INFO digits on a CAMA trunk. older switches use 1 INFO digit,...
Definition: chan_dahdi.h:190
unsigned int busydetect
TRUE if busy detection is enabled. (Listens for the beep-beep busy pattern.)
Definition: chan_dahdi.h:206
unsigned int hidecalleridname
TRUE if hide just the name not the number for legacy PBX use.
Definition: chan_dahdi.h:308
struct timeval waitingfordt
Definition: chan_dahdi.h:697
struct ast_dsp * dsp
Opaque DSP configuration structure.
Definition: chan_dahdi.h:700
struct dahdi_pvt * prev
Definition: chan_dahdi.h:170
ast_group_t pickupgroup
Bitmapped pickup groups this belongs to.
Definition: chan_dahdi.h:575
int callingpres
Definition: chan_dahdi.h:598
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:605
char context[AST_MAX_CONTEXT]
The configured context for incoming calls.
Definition: chan_dahdi.h:497
unsigned int cancallforward
TRUE if support for call forwarding enabled. Dial *72 to enable call forwarding. Dial *73 to disable ...
Definition: chan_dahdi.h:238
int radio
Nonzero if the signaling type is sent over a radio.
Definition: chan_dahdi.h:148
char parkinglot[AST_MAX_EXTENSION]
Definition: chan_dahdi.h:524
int cidcwexpire
Definition: chan_dahdi.h:600
unsigned int hardwaredtmf
TRUE if DTMF detection needs to be done by hardware.
Definition: chan_dahdi.h:295
int callwaitingrepeat
Definition: chan_dahdi.h:599
char begindigit
DTMF digit in progress. 0 when no digit in progress.
Definition: chan_dahdi.h:767
struct ast_cc_config_params * cc_params
Definition: chan_dahdi.h:771
unsigned int mate
TRUE if TDD in MATE mode.
Definition: chan_dahdi.h:326
float txgain
Software Tx gain set by chan_dahdi.conf.
Definition: chan_dahdi.h:162
int firstdigit_timeout
Time (ms) to detect first digit (in an analog phone)
Definition: chan_dahdi.h:686
int amaflags
Definition: chan_dahdi.h:707
struct dahdi_echocanparams head
Definition: chan_dahdi.h:633
unsigned int echocanbridged
TRUE if echo cancellation enabled when bridged.
Definition: chan_dahdi.h:270
int cid_signalling
Definition: chan_dahdi.h:594
char finaldial[64]
Second part of SIG_FEATDMF_TA wink operation.
Definition: chan_dahdi.h:705
unsigned int transfer
TRUE if call transfer is enabled.
Definition: chan_dahdi.h:386
unsigned int transfertobusy
TRUE if allowed to flash-transfer to busy channels.
Definition: chan_dahdi.h:417
int buf_no
Definition: chan_dahdi.h:139
unsigned int inalarm
TRUE if in an alarm condition.
Definition: chan_dahdi.h:324
char cid_name[AST_MAX_EXTENSION]
Caller ID name from an incoming call.
Definition: chan_dahdi.h:541
ast_mutex_t lock
Definition: chan_dahdi.h:125
unsigned int inservice
TRUE if channel is out of reset and ready.
Definition: chan_dahdi.h:446
char language[MAX_LANGUAGE]
Language configured for calls.
Definition: chan_dahdi.h:513
unsigned int digital
TRUE if the transfer capability of the call is digital.
Definition: chan_dahdi.h:260
int channel
Definition: chan_dahdi.h:591
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_dahdi.h:706
unsigned int mwioverride_disposition
Manual MWI disposition (on/off)
Definition: chan_dahdi.h:441
struct ast_dsp_busy_pattern busy_cadence
Busy cadence pattern description.
Definition: chan_dahdi.h:652
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition: chan_dahdi.h:621
unsigned int pulsedial
TRUE if a pulsed digit was detected. (Pulse dial phone detected)
Definition: chan_dahdi.h:360
unsigned int calledsubscriberheld
TRUE if Called Subscriber held is enabled. This allows a single incoming call to hold a DAHDI channel...
Definition: chan_dahdi.h:213
int muting
TRUE if confrence is muted.
Definition: chan_dahdi.h:769
char cid_tag[AST_MAX_EXTENSION]
Caller ID tag from incoming call.
Definition: chan_dahdi.h:537
int matchdigit_timeout
Time (ms) to wait, in case of ambiguous match (in an analog phone)
Definition: chan_dahdi.h:696
char mohsuggest[MAX_MUSICCLASS]
Suggested music-on-hold class for peer channel to use for calls.
Definition: chan_dahdi.h:523
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition: chan_dahdi.h:394
float rxgain
Software Rx gain set by chan_dahdi.conf.
Definition: chan_dahdi.h:160
int polarity
Current line interface polarity. POLARITY_IDLE, POLARITY_REV.
Definition: chan_dahdi.h:742
ast_group_t callgroup
Bitmapped call groups this belongs to.
Definition: chan_dahdi.h:570
unsigned int dialing
TRUE if in the process of dialing digits or sending something.
Definition: chan_dahdi.h:258
unsigned int usefaxbuffers
Definition: chan_dahdi.h:276
char callwait_name[AST_MAX_EXTENSION]
Call waiting name.
Definition: chan_dahdi.h:549
char mohinterpret[MAX_MUSICCLASS]
The configured music-on-hold class to use for calls.
Definition: chan_dahdi.h:518
int dialtone_detect
Number of frames to watch for dialtone in incoming calls.
Definition: chan_dahdi.h:675
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition: chan_dahdi.h:488
int propconfno
Definition: chan_dahdi.h:565
int inconference
Definition: chan_dahdi.h:136
int cid_ton
Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise.
Definition: chan_dahdi.h:539
ast_group_t groupmatch
Definition: chan_dahdi.c:13828
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:11177
unsigned char buf[READ_SIZE]
Definition: chan_dahdi.c:11178
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