Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
chan_dahdi.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2008, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief DAHDI for Pseudo TDM
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * Connects to the DAHDI telephony library as well as
26 * libpri. Libpri is optional and needed only if you are
27 * going to use ISDN connections.
28 *
29 * You need to install libraries before you attempt to compile
30 * and install the DAHDI channel.
31 *
32 * \ingroup channel_drivers
33 *
34 * \todo Deprecate the "musiconhold" configuration option post 1.4
35 */
36
37/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
38 * \addtogroup configuration_file
39 */
40
41/*! \page chan_dahdi.conf chan_dahdi.conf
42 * \verbinclude chan_dahdi.conf.sample
43 */
44
45/*** MODULEINFO
46 <depend>dahdi</depend>
47 <depend>tonezone</depend>
48 <use type="module">res_smdi</use>
49 <use type="external">pri</use>
50 <use type="external">ss7</use>
51 <use type="external">openr2</use>
52 <support_level>core</support_level>
53 ***/
54
55#include "asterisk.h"
56
57#if defined(__NetBSD__) || defined(__FreeBSD__)
58#include <pthread.h>
59#else
60#include <sys/sysmacros.h>
61#endif
62#include <signal.h>
63#include <sys/stat.h>
64#include <math.h>
65
66#include "sig_analog.h"
67/* Analog signaling is currently still present in chan_dahdi for use with
68 * radio. Sig_analog does not currently handle any radio operations. If
69 * radio only uses analog signaling, then the radio handling logic could
70 * be placed in sig_analog and the duplicated code could be removed.
71 */
72
73#if defined(HAVE_PRI)
74#include "sig_pri.h"
75#ifndef PRI_RESTART
76#error "Upgrade your libpri"
77#endif
78#endif /* defined(HAVE_PRI) */
79
80#if defined(HAVE_SS7)
81#include "sig_ss7.h"
82#if !defined(LIBSS7_ABI_COMPATIBILITY)
83#error "Upgrade your libss7"
84#elif LIBSS7_ABI_COMPATIBILITY != 2
85#error "Your installed libss7 is not compatible"
86#endif
87#endif /* defined(HAVE_SS7) */
88
89#if defined(HAVE_OPENR2)
90/* put this here until sig_mfcr2 comes along */
91#define SIG_MFCR2_MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
92#endif /* defined(HAVE_OPENR2) */
93
94#include "asterisk/lock.h"
95#include "asterisk/channel.h"
96#include "asterisk/config.h"
97#include "asterisk/module.h"
98#include "asterisk/pbx.h"
99#include "asterisk/file.h"
100#include "asterisk/ulaw.h"
101#include "asterisk/alaw.h"
102#include "asterisk/callerid.h"
103#include "asterisk/adsi.h"
104#include "asterisk/cli.h"
105#include "asterisk/pickup.h"
106#include "asterisk/features.h"
107#include "asterisk/musiconhold.h"
108#include "asterisk/say.h"
109#include "asterisk/tdd.h"
110#include "asterisk/mwi.h"
111#include "asterisk/dsp.h"
112#include "asterisk/astdb.h"
113#include "asterisk/manager.h"
114#include "asterisk/causes.h"
115#include "asterisk/term.h"
116#include "asterisk/utils.h"
117#include "asterisk/transcap.h"
119#include "asterisk/abstract_jb.h"
120#include "asterisk/smdi.h"
121#include "asterisk/devicestate.h"
122#include "asterisk/paths.h"
123#include "asterisk/ccss.h"
125#include "asterisk/bridge.h"
127#include "asterisk/parking.h"
129#include "chan_dahdi.h"
131
132/*** DOCUMENTATION
133 <application name="DAHDISendKeypadFacility" language="en_US">
134 <since>
135 <version>1.4.22</version>
136 </since>
137 <synopsis>
138 Send digits out of band over a PRI.
139 </synopsis>
140 <syntax>
141 <parameter name="digits" required="true" />
142 </syntax>
143 <description>
144 <para>This application will send the given string of digits in a Keypad
145 Facility IE over the current channel.</para>
146 </description>
147 </application>
148 <application name="DAHDISendCallreroutingFacility" language="en_US">
149 <since>
150 <version>1.6.2.0</version>
151 </since>
152 <synopsis>
153 Send an ISDN call rerouting/deflection facility message.
154 </synopsis>
155 <syntax argsep=",">
156 <parameter name="destination" required="true">
157 <para>Destination number.</para>
158 </parameter>
159 <parameter name="original">
160 <para>Original called number.</para>
161 </parameter>
162 <parameter name="reason">
163 <para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
164 </parameter>
165 </syntax>
166 <description>
167 <para>This application will send an ISDN switch specific call
168 rerouting/deflection facility message over the current channel.
169 Supported switches depend upon the version of libpri in use.</para>
170 </description>
171 </application>
172 <application name="DAHDIAcceptR2Call" language="en_US">
173 <since>
174 <version>1.6.1.0</version>
175 </since>
176 <synopsis>
177 Accept an R2 call if its not already accepted (you still need to answer it)
178 </synopsis>
179 <syntax>
180 <parameter name="charge" required="true">
181 <para>Yes or No.</para>
182 <para>Whether you want to accept the call with charge or without charge.</para>
183 </parameter>
184 </syntax>
185 <description>
186 <para>This application will Accept the R2 call either with charge or no charge.</para>
187 </description>
188 </application>
189 <function name="POLARITY" language="en_US">
190 <since>
191 <version>16.28.0</version>
192 <version>18.14.0</version>
193 <version>19.6.0</version>
194 </since>
195 <synopsis>
196 Set or get the polarity of a DAHDI channel.
197 </synopsis>
198 <syntax />
199 <description>
200 <para>The POLARITY function can be used to set the polarity of a DAHDI channel.</para>
201 <para>Applies only to FXS channels (using FXO signalling) with supporting hardware.</para>
202 <para>The polarity can be set to the following numeric or named values:</para>
203 <enumlist>
204 <enum name="0" />
205 <enum name="idle" />
206 <enum name="1" />
207 <enum name="reverse" />
208 </enumlist>
209 <para>However, when read, the function will always return 0 or 1.</para>
210 <example title="Set idle polarity">
211 same => n,Set(POLARITY()=0)
212 </example>
213 <example title="Set reverse polarity">
214 same => n,NoOp(Current Polarity: ${POLARITY()})
215 same => n,Set(POLARITY()=reverse)
216 same => n,NoOp(New Polarity: ${POLARITY()})
217 </example>
218 <example title="Reverse the polarity from whatever it is currently">
219 same => n,Set(POLARITY()=${IF($[ "${POLARITY()}" = "1" ]?0:1)})
220 </example>
221 </description>
222 </function>
223 <function name="DAHDI_CHANNEL" language="en_US">
224 <synopsis>
225 Set or get a property of a DAHDI channel.
226 </synopsis>
227 <syntax>
228 <parameter name="property" required="true">
229 <para>The property to set or get.</para>
230 <enumlist>
231 <enum name="owner">
232 <para>R/O The name of the active channel on this DAHDI device.</para>
233 </enum>
234 <enum name="callwait">
235 <para>R/O The name of the call waiting channel on this DAHDI device.</para>
236 </enum>
237 <enum name="threeway">
238 <para>R/O The name of the three-way channel on this DAHDI device.</para>
239 </enum>
240 <enum name="polarity">
241 <para>R/W The polarity of the channel (0 or 1, idle or reverse can also be used for setting).</para>
242 <para>Only valid on FXO-signalled channels.</para>
243 </enum>
244 <enum name="dnd">
245 <para>R/W Whether Do Not Disturb is active.</para>
246 <para>Only valid on FXO-signalled channels.</para>
247 </enum>
248 <enum name="callforward">
249 <para>R/W The call forwarding target number.</para>
250 <para>Only valid on FXO-signalled channels.</para>
251 </enum>
252 <enum name="lastexten">
253 <para>R/W The last number dialed.</para>
254 <para>Only valid on FXO-signalled channels.</para>
255 </enum>
256 </enumlist>
257 </parameter>
258 <parameter name="channel" required="false">
259 <para>The DAHDI channel number.</para>
260 <para>If not specified, the DAHDI channel number of the current channel
261 will be used (in which case it must be a DAHDI channel).</para>
262 </parameter>
263 </syntax>
264 <description>
265 <para>The DAHDI_CHANNEL function can be used to set or get properties of DAHDI channels
266 that are not specific to Asterisk channels.</para>
267 <para>This function may also be called from non-DAHDI channels.</para>
268 <example title="Set reverse polarity on current DAHDI channel">
269 same => n,Set(DAHDI_CHANNEL(polarity)=1)
270 same => n,NoOp(${DAHDI_CHANNEL(polarity)})
271 </example>
272 <example title="Set call forwarding target for channel 1">
273 same => n,Set(DAHDI_CHANNEL(callforwardnumber,1)=5552368)
274 same => n,NoOp(Calls now forwarding to ${DAHDI_CHANNEL(callforwardnumber,1)})
275 </example>
276 </description>
277 </function>
278 <info name="CHANNEL" language="en_US" tech="DAHDI">
279 <enumlist>
280 <enum name="dahdi_channel">
281 <para>R/O DAHDI channel related to this channel.</para>
282 </enum>
283 <enum name="dahdi_span">
284 <para>R/O DAHDI span related to this channel.</para>
285 </enum>
286 <enum name="dahdi_group">
287 <para>R/O DAHDI logical group related to this channel.</para>
288 </enum>
289 <enum name="dahdi_type">
290 <para>R/O DAHDI channel type, one of:</para>
291 <enumlist>
292 <enum name="analog" />
293 <enum name="mfc/r2" />
294 <enum name="pri" />
295 <enum name="pseudo" />
296 <enum name="ss7" />
297 </enumlist>
298 </enum>
299 <enum name="keypad_digits">
300 <para>R/O PRI Keypad digits that came in with the SETUP message.</para>
301 </enum>
302 <enum name="reversecharge">
303 <para>R/O PRI Reverse Charging Indication, one of:</para>
304 <enumlist>
305 <enum name="-1"> <para>None</para></enum>
306 <enum name=" 1"> <para>Reverse Charging Requested</para></enum>
307 </enumlist>
308 </enum>
309 <enum name="no_media_path">
310 <para>R/O PRI Nonzero if the channel has no B channel.
311 The channel is either on hold or a call waiting call.</para>
312 </enum>
313 <enum name="buffers">
314 <para>W/O Change the channel's buffer policy (for the current call only)</para>
315 <para>This option takes two arguments:</para>
316 <para> Number of buffers,</para>
317 <para> Buffer policy being one of:</para>
318 <para> <literal>full</literal></para>
319 <para> <literal>immediate</literal></para>
320 <para> <literal>half</literal></para>
321 </enum>
322 <enum name="echocan_mode">
323 <para>W/O Change the configuration of the active echo
324 canceller on the channel (if any), for the current call
325 only.</para>
326 <para>Possible values are:</para>
327 <para> <literal>on</literal> Normal mode (the echo canceller is actually reinitialized)</para>
328 <para> <literal>off</literal> Disabled</para>
329 <para> <literal>fax</literal> FAX/data mode (NLP disabled if possible, otherwise
330 completely disabled)</para>
331 <para> <literal>voice</literal> Voice mode (returns from FAX mode, reverting the changes that were made)</para>
332 </enum>
333 <enum name="dialmode">
334 <para>R/W Pulse and tone dialing mode of the channel.</para>
335 <para>Disabling tone dialing using this option will not automatically disable the DSP used for DTMF detection.
336 To do that, also set the <literal>digitdetect</literal> option. If digit detection is disabled,
337 DTMF will not be detected, regardless of the <literal>dialmode</literal> setting.
338 The <literal>digitdetect</literal> setting has no impact on pulse dialing detection.</para>
339 <para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
340 <para>The <literal>dialmode</literal> setting applies to the DAHDI channel as a whole, but is reset for each call,
341 so modifications made using the <literal>CHANNEL</literal> function apply temporarily per-call.
342 The <literal>digitdetect</literal> setting applies to the entire DAHDI channel,
343 so any changes made to this setting will affect all calls concurrently on the same DAHDI channel.
344 <literal>digitdetect</literal> is reset once all calls on the line have cleared.</para>
345 <enumlist>
346 <enum name="both" />
347 <enum name="pulse" />
348 <enum name="dtmf" />
349 <enum name="tone" />
350 <enum name="none" />
351 </enumlist>
352 </enum>
353 <enum name="waitfordialtone">
354 <para>W/O Duration in ms for which to wait for dial tone on the current call.</para>
355 <para>This setting is will temporarily override the <literal>waitfordialtone</literal>
356 setting in <literal>chan_dahdi.conf</literal> (typically if that setting is disabled).
357 You must call this in a pre-dial handler when making a call on an analog trunk
358 (e.g. FXS-signalled interface).</para>
359 <para>This allows, for example, being able to barge in on an in-use trunk,
360 if dialed specifically, but allows skipping the trunk when routing calls
361 if dial tone is not present on a channel.</para>
362 <para>This setting will only apply to the current (next) call made on the
363 DAHDI channel, and will not persist for future calls.</para>
364 <para>Please keep in mind that due to the way that chan_dahdi implements dial tone detection,
365 DTMF digits on an in-use channel will temporarily relay to any other channels attempting to use the channel for a call.
366 However, voice transmission will not leak.</para>
367 </enum>
368 </enumlist>
369 </info>
370 <info name="Dial_Resource" language="en_US" tech="DAHDI">
371 <para>DAHDI allows several modifiers to be specified as part of the resource.</para>
372 <para>The general syntax is :</para>
373 <para><literal>Dial(DAHDI/pseudo[/extension])</literal></para>
374 <para><literal>Dial(DAHDI/&lt;channel#&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
375 <para><literal>Dial(DAHDI/(g|G|r|R)&lt;group#(0-63)&gt;[c|r&lt;cadence#&gt;|d][/extension])</literal></para>
376 <para>The following modifiers may be used before the channel number:</para>
377 <enumlist>
378 <enum name="g">
379 <para>Search forward, dialing on first available channel in group (lowest to highest).</para>
380 </enum>
381 <enum name="G">
382 <para>Search backward, dialing on first available channel in group (highest to lowest).</para>
383 </enum>
384 <enum name="r">
385 <para>Round robin search forward, picking up from where last left off (lowest to highest).</para>
386 </enum>
387 <enum name="R">
388 <para>Round robin search backward, picking up from where last left off (highest to lowest).</para>
389 </enum>
390 </enumlist>
391 <para>The following modifiers may be used after the channel number:</para>
392 <enumlist>
393 <enum name="c">
394 <para>Wait for DTMF digit <literal>#</literal> before providing answer supervision.</para>
395 <para>This can be useful on outbound calls via FXO ports, as otherwise
396 they would indicate answer immediately.</para>
397 </enum>
398 <enum name="d">
399 <para>Force bearer capability for ISDN/SS7 call to digital.</para>
400 </enum>
401 <enum name="i">
402 <para>ISDN span channel restriction.</para>
403 <para>Used by CC to ensure that the CC recall goes out the same span.
404 Also to make ISDN channel names dialable when the sequence number
405 is stripped off. (Used by DTMF attended transfer feature.)</para>
406 </enum>
407 <enum name="r">
408 <para>Specifies the distinctive ring cadence number to use immediately after
409 specifying this option. There are 4 default built-in cadences, and up to 24
410 total cadences may be configured.</para>
411 </enum>
412 </enumlist>
413 <example title="Dial 555-1212 on first available channel in group 1, searching from highest to lowest">
414 same => n,Dial(DAHDI/g1/5551212)
415 </example>
416 <example title="Ringing FXS channel 4 with ring cadence 2">
417 same => n,Dial(DAHDI/4r2)
418 </example>
419 <example title="Dial 555-1212 on channel 3 and require answer confirmation">
420 same => n,Dial(DAHDI/3c/5551212)
421 </example>
422 </info>
423 <manager name="DAHDITransfer" language="en_US">
424 <since>
425 <version>1.4.22</version>
426 </since>
427 <synopsis>
428 Transfer DAHDI Channel.
429 </synopsis>
430 <syntax>
431 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
432 <parameter name="DAHDIChannel" required="true">
433 <para>DAHDI channel number to transfer.</para>
434 </parameter>
435 </syntax>
436 <description>
437 <para>Simulate a flash hook event by the user connected to the channel.</para>
438 <note><para>Valid only for analog channels.</para></note>
439 </description>
440 </manager>
441 <manager name="DAHDIHangup" language="en_US">
442 <since>
443 <version>1.4.22</version>
444 </since>
445 <synopsis>
446 Hangup DAHDI Channel.
447 </synopsis>
448 <syntax>
449 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
450 <parameter name="DAHDIChannel" required="true">
451 <para>DAHDI channel number to hangup.</para>
452 </parameter>
453 </syntax>
454 <description>
455 <para>Simulate an on-hook event by the user connected to the channel.</para>
456 <note><para>Valid only for analog channels.</para></note>
457 </description>
458 </manager>
459 <manager name="DAHDIDialOffhook" language="en_US">
460 <since>
461 <version>1.4.22</version>
462 </since>
463 <synopsis>
464 Dial over DAHDI channel while offhook.
465 </synopsis>
466 <syntax>
467 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
468 <parameter name="DAHDIChannel" required="true">
469 <para>DAHDI channel number to dial digits.</para>
470 </parameter>
471 <parameter name="Number" required="true">
472 <para>Digits to dial.</para>
473 </parameter>
474 </syntax>
475 <description>
476 <para>Generate DTMF control frames to the bridged peer.</para>
477 </description>
478 </manager>
479 <manager name="DAHDIDNDon" language="en_US">
480 <since>
481 <version>1.4.22</version>
482 </since>
483 <synopsis>
484 Toggle DAHDI channel Do Not Disturb status ON.
485 </synopsis>
486 <syntax>
487 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
488 <parameter name="DAHDIChannel" required="true">
489 <para>DAHDI channel number to set DND on.</para>
490 </parameter>
491 </syntax>
492 <description>
493 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> on".</para>
494 <note><para>Feature only supported by analog channels.</para></note>
495 </description>
496 </manager>
497 <manager name="DAHDIDNDoff" language="en_US">
498 <since>
499 <version>1.4.22</version>
500 </since>
501 <synopsis>
502 Toggle DAHDI channel Do Not Disturb status OFF.
503 </synopsis>
504 <syntax>
505 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
506 <parameter name="DAHDIChannel" required="true">
507 <para>DAHDI channel number to set DND off.</para>
508 </parameter>
509 </syntax>
510 <description>
511 <para>Equivalent to the CLI command "dahdi set dnd <variable>channel</variable> off".</para>
512 <note><para>Feature only supported by analog channels.</para></note>
513 </description>
514 </manager>
515 <manager name="DAHDIShowChannels" language="en_US">
516 <since>
517 <version>1.4.22</version>
518 </since>
519 <synopsis>
520 Show status of DAHDI channels.
521 </synopsis>
522 <syntax>
523 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
524 <parameter name="DAHDIChannel">
525 <para>Specify the specific channel number to show. Show all channels if zero or not present.</para>
526 </parameter>
527 </syntax>
528 <description>
529 <para>Similar to the CLI command "dahdi show channels".</para>
530 </description>
531 </manager>
532 <manager name="DAHDIShowStatus" language="en_US">
533 <since>
534 <version>21.3.0</version>
535 <version>20.8.0</version>
536 <version>18.23.0</version>
537 </since>
538 <synopsis>
539 Show status of DAHDI spans.
540 </synopsis>
541 <syntax/>
542 <description>
543 <para>Similar to the CLI command "dahdi show status".</para>
544 </description>
545 </manager>
546 <manager name="DAHDIRestart" language="en_US">
547 <since>
548 <version>1.4.22</version>
549 </since>
550 <synopsis>
551 Fully Restart DAHDI channels (terminates calls).
552 </synopsis>
553 <syntax>
554 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
555 </syntax>
556 <description>
557 <para>Equivalent to the CLI command "dahdi restart".</para>
558 </description>
559 </manager>
560 <manager name="PRIShowSpans" language="en_US">
561 <since>
562 <version>10.0.0</version>
563 </since>
564 <synopsis>
565 Show status of PRI spans.
566 </synopsis>
567 <syntax>
568 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
569 <parameter name="Span">
570 <para>Specify the specific span to show. Show all spans if zero or not present.</para>
571 </parameter>
572 </syntax>
573 <description>
574 <para>Similar to the CLI command "pri show spans".</para>
575 </description>
576 </manager>
577 <manager name="PRIDebugSet" language="en_US">
578 <since>
579 <version>13.0.0</version>
580 </since>
581 <synopsis>
582 Set PRI debug levels for a span
583 </synopsis>
584 <syntax>
585 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
586 <parameter name="Span" required="true">
587 <para>Which span to affect.</para>
588 </parameter>
589 <parameter name="Level" required="true">
590 <para>What debug level to set. May be a numerical value or a text value from the list below</para>
591 <enumlist>
592 <enum name="off" />
593 <enum name="on" />
594 <enum name="hex" />
595 <enum name="intense" />
596 </enumlist>
597 </parameter>
598 </syntax>
599 <description>
600 <para>Equivalent to the CLI command "pri set debug &lt;level&gt; span &lt;span&gt;".</para>
601 </description>
602 </manager>
603 <manager name="PRIDebugFileSet" language="en_US">
604 <since>
605 <version>13.0.0</version>
606 </since>
607 <synopsis>
608 Set the file used for PRI debug message output
609 </synopsis>
610 <syntax>
611 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
612 <parameter name="File" required="true">
613 <para>Path of file to write debug output.</para>
614 </parameter>
615 </syntax>
616 <description>
617 <para>Equivalent to the CLI command "pri set debug file &lt;output-file&gt;"</para>
618 </description>
619 </manager>
620 <manager name="PRIDebugFileUnset" language="en_US">
621 <since>
622 <version>13.0.0</version>
623 </since>
624 <synopsis>
625 Disables file output for PRI debug messages
626 </synopsis>
627 <syntax>
628 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
629 </syntax>
630 </manager>
631 <managerEvent language="en_US" name="AlarmClear">
632 <managerEventInstance class="EVENT_FLAG_SYSTEM">
633 <since>
634 <version>12.0.0</version>
635 </since>
636 <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
637 <syntax>
638 <parameter name="DAHDIChannel">
639 <para>The DAHDI channel on which the alarm was cleared.</para>
640 <note><para>This is not an Asterisk channel identifier.</para></note>
641 </parameter>
642 </syntax>
643 </managerEventInstance>
644 </managerEvent>
645 <managerEvent language="en_US" name="SpanAlarmClear">
646 <managerEventInstance class="EVENT_FLAG_SYSTEM">
647 <since>
648 <version>12.0.0</version>
649 </since>
650 <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
651 <syntax>
652 <parameter name="Span">
653 <para>The span on which the alarm was cleared.</para>
654 </parameter>
655 </syntax>
656 </managerEventInstance>
657 </managerEvent>
658 <managerEvent language="en_US" name="DNDState">
659 <managerEventInstance class="EVENT_FLAG_SYSTEM">
660 <since>
661 <version>12.0.0</version>
662 </since>
663 <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
664 <syntax>
665 <parameter name="DAHDIChannel">
666 <para>The DAHDI channel on which DND status changed.</para>
667 <note><para>This is not an Asterisk channel identifier.</para></note>
668 </parameter>
669 <parameter name="Status">
670 <enumlist>
671 <enum name="enabled"/>
672 <enum name="disabled"/>
673 </enumlist>
674 </parameter>
675 </syntax>
676 </managerEventInstance>
677 </managerEvent>
678 <managerEvent language="en_US" name="Alarm">
679 <managerEventInstance class="EVENT_FLAG_SYSTEM">
680 <since>
681 <version>12.0.0</version>
682 </since>
683 <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
684 <syntax>
685 <parameter name="DAHDIChannel">
686 <para>The channel on which the alarm occurred.</para>
687 <note><para>This is not an Asterisk channel identifier.</para></note>
688 </parameter>
689 <parameter name="Alarm">
690 <para>A textual description of the alarm that occurred.</para>
691 </parameter>
692 </syntax>
693 </managerEventInstance>
694 </managerEvent>
695 <managerEvent language="en_US" name="SpanAlarm">
696 <managerEventInstance class="EVENT_FLAG_SYSTEM">
697 <since>
698 <version>12.0.0</version>
699 </since>
700 <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
701 <syntax>
702 <parameter name="Span">
703 <para>The span on which the alarm occurred.</para>
704 </parameter>
705 <parameter name="Alarm">
706 <para>A textual description of the alarm that occurred.</para>
707 </parameter>
708 </syntax>
709 </managerEventInstance>
710 </managerEvent>
711 <managerEvent language="en_US" name="DAHDIChannel">
712 <managerEventInstance class="EVENT_FLAG_CALL">
713 <since>
714 <version>12.0.0</version>
715 </since>
716 <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
717 <syntax>
718 <channel_snapshot/>
719 <parameter name="DAHDIGroup">
720 <para>The DAHDI logical group associated with this channel.</para>
721 </parameter>
722 <parameter name="DAHDISpan">
723 <para>The DAHDI span associated with this channel.</para>
724 </parameter>
725 <parameter name="DAHDIChannel">
726 <para>The DAHDI channel associated with this channel.</para>
727 </parameter>
728 </syntax>
729 </managerEventInstance>
730 </managerEvent>
731 ***/
732
733#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
734
735static const char * const lbostr[] = {
736"0 db (CSU)/0-133 feet (DSX-1)",
737"133-266 feet (DSX-1)",
738"266-399 feet (DSX-1)",
739"399-533 feet (DSX-1)",
740"533-655 feet (DSX-1)",
741"-7.5db (CSU)",
742"-15db (CSU)",
743"-22.5db (CSU)"
744};
745
746/*! Global jitterbuffer configuration - by default, jb is disabled
747 * \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
749{
750 .flags = 0,
751 .max_size = 200,
752 .resync_threshold = 1000,
753 .impl = "fixed",
754 .target_extra = 40,
755};
757
758/*!
759 * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
760 * the user hangs up to reset the state machine so ring works properly.
761 * This is used to be able to support kewlstart by putting the zhone in
762 * groundstart mode since their forward disconnect supervision is entirely
763 * broken even though their documentation says it isn't and their support
764 * is entirely unwilling to provide any assistance with their channel banks
765 * even though their web site says they support their products for life.
766 */
767/* #define ZHONE_HACK */
768
769/*! \brief Typically, how many rings before we should send Caller*ID */
770#define DEFAULT_CIDRINGS 1
771
772#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw)
773
774
775/*! \brief Signaling types that need to use MF detection should be placed in this macro */
776#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
777
778/*! \brief Whether a channel is FXO signaled */
779#define IS_FXO_SIG(p) (((p)->sig == SIG_FXOKS) || ((p)->sig == SIG_FXOLS) || ((p)->sig == SIG_FXOGS))
780#define CHAN_IS_FXO_SIG(sig) (sig == SIG_FXOKS || sig == SIG_FXOLS || sig == SIG_FXOGS)
781
782static const char tdesc[] = "DAHDI Telephony"
783#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
784 " w/"
785 #if defined(HAVE_PRI)
786 "PRI"
787 #endif /* defined(HAVE_PRI) */
788 #if defined(HAVE_SS7)
789 #if defined(HAVE_PRI)
790 " & "
791 #endif /* defined(HAVE_PRI) */
792 "SS7"
793 #endif /* defined(HAVE_SS7) */
794 #if defined(HAVE_OPENR2)
795 #if defined(HAVE_PRI) || defined(HAVE_SS7)
796 " & "
797 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
798 "MFC/R2"
799 #endif /* defined(HAVE_OPENR2) */
800#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2) */
801;
802
803static const char config[] = "chan_dahdi.conf";
804
805#ifdef LOTS_OF_SPANS
806#define NUM_SPANS DAHDI_MAX_SPANS
807#else
808#define NUM_SPANS 32
809#endif
810
811#define CHAN_PSEUDO -2
812
813#define CALLPROGRESS_PROGRESS 1
814#define CALLPROGRESS_FAX_OUTGOING 2
815#define CALLPROGRESS_FAX_INCOMING 4
816#define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
817
818#define NUM_CADENCE_MAX 25
819static int num_cadence = 4;
821
822static int has_pseudo;
823
824static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
825 { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
826 { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
827 { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
828 { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
829};
830
831/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
832 * is 1, the second pause is 2 and so on.
833 */
834
836 2, /*!< Right after first long ring */
837 4, /*!< Right after long part */
838 3, /*!< After third chirp */
839 2, /*!< Second spell */
840};
841
842/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
843static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
844
845#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
846 (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
847
848#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
849#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
850
851static char defaultcic[64] = "";
852static char defaultozz[64] = "";
853
854/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
855static char mwimonitornotify[PATH_MAX] = "";
856#ifndef HAVE_DAHDI_LINEREVERSE_VMWI
857static int mwisend_rpas = 0;
858#endif
859
860static char progzone[10] = "";
861
864
865static int numbufs = 4;
866
867static int mwilevel = 512;
868static int dtmfcid_level = 256;
869
870#define REPORT_CHANNEL_ALARMS 1
871#define REPORT_SPAN_ALARMS 2
873
874#ifdef HAVE_PRI
875static int pridebugfd = -1;
876static char pridebugfilename[1024] = "";
877#endif
878
879/*! \brief Protect the interface list (of dahdi_pvt's) */
881
882
883static int ifcount = 0;
884
885#ifdef HAVE_PRI
886AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
887#endif
888
889/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
890 when it's doing something critical. */
892
893/*! \brief This is the thread for the monitor which checks for input on the channels
894 which are not currently in use. */
899static int ss_thread_count = 0;
900static int num_restart_pending = 0;
901
902static int restart_monitor(void);
903
904static int dahdi_sendtext(struct ast_channel *c, const char *text);
905
906/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
907static inline int dahdi_get_event(int fd)
908{
909 int j;
910 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
911 return -1;
912 return j;
913}
914
915/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
916static inline int dahdi_wait_event(int fd)
917{
918 int i, j = 0;
919 i = DAHDI_IOMUX_SIGEVENT;
920 if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
921 return -1;
922 if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
923 return -1;
924 return j;
925}
926
927/*! Chunk size to read -- we use 20ms chunks to make things happy. */
928#define READ_SIZE 160
929
930#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
931#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
932
933#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
934#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
935#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
936#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
937#define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
938#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
939#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
940
941/*!
942 * \brief Configured ring timeout base.
943 * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
944 */
946
947#if defined(HAVE_SS7)
948
949struct dahdi_ss7 {
950 struct sig_ss7_linkset ss7;
951};
952
953static struct dahdi_ss7 linksets[NUM_SPANS];
954
955static int cur_ss7type = -1;
956static int cur_slc = -1;
957static int cur_linkset = -1;
958static int cur_pointcode = -1;
959static int cur_cicbeginswith = -1;
960static int cur_adjpointcode = -1;
961static int cur_networkindicator = -1;
962static int cur_defaultdpc = -1;
963#endif /* defined(HAVE_SS7) */
964
965#ifdef HAVE_OPENR2
966struct dahdi_mfcr2_conf {
967 openr2_variant_t variant;
968 int mfback_timeout;
969 int metering_pulse_timeout;
970 int max_ani;
971 int max_dnis;
972#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
973 int dtmf_time_on;
974 int dtmf_time_off;
975#endif
976#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
977 int dtmf_end_timeout;
978#endif
979 signed int get_ani_first:2;
980#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
981 signed int skip_category_request:2;
982#endif
983 unsigned int call_files:1;
984 unsigned int allow_collect_calls:1;
985 unsigned int charge_calls:1;
986 unsigned int accept_on_offer:1;
987 unsigned int forced_release:1;
988 unsigned int double_answer:1;
989 signed int immediate_accept:2;
990#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
991 signed int dtmf_dialing:2;
992 signed int dtmf_detection:2;
993#endif
994 char logdir[OR2_MAX_PATH];
995 char r2proto_file[OR2_MAX_PATH];
996 openr2_log_level_t loglevel;
997 openr2_calling_party_category_t category;
998};
999
1000/* MFC-R2 pseudo-link structure */
1001struct dahdi_mfcr2 {
1002 int index; /*!< Unique index for CLI */
1003 pthread_t r2master; /*!< Thread of master */
1004 openr2_context_t *protocol_context; /*!< OpenR2 context handle */
1005 struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
1006 int numchans; /*!< Number of channels in this R2 block */
1007 int live_chans; /*!< Number of unremoved channels in this R2 block */
1008 int nodev; /*!< Link disconnected? */
1009 struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
1010};
1011
1012struct r2link_entry {
1013 struct dahdi_mfcr2 mfcr2;
1014 AST_LIST_ENTRY(r2link_entry) list;
1015};
1016static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
1017static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
1018
1019
1020/* how many r2links have been malloc'd */
1021static int r2links_count = 0;
1022
1023#endif /* HAVE_OPENR2 */
1024
1025#ifdef HAVE_PRI
1026
1027struct dahdi_pri {
1028 int dchannels[SIG_PRI_NUM_DCHANS]; /*!< What channel are the dchannels on */
1029 int mastertrunkgroup; /*!< What trunk group is our master */
1030 int prilogicalspan; /*!< Logical span number within trunk group */
1031 struct sig_pri_span pri;
1032};
1033
1034static struct dahdi_pri pris[NUM_SPANS];
1035
1036#if defined(HAVE_PRI_CCSS)
1037/*! DAHDI PRI CCSS agent and monitor type name. */
1038static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
1039#endif /* defined(HAVE_PRI_CCSS) */
1040
1041#else
1042/*! Shut up the compiler */
1043struct dahdi_pri;
1044#endif
1045
1046/* Polarity states */
1047#define POLARITY_IDLE 0
1048#define POLARITY_REV 1
1049
1050const char * const subnames[] = {
1051 "Real",
1052 "Callwait",
1053 "Threeway"
1054};
1055
1056static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */
1057static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */
1058
1059#if defined(HAVE_PRI)
1060struct doomed_pri {
1061 struct sig_pri_span *pri;
1062 AST_LIST_ENTRY(doomed_pri) list;
1063};
1064static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
1065
1066static void pri_destroy_span(struct sig_pri_span *pri);
1067
1068static struct dahdi_parms_pseudo {
1069 int buf_no; /*!< Number of buffers */
1070 int buf_policy; /*!< Buffer policy */
1071 int faxbuf_no; /*!< Number of Fax buffers */
1072 int faxbuf_policy; /*!< Fax buffer policy */
1073} dahdi_pseudo_parms;
1074#endif /* defined(HAVE_PRI) */
1075
1076/*! \brief Channel configuration from chan_dahdi.conf .
1077 * This struct is used for parsing the [channels] section of chan_dahdi.conf.
1078 * Generally there is a field here for every possible configuration item.
1079 *
1080 * The state of fields is saved along the parsing and whenever a 'channel'
1081 * statement is reached, the current dahdi_chan_conf is used to configure the
1082 * channel (struct dahdi_pvt)
1083 *
1084 * \see dahdi_chan_init for the default values.
1085 */
1088#ifdef HAVE_PRI
1089 struct dahdi_pri pri;
1090#endif
1091
1092#if defined(HAVE_SS7)
1093 struct dahdi_ss7 ss7;
1094#endif /* defined(HAVE_SS7) */
1095
1096#ifdef HAVE_OPENR2
1097 struct dahdi_mfcr2_conf mfcr2;
1098#endif
1099 struct dahdi_params timing;
1100 int is_sig_auto; /*!< Use channel signalling from DAHDI? */
1101 /*! Continue configuration even if a channel is not there. */
1103
1104 /*!
1105 * \brief The serial port to listen for SMDI data on
1106 * \note Set from the "smdiport" string read in from chan_dahdi.conf
1107 */
1109
1110 /*!
1111 * \brief Don't create channels below this number
1112 * \note by default is 0 (no limit)
1113 */
1115
1116 /*!
1117 * \brief Don't create channels above this number (infinity by default)
1118 * \note by default is 0 (special value that means "no limit").
1119 */
1121};
1122
1123/*! returns a new dahdi_chan_conf with default values (by-value) */
1125{
1126 /* recall that if a field is not included here it is initialized
1127 * to 0 or equivalent
1128 */
1129 struct dahdi_chan_conf conf = {
1130#ifdef HAVE_PRI
1131 .pri.pri = {
1132 .nsf = PRI_NSF_NONE,
1133 .switchtype = PRI_SWITCH_NI2,
1134 .dialplan = PRI_UNKNOWN + 1,
1135 .localdialplan = PRI_NATIONAL_ISDN + 1,
1136 .nodetype = PRI_CPE,
1137 .qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
1138
1139#if defined(HAVE_PRI_CCSS)
1140 .cc_ptmp_recall_mode = 1,/* specificRecall */
1141 .cc_qsig_signaling_link_req = 1,/* retain */
1142 .cc_qsig_signaling_link_rsp = 1,/* retain */
1143#endif /* defined(HAVE_PRI_CCSS) */
1144
1145 .minunused = 2,
1146 .idleext = "",
1147 .idledial = "",
1148 .internationalprefix = "",
1149 .nationalprefix = "",
1150 .localprefix = "",
1151 .privateprefix = "",
1152 .unknownprefix = "",
1153 .colp_send = SIG_PRI_COLP_UPDATE,
1154 .resetinterval = -1,
1155 },
1156#endif
1157#if defined(HAVE_SS7)
1158 .ss7.ss7 = {
1159 .called_nai = SS7_NAI_NATIONAL,
1160 .calling_nai = SS7_NAI_NATIONAL,
1161 .internationalprefix = "",
1162 .nationalprefix = "",
1163 .subscriberprefix = "",
1164 .unknownprefix = "",
1165 .networkroutedprefix = ""
1166 },
1167#endif /* defined(HAVE_SS7) */
1168#ifdef HAVE_OPENR2
1169 .mfcr2 = {
1170 .variant = OR2_VAR_ITU,
1171 .mfback_timeout = -1,
1172 .metering_pulse_timeout = -1,
1173 .max_ani = 10,
1174 .max_dnis = 4,
1175 .get_ani_first = -1,
1176#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
1177 .skip_category_request = -1,
1178#endif
1179 .call_files = 0,
1180 .allow_collect_calls = 0,
1181 .charge_calls = 1,
1182 .accept_on_offer = 1,
1183 .forced_release = 0,
1184 .double_answer = 0,
1185 .immediate_accept = -1,
1186#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
1187 .dtmf_dialing = -1,
1188 .dtmf_detection = -1,
1189 .dtmf_time_on = OR2_DEFAULT_DTMF_ON,
1190 .dtmf_time_off = OR2_DEFAULT_DTMF_OFF,
1191#endif
1192#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
1193 .dtmf_end_timeout = -1,
1194#endif
1195 .logdir = "",
1196 .r2proto_file = "",
1197 .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
1198 .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
1199 },
1200#endif
1201 .chan = {
1202 .context = "default",
1203 .immediatering = 1,
1204 .cid_num = "",
1205 .cid_name = "",
1206 .cid_tag = "",
1207 .mohinterpret = "default",
1208 .mohsuggest = "",
1209 .parkinglot = "",
1210 .transfertobusy = 1,
1211 .permdialmode = ANALOG_DIALMODE_BOTH,
1212
1213 .ani_info_digits = 2,
1214 .ani_wink_time = 1000,
1215 .ani_timeout = 10000,
1216
1217 .cid_signalling = CID_SIG_BELL,
1218 .cid_start = CID_START_RING,
1219 .dahditrcallerid = 0,
1220 .use_callerid = 1,
1221 .sig = -1,
1222 .outsigmod = -1,
1223
1224 .cid_rxgain = +5.0,
1225
1226 .tonezone = -1,
1227
1228 .echocancel.head.tap_length = 1,
1229
1230 .busycount = 3,
1231
1232 .accountcode = "",
1233
1234 .mailbox = "",
1235
1236#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
1237 .mwisend_fsk = 1,
1238#endif
1239 .polarityonanswerdelay = 600,
1240
1241 .sendcalleridafter = DEFAULT_CIDRINGS,
1242
1243 .buf_policy = DAHDI_POLICY_IMMEDIATE,
1244 .buf_no = numbufs,
1245 .usefaxbuffers = 0,
1246 .cc_params = ast_cc_config_params_init(),
1247 .firstdigit_timeout = ANALOG_FIRST_DIGIT_TIMEOUT,
1248 .interdigit_timeout = ANALOG_INTER_DIGIT_TIMEOUT,
1249 .matchdigit_timeout = ANALOG_MATCH_DIGIT_TIMEOUT,
1250 },
1251 .timing = {
1252 .prewinktime = -1,
1253 .preflashtime = -1,
1254 .winktime = -1,
1255 .flashtime = -1,
1256 .starttime = -1,
1257 .rxwinktime = -1,
1258 .rxflashtime = -1,
1259 .debouncetime = -1
1260 },
1261 .is_sig_auto = 1,
1262 .ignore_failed_channels = 1,
1263 .smdi_port = "/dev/ttyS0",
1264 };
1265
1266 return conf;
1267}
1268
1269
1270static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
1271 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
1272 const char *data, int *cause);
1273static int dahdi_digit_begin(struct ast_channel *ast, char digit);
1274static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
1275static int dahdi_sendtext(struct ast_channel *c, const char *text);
1276static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout);
1277static int dahdi_hangup(struct ast_channel *ast);
1278static int dahdi_answer(struct ast_channel *ast);
1279static struct ast_frame *dahdi_read(struct ast_channel *ast);
1280static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
1281static struct ast_frame *dahdi_exception(struct ast_channel *ast);
1282static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
1283static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1284static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
1285static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
1286static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
1287static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
1288static int dahdi_devicestate(const char *data);
1289static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
1290
1292 .type = "DAHDI",
1293 .description = tdesc,
1294 .requester = dahdi_request,
1295 .send_digit_begin = dahdi_digit_begin,
1296 .send_digit_end = dahdi_digit_end,
1297 .send_text = dahdi_sendtext,
1298 .call = dahdi_call,
1299 .hangup = dahdi_hangup,
1300 .answer = dahdi_answer,
1301 .read = dahdi_read,
1302 .write = dahdi_write,
1303 .exception = dahdi_exception,
1304 .indicate = dahdi_indicate,
1305 .fixup = dahdi_fixup,
1306 .setoption = dahdi_setoption,
1307 .queryoption = dahdi_queryoption,
1308 .func_channel_read = dahdi_func_read,
1309 .func_channel_write = dahdi_func_write,
1310 .devicestate = dahdi_devicestate,
1311 .cc_callback = dahdi_cc_callback,
1312};
1313
1314#define GET_CHANNEL(p) ((p)->channel)
1315
1317{
1318 switch (sig) {
1319 case SIG_FXOLS:
1320 return ANALOG_SIG_FXOLS;
1321 case SIG_FXOGS:
1322 return ANALOG_SIG_FXOGS;
1323 case SIG_FXOKS:
1324 return ANALOG_SIG_FXOKS;
1325 case SIG_FXSLS:
1326 return ANALOG_SIG_FXSLS;
1327 case SIG_FXSGS:
1328 return ANALOG_SIG_FXSGS;
1329 case SIG_FXSKS:
1330 return ANALOG_SIG_FXSKS;
1331 case SIG_EMWINK:
1332 return ANALOG_SIG_EMWINK;
1333 case SIG_EM:
1334 return ANALOG_SIG_EM;
1335 case SIG_EM_E1:
1336 return ANALOG_SIG_EM_E1;
1337 case SIG_FEATD:
1338 return ANALOG_SIG_FEATD;
1339 case SIG_FEATDMF:
1340 return ANALOG_SIG_FEATDMF;
1341 case SIG_E911:
1342 return SIG_E911;
1343 case SIG_FGC_CAMA:
1344 return ANALOG_SIG_FGC_CAMA;
1345 case SIG_FGC_CAMAMF:
1346 return ANALOG_SIG_FGC_CAMAMF;
1347 case SIG_FEATB:
1348 return ANALOG_SIG_FEATB;
1349 case SIG_SFWINK:
1350 return ANALOG_SIG_SFWINK;
1351 case SIG_SF:
1352 return ANALOG_SIG_SF;
1353 case SIG_SF_FEATD:
1354 return ANALOG_SIG_SF_FEATD;
1355 case SIG_SF_FEATDMF:
1356 return ANALOG_SIG_SF_FEATDMF;
1357 case SIG_FEATDMF_TA:
1358 return ANALOG_SIG_FEATDMF_TA;
1359 case SIG_SF_FEATB:
1360 return ANALOG_SIG_FEATB;
1361 default:
1362 return -1;
1363 }
1364}
1365
1366
1368{
1369 switch (tone) {
1371 return DAHDI_TONE_RINGTONE;
1373 return DAHDI_TONE_STUTTER;
1375 return DAHDI_TONE_CONGESTION;
1377 return DAHDI_TONE_DIALTONE;
1379 return DAHDI_TONE_DIALRECALL;
1380 case ANALOG_TONE_INFO:
1381 return DAHDI_TONE_INFO;
1382 default:
1383 return -1;
1384 }
1385}
1386
1387static int analogsub_to_dahdisub(enum analog_sub analogsub)
1388{
1389 int index;
1390
1391 switch (analogsub) {
1392 case ANALOG_SUB_REAL:
1393 index = SUB_REAL;
1394 break;
1396 index = SUB_CALLWAIT;
1397 break;
1399 index = SUB_THREEWAY;
1400 break;
1401 default:
1402 ast_log(LOG_ERROR, "Unidentified sub!\n");
1403 index = SUB_REAL;
1404 }
1405
1406 return index;
1407}
1408
1409/*!
1410 * \internal
1411 * \brief release all members on the doomed pris list
1412 * \since 13.0
1413 *
1414 * Called periodically by the monitor threads to release spans marked for
1415 * removal.
1416 */
1417static void release_doomed_pris(void)
1418{
1419#ifdef HAVE_PRI
1420 struct doomed_pri *entry;
1421
1422 AST_LIST_LOCK(&doomed_pris);
1423 while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
1424 /* The span destruction must be done with this lock not held */
1425 AST_LIST_UNLOCK(&doomed_pris);
1426 ast_debug(4, "Destroying span %d from doomed queue.\n",
1427 entry->pri->span);
1428 pri_destroy_span(entry->pri);
1429 ast_free(entry);
1430 AST_LIST_LOCK(&doomed_pris);
1431 }
1432 AST_LIST_UNLOCK(&doomed_pris);
1433#endif
1434}
1435
1436#ifdef HAVE_PRI
1437/*!
1438 * \brief Queue a span for destruction
1439 * \since 13.0
1440 *
1441 * \param pri the span to destroy
1442 *
1443 * Add a span to the list of spans to be destroyed later on
1444 * by the monitor thread. Allows destroying a span while holding its
1445 * lock.
1446 */
1447static void pri_queue_for_destruction(struct sig_pri_span *pri)
1448{
1449 struct doomed_pri *entry;
1450
1451 AST_LIST_LOCK(&doomed_pris);
1452 AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
1453 if (entry->pri == pri) {
1454 AST_LIST_UNLOCK(&doomed_pris);
1455 return;
1456 }
1457 }
1458 entry = ast_calloc(sizeof(struct doomed_pri), 1);
1459 if (!entry) {
1460 /* Nothing useful to do here. Panic? */
1461 ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
1462 AST_LIST_UNLOCK(&doomed_pris);
1463 return;
1464 }
1465 entry->pri = pri;
1466 ast_debug(4, "Queue span %d for destruction.\n", pri->span);
1467 AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
1468 AST_LIST_UNLOCK(&doomed_pris);
1469}
1470#endif
1471
1472/*!
1473 * \internal
1474 * \brief Send a dial string to DAHDI.
1475 * \since 12.0.0
1476 *
1477 * \param pvt DAHDI private pointer
1478 * \param operation DAHDI dial operation to do to string
1479 * \param dial_str Dial string to send
1480 *
1481 * \retval 0 on success.
1482 * \retval non-zero on error.
1483 */
1484static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
1485{
1486 int res;
1487 int offset;
1488 const char *pos;
1489 struct dahdi_dialoperation zo = {
1490 .op = operation,
1491 };
1492
1493 /* Convert the W's to ww. */
1494 pos = dial_str;
1495 for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
1496 if (!*pos) {
1497 break;
1498 }
1499 if (*pos == 'W') {
1500 /* Convert 'W' to "ww" */
1501 ++pos;
1502 if (offset >= sizeof(zo.dialstr) - 3) {
1503 /* No room to expand */
1504 break;
1505 }
1506 zo.dialstr[offset] = 'w';
1507 ++offset;
1508 zo.dialstr[offset] = 'w';
1509 continue;
1510 }
1511 zo.dialstr[offset] = *pos++;
1512 }
1513 /* The zo initialization has already terminated the dialstr. */
1514
1515 ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
1516 pvt->channel, dial_str, zo.dialstr);
1517 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
1518 if (res) {
1519 ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
1520 pvt->channel, dial_str, strerror(errno));
1521 }
1522
1523 return res;
1524}
1525
1527static int bump_gains(struct dahdi_pvt *p);
1528static int dahdi_setlinear(int dfd, int linear);
1529
1530static int my_start_cid_detect(void *pvt, int cid_signalling)
1531{
1532 struct dahdi_pvt *p = pvt;
1533 int index = SUB_REAL;
1535 if (!p->cs) {
1536 ast_log(LOG_ERROR, "Unable to alloc callerid\n");
1537 return -1;
1538 }
1539 bump_gains(p);
1540 dahdi_setlinear(p->subs[index].dfd, 0);
1541
1542 return 0;
1543}
1544
1545static int restore_gains(struct dahdi_pvt *p);
1546
1547static int my_stop_cid_detect(void *pvt)
1548{
1549 struct dahdi_pvt *p = pvt;
1550 int index = SUB_REAL;
1551
1552 if (p->cs) {
1553 callerid_free(p->cs);
1554 }
1555
1556 /* Restore linear mode after Caller*ID processing */
1557 dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
1558 restore_gains(p);
1559
1560 return 0;
1561}
1562
1563static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
1564{
1565 struct dahdi_pvt *p = pvt;
1566 struct analog_pvt *analog_p = p->sig_pvt;
1567 struct pollfd poller;
1568 char *name, *num;
1569 int index = SUB_REAL;
1570 int res;
1571 unsigned char buf[256];
1572 int flags;
1573 int redirecting;
1574
1575 poller.fd = p->subs[SUB_REAL].dfd;
1576 poller.events = POLLPRI | POLLIN;
1577 poller.revents = 0;
1578
1579 res = poll(&poller, 1, timeout);
1580
1581 if (poller.revents & POLLPRI) {
1583 return 1;
1584 }
1585
1586 if (poller.revents & POLLIN) {
1587 /*** NOTES ***/
1588 /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
1589 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
1590 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
1591 * a failure and die, and returning 2 means no event was received. */
1592 res = read(p->subs[index].dfd, buf, sizeof(buf));
1593 if (res < 0) {
1594 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1595 return -1;
1596 }
1597
1598 if (analog_p->ringt > 0) {
1599 if (!(--analog_p->ringt)) {
1600 /* only return if we timeout from a ring event */
1601 return -1;
1602 }
1603 }
1604
1605 if (p->cid_signalling == CID_SIG_V23_JP) {
1606 res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
1607 } else {
1608 res = callerid_feed(p->cs, buf, res, AST_LAW(p));
1609 }
1610 if (res < 0) {
1611 /*
1612 * The previous diagnostic message output likely
1613 * explains why it failed.
1614 */
1615 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
1616 return -1;
1617 }
1618
1619 if (res == 1) {
1620 struct ast_channel *chan = analog_p->ss_astchan;
1622 if (name)
1624 if (num)
1625 ast_copy_string(numbuf, num, ANALOG_MAX_CID);
1626
1628 /* If we got a presentation, we must set it on the channel */
1629 struct ast_party_caller caller;
1630
1632 caller.id.name.presentation = caller.id.number.presentation = (flags & CID_PRIVATE_NUMBER) ?
1635 ast_party_caller_free(&caller);
1636 }
1637 if (redirecting) {
1638 /* There is a redirecting reason available in the Caller*ID received.
1639 * No idea what the redirecting number is, since the Caller*ID protocol
1640 * has no parameter for that, but at least we know WHY it was redirected. */
1641 ast_channel_redirecting(chan)->reason.code = redirecting;
1642 }
1643
1644 if (flags & CID_QUALIFIER) {
1645 /* This is the inverse of how the qualifier is set in sig_analog */
1646 pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
1647 }
1648
1649 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));
1650 return 0;
1651 }
1652 }
1653
1654 *ev = ANALOG_EVENT_NONE;
1655 return 2;
1656}
1657
1658static const char *event2str(int event);
1659
1660static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
1661{
1662 unsigned char buf[256];
1663 int distMatches;
1664 int curRingData[RING_PATTERNS];
1665 int receivedRingT;
1666 int counter1;
1667 int counter;
1668 int i;
1669 int res;
1670 int checkaftercid = 0;
1671 const char *matched_context;
1672 struct dahdi_pvt *p = pvt;
1673 struct analog_pvt *analog_p = p->sig_pvt;
1674
1675 if (ringdata == NULL) {
1676 ringdata = curRingData;
1677 } else {
1678 checkaftercid = 1;
1679 }
1680
1681 /* We must have a ring by now so lets try to listen for distinctive ringing */
1682 if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
1683 /* Clear the current ring data array so we don't have old data in it. */
1684 for (receivedRingT = 0; receivedRingT < RING_PATTERNS; receivedRingT++)
1685 ringdata[receivedRingT] = 0;
1686 receivedRingT = 0;
1687
1688 if (checkaftercid && distinctiveringaftercid) {
1689 ast_verb(3, "Detecting post-CID distinctive ring\n");
1690 }
1691
1692 for (;;) {
1693 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
1694 res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i);
1695 if (res) {
1696 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
1697 ast_hangup(chan);
1698 return 1;
1699 }
1700 if (i & DAHDI_IOMUX_SIGEVENT) {
1701 res = dahdi_get_event(p->subs[idx].dfd);
1702 ast_debug(3, "Got event %d (%s)...\n", res, event2str(res));
1703 if (res == DAHDI_EVENT_NOALARM) {
1704 p->inalarm = 0;
1705 analog_p->inalarm = 0;
1706 } else if (res == DAHDI_EVENT_RINGOFFHOOK) {
1707 /* Let us detect distinctive ring */
1708 ringdata[receivedRingT] = analog_p->ringt;
1709
1710 if (analog_p->ringt < analog_p->ringt_base / 2) {
1711 break;
1712 }
1713 /* Increment the ringT counter so we can match it against
1714 values in chan_dahdi.conf for distinctive ring */
1715 if (++receivedRingT == RING_PATTERNS) {
1716 break;
1717 }
1718 }
1719 } else if (i & DAHDI_IOMUX_READ) {
1720 res = read(p->subs[idx].dfd, buf, sizeof(buf));
1721 if (res < 0) {
1722 if (errno != ELAST) {
1723 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
1724 ast_hangup(chan);
1725 return 1;
1726 }
1727 break;
1728 }
1729 if (analog_p->ringt > 0) {
1730 if (!(--analog_p->ringt)) {
1731 break;
1732 }
1733 }
1734 }
1735 }
1736 }
1737
1738 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
1739 ast_verb(3, "Detected ring pattern: %d,%d,%d\n", ringdata[0], ringdata[1], ringdata[2]);
1740 matched_context = p->defcontext;
1741 for (counter = 0; counter < 3; counter++) {
1742 int range = p->drings.ringnum[counter].range;
1743
1744 distMatches = 0;
1745 ast_verb(3, "Checking %d,%d,%d with +/- %d range\n",
1746 p->drings.ringnum[counter].ring[0],
1747 p->drings.ringnum[counter].ring[1],
1748 p->drings.ringnum[counter].ring[2],
1749 range);
1750 for (counter1 = 0; counter1 < 3; counter1++) {
1751 int ring = p->drings.ringnum[counter].ring[counter1];
1752
1753 if (ring == -1) {
1754 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
1755 ringdata[counter1]);
1756 distMatches++;
1757 } else if (ring - range <= ringdata[counter1] && ringdata[counter1] <= ring + range) {
1758 ast_verb(3, "Ring pattern %d is in range: %d to %d\n",
1759 ringdata[counter1], ring - range, ring + range);
1760 distMatches++;
1761 } else {
1762 /* The current dring pattern cannot match. */
1763 break;
1764 }
1765 }
1766
1767 if (distMatches == 3) {
1768 /* The ring matches, set the context to whatever is for distinctive ring.. */
1769 matched_context = S_OR(p->drings.ringContext[counter].contextData, p->defcontext);
1770 ast_verb(3, "Matched Distinctive Ring context %s\n", matched_context);
1771 break;
1772 }
1773 }
1774
1775 /* Set selected distinctive ring context if not already set. */
1776 if (strcmp(p->context, matched_context) != 0) {
1777 ast_copy_string(p->context, matched_context, sizeof(p->context));
1778 ast_channel_context_set(chan, matched_context);
1779 }
1780
1781 return 0;
1782}
1783
1784static int my_stop_callwait(void *pvt)
1785{
1786 struct dahdi_pvt *p = pvt;
1787 p->callwaitingrepeat = 0;
1788 p->cidcwexpire = 0;
1789 p->cid_suppress_expire = 0;
1790
1791 return 0;
1792}
1793
1794static int send_callerid(struct dahdi_pvt *p);
1795static int save_conference(struct dahdi_pvt *p);
1796static int restore_conference(struct dahdi_pvt *p);
1797
1798static int my_callwait(void *pvt)
1799{
1800 struct dahdi_pvt *p = pvt;
1801
1803 if (p->cidspill) {
1804 ast_log(LOG_WARNING, "Spill already exists?!?\n");
1805 ast_free(p->cidspill);
1806 }
1807
1808 /*
1809 * SAS: Subscriber Alert Signal, 440Hz for 300ms
1810 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
1811 */
1812 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
1813 return -1;
1814 save_conference(p);
1815 /* Silence */
1816 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
1817 if (!p->callwaitrings && p->callwaitingcallerid) {
1818 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
1819 p->callwaitcas = 1;
1820 p->cidlen = 2400 + 680 + READ_SIZE * 4;
1821 } else {
1822 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
1823 p->callwaitcas = 0;
1824 p->cidlen = 2400 + READ_SIZE * 4;
1825 }
1826 p->cidpos = 0;
1827 send_callerid(p);
1828
1829 return 0;
1830}
1831
1832static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
1833{
1834 struct dahdi_pvt *p = pvt;
1835 struct analog_pvt *analog_p = p->sig_pvt;
1836
1837 ast_debug(2, "Starting cid spill\n");
1838
1839 if (p->cidspill) {
1840 ast_log(LOG_WARNING, "cidspill already exists??\n");
1841 ast_free(p->cidspill);
1842 }
1843
1845 int pres = ast_party_id_presentation(&caller->id);
1846 if (cwcid == 0) {
1847 /* Some CPE support additional parameters for on-hook Caller*ID,
1848 * such as redirecting reason and call qualifier, so send those
1849 * if available.
1850 * I don't know of any CPE that supports this for Call Waiting (unfortunately),
1851 * so don't send those for call waiting as that will just lengthen the CID spill
1852 * for no good reason.
1853 */
1855 caller->id.name.str,
1857 NULL,
1858 analog_p->redirecting_reason,
1859 pres,
1860 analog_p->call_qualifier,
1862 AST_LAW(p));
1863 } else {
1864 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
1866 p->callwaitcas = 0;
1867 p->cidcwexpire = 0;
1869 caller->id.name.str,
1871 NULL,
1872 -1,
1873 pres,
1874 0,
1875 AST_LAW(p));
1876 p->cidlen += READ_SIZE * 4;
1877 }
1878 p->cidpos = 0;
1879 p->cid_suppress_expire = 0;
1880 send_callerid(p);
1881 }
1882 return 0;
1883}
1884
1886{
1887 struct dahdi_pvt *p = pvt;
1888 if (p->dsp)
1890
1891 return 0;
1892}
1893
1894static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
1895{
1896 struct dahdi_pvt *p = pvt;
1897
1898 if (p->channel == CHAN_PSEUDO)
1899 ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
1900
1901 if (mode == ANALOG_DIGITMODE_DTMF) {
1902 /* If we do hardware dtmf, no need for a DSP */
1903 if (p->hardwaredtmf) {
1904 if (p->dsp) {
1905 ast_dsp_free(p->dsp);
1906 p->dsp = NULL;
1907 }
1908 return 0;
1909 }
1910
1911 if (!p->dsp) {
1912 p->dsp = ast_dsp_new();
1913 if (!p->dsp) {
1914 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1915 return -1;
1916 }
1917 }
1918
1920 } else if (mode == ANALOG_DIGITMODE_MF) {
1921 if (!p->dsp) {
1922 p->dsp = ast_dsp_new();
1923 if (!p->dsp) {
1924 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
1925 return -1;
1926 }
1927 }
1929 }
1930 return 0;
1931}
1932
1933static int dahdi_wink(struct dahdi_pvt *p, int index);
1934
1935static int my_wink(void *pvt, enum analog_sub sub)
1936{
1937 struct dahdi_pvt *p = pvt;
1938 int index = analogsub_to_dahdisub(sub);
1939 if (index != SUB_REAL) {
1940 ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
1941 }
1942 return dahdi_wink(p, index);
1943}
1944
1945static void wakeup_sub(struct dahdi_pvt *p, int a);
1946
1947static int reset_conf(struct dahdi_pvt *p);
1948
1949static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
1950
1951static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
1952{
1953 struct ast_frame *f = *dest;
1954 struct dahdi_pvt *p = pvt;
1955 int idx = analogsub_to_dahdisub(analog_index);
1956
1957 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
1958 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
1959 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
1960
1961 if (f->subclass.integer == 'f') {
1962 if (f->frametype == AST_FRAME_DTMF_END) {
1963 /* Fax tone -- Handle and return NULL */
1964 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
1965 /* If faxbuffers are configured, use them for the fax transmission */
1966 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
1967 struct dahdi_bufferinfo bi = {
1968 .txbufpolicy = p->faxbuf_policy,
1969 .bufsize = p->bufsize,
1970 .numbufs = p->faxbuf_no
1971 };
1972 int res;
1973
1974 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
1975 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
1976 } else {
1977 p->bufferoverrideinuse = 1;
1978 }
1979 }
1980 p->faxhandled = 1;
1981 if (p->dsp) {
1982 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
1984 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
1985 }
1986 if (strcmp(ast_channel_exten(ast), "fax")) {
1987 const char *target_context = ast_channel_context(ast);
1988
1989 /*
1990 * We need to unlock 'ast' here because ast_exists_extension has the
1991 * potential to start autoservice on the channel. Such action is prone
1992 * to deadlock if the channel is locked.
1993 *
1994 * ast_async_goto() has its own restriction on not holding the
1995 * channel lock.
1996 */
1998 ast_channel_unlock(ast);
1999 if (ast_exists_extension(ast, target_context, "fax", 1,
2000 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
2001 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
2002 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
2003 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
2004 if (ast_async_goto(ast, target_context, "fax", 1))
2005 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
2006 } else {
2007 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
2008 }
2009 ast_channel_lock(ast);
2010 ast_mutex_lock(&p->lock);
2011 } else {
2012 ast_debug(1, "Already in a fax extension, not redirecting\n");
2013 }
2014 } else {
2015 ast_debug(1, "Fax already handled\n");
2016 }
2017 dahdi_confmute(p, 0);
2018 }
2019 p->subs[idx].f.frametype = AST_FRAME_NULL;
2020 p->subs[idx].f.subclass.integer = 0;
2021 *dest = &p->subs[idx].f;
2022 }
2023}
2024
2025static void my_lock_private(void *pvt)
2026{
2027 struct dahdi_pvt *p = pvt;
2028 ast_mutex_lock(&p->lock);
2029}
2030
2031static void my_unlock_private(void *pvt)
2032{
2033 struct dahdi_pvt *p = pvt;
2035}
2036
2037static void my_deadlock_avoidance_private(void *pvt)
2038{
2039 struct dahdi_pvt *p = pvt;
2040
2042}
2043
2045{
2046 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2047 struct ast_channel_blob *obj = stasis_message_data(msg);
2048 struct ast_json *group, *span, *channel;
2049
2050 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2051 if (!channel_string) {
2052 return NULL;
2053 }
2054
2055 group = ast_json_object_get(obj->blob, "group");
2056 span = ast_json_object_get(obj->blob, "span");
2057 channel = ast_json_object_get(obj->blob, "channel");
2058
2059 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
2060 "%s"
2061 "DAHDIGroup: %llu\r\n"
2062 "DAHDISpan: %u\r\n"
2063 "DAHDIChannel: %s\r\n",
2064 ast_str_buffer(channel_string),
2066 (unsigned int)ast_json_integer_get(span),
2067 ast_json_string_get(channel));
2068}
2069
2072 );
2073
2074/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
2075static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
2076{
2077 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
2078
2079 ast_assert(dahdi_channel != NULL);
2080
2081 blob = ast_json_pack("{s: I, s: i, s: s}",
2082 "group", (ast_json_int_t)group,
2083 "span", span,
2084 "channel", dahdi_channel);
2085 if (!blob) {
2086 return;
2087 }
2088
2089 ast_channel_lock(chan);
2090 ast_channel_publish_blob(chan, dahdichannel_type(), blob);
2091 ast_channel_unlock(chan);
2092}
2093
2094/*!
2095 * \internal
2096 * \brief Post an AMI DAHDI channel association event.
2097 * \since 1.8
2098 *
2099 * \param p DAHDI private pointer
2100 * \param chan Channel associated with the private pointer
2101 */
2102static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
2103{
2104 char ch_name[23];
2105
2106 if (p->channel < CHAN_PSEUDO) {
2107 /* No B channel */
2108 snprintf(ch_name, sizeof(ch_name), "no-media (%d)", p->channel);
2109 } else if (p->channel == CHAN_PSEUDO) {
2110 /* Pseudo channel */
2111 strcpy(ch_name, "pseudo");
2112 } else {
2113 /* Real channel */
2114 snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
2115 }
2116 publish_dahdichannel(chan, p->group, p->span, ch_name);
2117}
2118
2119#ifdef HAVE_PRI
2120/*!
2121 * \internal
2122 * \brief Post an AMI DAHDI channel association event.
2123 * \since 1.8
2124 *
2125 * \param pvt DAHDI private pointer
2126 * \param chan Channel associated with the private pointer
2127 */
2128static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
2129{
2130 struct dahdi_pvt *p = pvt;
2131
2132 dahdi_ami_channel_event(p, chan);
2133}
2134#endif
2135
2136/* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
2137* returns the last value of the linear setting
2138*/
2139static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
2140{
2141 struct dahdi_pvt *p = pvt;
2142 int oldval;
2143 int idx = analogsub_to_dahdisub(sub);
2144
2145 dahdi_setlinear(p->subs[idx].dfd, linear_mode);
2146 oldval = p->subs[idx].linear;
2147 p->subs[idx].linear = linear_mode ? 1 : 0;
2148 return oldval;
2149}
2150
2151static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
2152{
2153 struct dahdi_pvt *p = pvt;
2154 int idx = analogsub_to_dahdisub(sub);
2155
2156 p->subs[idx].inthreeway = inthreeway;
2157}
2158
2159static int get_alarms(struct dahdi_pvt *p);
2160static void handle_alarms(struct dahdi_pvt *p, int alms);
2161static void my_get_and_handle_alarms(void *pvt)
2162{
2163 int res;
2164 struct dahdi_pvt *p = pvt;
2165
2166 res = get_alarms(p);
2167 handle_alarms(p, res);
2168}
2169
2171{
2173
2174 if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
2175 struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
2176
2177 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
2178 return p->sig_pvt;
2179 }
2180 }
2181 return NULL;
2182}
2183
2184static int my_get_sub_fd(void *pvt, enum analog_sub sub)
2185{
2186 struct dahdi_pvt *p = pvt;
2187 int dahdi_sub = analogsub_to_dahdisub(sub);
2188 return p->subs[dahdi_sub].dfd;
2189}
2190
2191static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
2192{
2193 struct dahdi_pvt *p = pvt;
2194
2195 /* Choose proper cadence */
2196 if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
2197 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
2198 ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
2199 *cid_rings = cidrings[p->distinctivering - 1];
2200 } else {
2201 if (p->distinctivering > 0) {
2202 ast_log(LOG_WARNING, "Cadence %d is not defined, falling back to default ring cadence\n", p->distinctivering);
2203 }
2204 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
2205 ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
2206 *cid_rings = p->sendcalleridafter;
2207 }
2208}
2209
2210static void my_set_alarm(void *pvt, int in_alarm)
2211{
2212 struct dahdi_pvt *p = pvt;
2213
2214 p->inalarm = in_alarm;
2215}
2216
2217static void my_set_dialing(void *pvt, int is_dialing)
2218{
2219 struct dahdi_pvt *p = pvt;
2220
2221 p->dialing = is_dialing;
2222}
2223
2224static void my_set_outgoing(void *pvt, int is_outgoing)
2225{
2226 struct dahdi_pvt *p = pvt;
2227
2228 p->outgoing = is_outgoing;
2229}
2230
2231#if defined(HAVE_PRI) || defined(HAVE_SS7)
2232static void my_set_digital(void *pvt, int is_digital)
2233{
2234 struct dahdi_pvt *p = pvt;
2235
2236 p->digital = is_digital;
2237}
2238#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2239
2240#if defined(HAVE_SS7)
2241static void my_set_inservice(void *pvt, int is_inservice)
2242{
2243 struct dahdi_pvt *p = pvt;
2244
2245 p->inservice = is_inservice;
2246}
2247#endif /* defined(HAVE_SS7) */
2248
2249#if defined(HAVE_SS7)
2250static void my_set_locallyblocked(void *pvt, int is_blocked)
2251{
2252 struct dahdi_pvt *p = pvt;
2253
2254 p->locallyblocked = is_blocked;
2255}
2256#endif /* defined(HAVE_SS7) */
2257
2258#if defined(HAVE_SS7)
2259static void my_set_remotelyblocked(void *pvt, int is_blocked)
2260{
2261 struct dahdi_pvt *p = pvt;
2262
2263 p->remotelyblocked = is_blocked;
2264}
2265#endif /* defined(HAVE_SS7) */
2266
2267static void my_set_ringtimeout(void *pvt, int ringt)
2268{
2269 struct dahdi_pvt *p = pvt;
2270 p->ringt = ringt;
2271}
2272
2273static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
2274{
2275 struct dahdi_pvt *p = pvt;
2276
2277 /* We reset p->waitfordialtonetemp here, to prevent leaking to future calls,
2278 * but we also need to check against this value until we get dialtone
2279 * or the timer expires, since waitingfordt is when the timer started,
2280 * not when it should expire.
2281 *
2282 * Critically, we only set p->waitingfordt here if waitfordialtone or waitfordialtonetemp
2283 * has already been set, as waitingfordt is what is checked at runtime to determine
2284 * if we should be waiting for dial tone. This ensures that if a second call
2285 * is initiated concurrently, the first one "consumes" waitfordialtonetemp and resets it,
2286 * preventing leaking to other calls while remaining available to check on the first one while dialing.
2287 */
2289 p->waitfordialtonetemp = 0;
2290
2292 return;
2293 }
2294
2295 /* Because the DSP is allocated when the channel is created,
2296 * if we requested waitfordialtone later (in a predial handler),
2297 * we need to create it now */
2298 if (!p->dsp) {
2299 p->dsp = ast_dsp_new();
2300 if (!p->dsp) {
2301 ast_log(LOG_ERROR, "Unable to allocate DSP\n");
2302 return;
2303 }
2304 }
2307
2308 ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtoneduration);
2309 gettimeofday(&p->waitingfordt, NULL);
2311}
2312
2313static int my_check_waitingfordt(void *pvt)
2314{
2315 struct dahdi_pvt *p = pvt;
2316
2317 if (p->waitingfordt.tv_sec) {
2318 return 1;
2319 }
2320
2321 return 0;
2322}
2323
2324static void my_set_confirmanswer(void *pvt, int flag)
2325{
2326 struct dahdi_pvt *p = pvt;
2327 p->confirmanswer = flag;
2328}
2329
2330static int my_check_confirmanswer(void *pvt)
2331{
2332 struct dahdi_pvt *p = pvt;
2333 if (p->confirmanswer) {
2334 return 1;
2335 }
2336
2337 return 0;
2338}
2339
2340static void my_set_callwaiting(void *pvt, int callwaiting_enable)
2341{
2342 struct dahdi_pvt *p = pvt;
2343
2344 p->callwaiting = callwaiting_enable;
2345}
2346
2347static void my_cancel_cidspill(void *pvt)
2348{
2349 struct dahdi_pvt *p = pvt;
2350
2351 ast_free(p->cidspill);
2352 p->cidspill = NULL;
2354}
2355
2356static int my_confmute(void *pvt, int mute)
2357{
2358 struct dahdi_pvt *p = pvt;
2359 return dahdi_confmute(p, mute);
2360}
2361
2362static void my_set_pulsedial(void *pvt, int flag)
2363{
2364 struct dahdi_pvt *p = pvt;
2365 p->pulsedial = flag;
2366}
2367
2368static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
2369{
2370 struct dahdi_pvt *p = pvt;
2371
2372 p->owner = new_owner;
2373}
2374
2375static const char *my_get_orig_dialstring(void *pvt)
2376{
2377 struct dahdi_pvt *p = pvt;
2378
2379 return p->dialstring;
2380}
2381
2388
2396
2397static void my_all_subchannels_hungup(void *pvt)
2398{
2399 struct dahdi_pvt *p = pvt;
2400 int res, law;
2401
2402 p->faxhandled = 0;
2403 p->didtdd = 0;
2404
2405 if (p->dsp) {
2406 ast_dsp_free(p->dsp);
2407 p->dsp = NULL;
2408 }
2409
2410 p->law = p->law_default;
2411 law = p->law_default;
2412 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
2413 if (res < 0)
2414 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
2415
2417
2418#if 1
2419 {
2420 int i;
2421 p->owner = NULL;
2422 /* Cleanup owners here */
2423 for (i = 0; i < 3; i++) {
2424 p->subs[i].owner = NULL;
2425 }
2426 }
2427#endif
2428
2429 reset_conf(p);
2430 if (num_restart_pending == 0) {
2432 }
2433}
2434
2435static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
2436
2437static int my_conf_del(void *pvt, enum analog_sub sub)
2438{
2439 struct dahdi_pvt *p = pvt;
2440 int x = analogsub_to_dahdisub(sub);
2441
2442 return conf_del(p, &p->subs[x], x);
2443}
2444
2445static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
2446
2447static int my_conf_add(void *pvt, enum analog_sub sub)
2448{
2449 struct dahdi_pvt *p = pvt;
2450 int x = analogsub_to_dahdisub(sub);
2451
2452 return conf_add(p, &p->subs[x], x, 0);
2453}
2454
2455static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
2456
2457static int my_complete_conference_update(void *pvt, int needconference)
2458{
2459 struct dahdi_pvt *p = pvt;
2460 int needconf = needconference;
2461 int x;
2462 int useslavenative;
2463 struct dahdi_pvt *slave = NULL;
2464
2465 useslavenative = isslavenative(p, &slave);
2466
2467 /* If we have a slave, add him to our conference now. or DAX
2468 if this is slave native */
2469 for (x = 0; x < MAX_SLAVES; x++) {
2470 if (p->slaves[x]) {
2471 if (useslavenative)
2472 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
2473 else {
2474 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
2475 needconf++;
2476 }
2477 }
2478 }
2479 /* If we're supposed to be in there, do so now */
2480 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
2481 if (useslavenative)
2482 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
2483 else {
2484 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
2485 needconf++;
2486 }
2487 }
2488 /* If we have a master, add ourselves to his conference */
2489 if (p->master) {
2490 if (isslavenative(p->master, NULL)) {
2492 } else {
2493 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
2494 }
2495 }
2496 if (!needconf) {
2497 /* Nobody is left (or should be left) in our conference.
2498 Kill it. */
2499 p->confno = -1;
2500 }
2501
2502 return 0;
2503}
2504
2505static int check_for_conference(struct dahdi_pvt *p);
2506
2507static int my_check_for_conference(void *pvt)
2508{
2509 struct dahdi_pvt *p = pvt;
2510 return check_for_conference(p);
2511}
2512
2513static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
2514{
2515 struct dahdi_pvt *p = pvt;
2516 int da, db;
2517 int tchan;
2518 int tinthreeway;
2519
2522
2523 tchan = p->subs[da].chan;
2524 p->subs[da].chan = p->subs[db].chan;
2525 p->subs[db].chan = tchan;
2526
2527 tinthreeway = p->subs[da].inthreeway;
2528 p->subs[da].inthreeway = p->subs[db].inthreeway;
2529 p->subs[db].inthreeway = tinthreeway;
2530
2531 p->subs[da].owner = ast_a;
2532 p->subs[db].owner = ast_b;
2533
2534 if (ast_a)
2535 ast_channel_set_fd(ast_a, 0, p->subs[da].dfd);
2536 if (ast_b)
2537 ast_channel_set_fd(ast_b, 0, p->subs[db].dfd);
2538
2539 wakeup_sub(p, a);
2540 wakeup_sub(p, b);
2541
2542 return;
2543}
2544
2545/*!
2546 * \internal
2547 * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
2548 * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
2549 *
2550 * \param callid_created value returned from ast_callid_threadstorage_auto()
2551 * \param i, state, startpbx, idx, law, assignedids, requestor, callid
2552 */
2553static 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);
2554
2555static 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);
2556
2557static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
2558{
2559 ast_callid callid = 0;
2560 int callid_created = ast_callid_threadstorage_auto(&callid);
2561 struct dahdi_pvt *p = pvt;
2562 int dsub = analogsub_to_dahdisub(sub);
2563
2564 return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, NULL, requestor, callid, callid_created);
2565}
2566
2567#if defined(HAVE_PRI) || defined(HAVE_SS7)
2568static int dahdi_setlaw(int dfd, int law)
2569{
2570 int res;
2571 res = ioctl(dfd, DAHDI_SETLAW, &law);
2572 if (res)
2573 return res;
2574 return 0;
2575}
2576#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2577
2578#if defined(HAVE_PRI)
2579static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state,
2580 enum sig_pri_law law, char *exten, const struct ast_assigned_ids *assignedids,
2581 const struct ast_channel *requestor)
2582{
2583 struct dahdi_pvt *p = pvt;
2584 int audio;
2585 int newlaw = -1;
2586 ast_callid callid = 0;
2587 int callid_created = ast_callid_threadstorage_auto(&callid);
2588
2589 switch (p->sig) {
2591 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
2592 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
2593 break;
2594 }
2595 /* Fall through */
2596 default:
2597 /* Set to audio mode at this point */
2598 audio = 1;
2599 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) {
2600 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
2601 p->channel, audio, strerror(errno));
2602 }
2603 break;
2604 }
2605
2606 if (law != SIG_PRI_DEFLAW) {
2607 dahdi_setlaw(p->subs[SUB_REAL].dfd, (law == SIG_PRI_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
2608 }
2609
2610 ast_copy_string(p->exten, exten, sizeof(p->exten));
2611
2612 switch (law) {
2613 case SIG_PRI_DEFLAW:
2614 newlaw = 0;
2615 break;
2616 case SIG_PRI_ALAW:
2617 newlaw = DAHDI_LAW_ALAW;
2618 break;
2619 case SIG_PRI_ULAW:
2620 newlaw = DAHDI_LAW_MULAW;
2621 break;
2622 }
2623
2624 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
2625}
2626#endif /* defined(HAVE_PRI) */
2627
2628static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
2629
2630#if defined(HAVE_PRI) || defined(HAVE_SS7)
2631/*!
2632 * \internal
2633 * \brief Open the PRI/SS7 channel media path.
2634 * \since 1.8
2635 *
2636 * \param p Channel private control structure.
2637 */
2638static void my_pri_ss7_open_media(void *p)
2639{
2640 struct dahdi_pvt *pvt = p;
2641 int res;
2642 int dfd;
2643 int set_val;
2644
2645 dfd = pvt->subs[SUB_REAL].dfd;
2646
2647 /* Open the media path. */
2648 set_val = 1;
2649 res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
2650 if (res < 0) {
2651 ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n",
2652 pvt->channel, strerror(errno));
2653 }
2654
2655 /* Set correct companding law for this call. */
2656 res = dahdi_setlaw(dfd, pvt->law);
2657 if (res < 0) {
2658 ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pvt->channel);
2659 }
2660
2661 /* Set correct gain for this call. */
2662 if (pvt->digital) {
2663 res = set_actual_gain(dfd, 0, 0, pvt->rxdrc, pvt->txdrc, pvt->law);
2664 } else {
2665 res = set_actual_gain(dfd, pvt->rxgain, pvt->txgain, pvt->rxdrc, pvt->txdrc,
2666 pvt->law);
2667 }
2668 if (res < 0) {
2669 ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pvt->channel);
2670 }
2671
2672 if (pvt->dsp_features && pvt->dsp) {
2674 }
2675}
2676#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
2677
2678#if defined(HAVE_PRI)
2679/*!
2680 * \internal
2681 * \brief Ask DAHDI to dial the given dial string.
2682 * \since 1.8.11
2683 *
2684 * \param p Channel private control structure.
2685 * \param dial_string String to pass to DAHDI to dial.
2686 *
2687 * \note The channel private lock needs to be held when calling.
2688 */
2689static void my_pri_dial_digits(void *p, const char *dial_string)
2690{
2691 char dial_str[DAHDI_MAX_DTMF_BUF];
2692 struct dahdi_pvt *pvt = p;
2693 int res;
2694
2695 snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
2696 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
2697 if (!res) {
2698 pvt->dialing = 1;
2699 }
2700}
2701#endif /* defined(HAVE_PRI) */
2702
2703static int unalloc_sub(struct dahdi_pvt *p, int x);
2704
2705static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
2706{
2707 struct dahdi_pvt *p = pvt;
2708
2709 return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
2710}
2711
2712static int alloc_sub(struct dahdi_pvt *p, int x);
2713
2714static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
2715{
2716 struct dahdi_pvt *p = pvt;
2717
2718 return alloc_sub(p, analogsub_to_dahdisub(analogsub));
2719}
2720
2721static int has_voicemail(struct dahdi_pvt *p);
2722
2723static int my_has_voicemail(void *pvt)
2724{
2725 struct dahdi_pvt *p = pvt;
2726
2727 return has_voicemail(p);
2728}
2729
2730static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
2731{
2732 struct dahdi_pvt *p = pvt;
2733 int index;
2734
2735 index = analogsub_to_dahdisub(sub);
2736
2737 return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
2738}
2739
2741{
2742 enum analog_event res;
2743
2744 switch (event) {
2745 case DAHDI_EVENT_ONHOOK:
2746 res = ANALOG_EVENT_ONHOOK;
2747 break;
2748 case DAHDI_EVENT_RINGOFFHOOK:
2750 break;
2751 case DAHDI_EVENT_WINKFLASH:
2753 break;
2754 case DAHDI_EVENT_ALARM:
2755 res = ANALOG_EVENT_ALARM;
2756 break;
2757 case DAHDI_EVENT_NOALARM:
2759 break;
2760 case DAHDI_EVENT_DIALCOMPLETE:
2762 break;
2763 case DAHDI_EVENT_RINGERON:
2765 break;
2766 case DAHDI_EVENT_RINGEROFF:
2768 break;
2769 case DAHDI_EVENT_HOOKCOMPLETE:
2771 break;
2772 case DAHDI_EVENT_PULSE_START:
2774 break;
2775 case DAHDI_EVENT_POLARITY:
2777 break;
2778 case DAHDI_EVENT_RINGBEGIN:
2780 break;
2781 case DAHDI_EVENT_EC_DISABLED:
2783 break;
2784 case DAHDI_EVENT_REMOVED:
2786 break;
2787 case DAHDI_EVENT_NEONMWI_ACTIVE:
2789 break;
2790 case DAHDI_EVENT_NEONMWI_INACTIVE:
2792 break;
2793#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
2794 case DAHDI_EVENT_TX_CED_DETECTED:
2796 break;
2797 case DAHDI_EVENT_RX_CED_DETECTED:
2799 break;
2800 case DAHDI_EVENT_EC_NLP_DISABLED:
2802 break;
2803 case DAHDI_EVENT_EC_NLP_ENABLED:
2805 break;
2806#endif
2807 case DAHDI_EVENT_PULSEDIGIT:
2809 break;
2810 case DAHDI_EVENT_DTMFDOWN:
2812 break;
2813 case DAHDI_EVENT_DTMFUP:
2814 res = ANALOG_EVENT_DTMFUP;
2815 break;
2816 default:
2817 switch(event & 0xFFFF0000) {
2818 case DAHDI_EVENT_PULSEDIGIT:
2819 case DAHDI_EVENT_DTMFDOWN:
2820 case DAHDI_EVENT_DTMFUP:
2821 /* The event includes a digit number in the low word.
2822 * Converting it to a 'enum analog_event' would remove
2823 * that information. Thus it is returned as-is.
2824 */
2825 return event;
2826 }
2827
2828 res = ANALOG_EVENT_ERROR;
2829 break;
2830 }
2831
2832 return res;
2833}
2834
2835static inline int dahdi_wait_event(int fd);
2836
2837static int my_wait_event(void *pvt)
2838{
2839 struct dahdi_pvt *p = pvt;
2840
2841 return dahdi_wait_event(p->subs[SUB_REAL].dfd);
2842}
2843
2844static int my_get_event(void *pvt)
2845{
2846 struct dahdi_pvt *p = pvt;
2847 int res;
2848
2849 if (p->fake_event) {
2850 res = p->fake_event;
2851 p->fake_event = 0;
2852 } else
2853 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
2854
2855 return dahdievent_to_analogevent(res);
2856}
2857
2858static int my_is_off_hook(void *pvt)
2859{
2860 struct dahdi_pvt *p = pvt;
2861 int res;
2862 struct dahdi_params par;
2863
2864 memset(&par, 0, sizeof(par));
2865
2866 if (p->subs[SUB_REAL].dfd > -1)
2867 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
2868 else {
2869 /* Assume not off hook on CVRS */
2870 res = 0;
2871 par.rxisoffhook = 0;
2872 }
2873 if (res) {
2874 ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
2875 }
2876
2877 if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
2878 /* When "onhook" that means no battery on the line, and thus
2879 it is out of service..., if it's on a TDM card... If it's a channel
2880 bank, there is no telling... */
2881 return (par.rxbits > -1) || par.rxisoffhook;
2882 }
2883
2884 return par.rxisoffhook;
2885}
2886
2887static int my_set_echocanceller(void *pvt, int enable)
2888{
2889 struct dahdi_pvt *p = pvt;
2890
2891 if (enable)
2892 dahdi_ec_enable(p);
2893 else
2895
2896 return 0;
2897}
2898
2899static int dahdi_ring_phone(struct dahdi_pvt *p);
2900
2901static int my_ring(void *pvt)
2902{
2903 struct dahdi_pvt *p = pvt;
2904
2905 return dahdi_ring_phone(p);
2906}
2907
2908static int my_flash(void *pvt)
2909{
2910 struct dahdi_pvt *p = pvt;
2911 int func = DAHDI_FLASH;
2912 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
2913}
2914
2915static inline int dahdi_set_hook(int fd, int hs);
2916
2917static int my_off_hook(void *pvt)
2918{
2919 struct dahdi_pvt *p = pvt;
2920 return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
2921}
2922
2923static void my_set_needringing(void *pvt, int value)
2924{
2925 struct dahdi_pvt *p = pvt;
2927}
2928
2929static void my_set_polarity(void *pvt, int value)
2930{
2931 struct dahdi_pvt *p = pvt;
2932
2933 if (p->channel == CHAN_PSEUDO) {
2934 return;
2935 }
2936 p->polarity = value;
2937 ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETPOLARITY, &value);
2938}
2939
2940static void my_start_polarityswitch(void *pvt)
2941{
2942 struct dahdi_pvt *p = pvt;
2943
2945 my_set_polarity(pvt, 0);
2946 }
2947}
2948
2949static void my_answer_polarityswitch(void *pvt)
2950{
2951 struct dahdi_pvt *p = pvt;
2952
2953 if (!p->answeronpolarityswitch) {
2954 return;
2955 }
2956
2957 my_set_polarity(pvt, 1);
2958}
2959
2960static void my_hangup_polarityswitch(void *pvt)
2961{
2962 struct dahdi_pvt *p = pvt;
2963
2964 if (!p->hanguponpolarityswitch) {
2965 return;
2966 }
2967
2968 if (p->answeronpolarityswitch) {
2969 my_set_polarity(pvt, 0);
2970 } else {
2971 my_set_polarity(pvt, 1);
2972 }
2973}
2974
2975static int my_start(void *pvt)
2976{
2977 struct dahdi_pvt *p = pvt;
2978 int x = DAHDI_START;
2979
2980 return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
2981}
2982
2983static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
2984{
2985 struct dahdi_pvt *p = pvt;
2986
2987 if (dop->op != ANALOG_DIAL_OP_REPLACE) {
2988 ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
2989 return -1;
2990 }
2991
2992 if (sub != ANALOG_SUB_REAL) {
2993 ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %u\n",
2994 dop->dialstr, p->channel, sub);
2995 return -1;
2996 }
2997
2998 return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
2999}
3000
3001static void dahdi_train_ec(struct dahdi_pvt *p);
3002
3003static int my_train_echocanceller(void *pvt)
3004{
3005 struct dahdi_pvt *p = pvt;
3006
3007 dahdi_train_ec(p);
3008
3009 return 0;
3010}
3011
3012static int my_is_dialing(void *pvt, enum analog_sub sub)
3013{
3014 struct dahdi_pvt *p = pvt;
3015 int index;
3016 int x;
3017
3018 index = analogsub_to_dahdisub(sub);
3019
3020 if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
3021 ast_debug(1, "DAHDI_DIALING ioctl failed!\n");
3022 return -1;
3023 }
3024
3025 return x;
3026}
3027
3028static int my_on_hook(void *pvt)
3029{
3030 struct dahdi_pvt *p = pvt;
3031 return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
3032}
3033
3034#if defined(HAVE_PRI)
3035static void my_pri_fixup_chans(void *chan_old, void *chan_new)
3036{
3037 struct dahdi_pvt *old_chan = chan_old;
3038 struct dahdi_pvt *new_chan = chan_new;
3039
3040 new_chan->owner = old_chan->owner;
3041 old_chan->owner = NULL;
3042 if (new_chan->owner) {
3043 ast_channel_tech_pvt_set(new_chan->owner, new_chan);
3044 ast_channel_internal_fd_set(new_chan->owner, 0, new_chan->subs[SUB_REAL].dfd);
3045 new_chan->subs[SUB_REAL].owner = old_chan->subs[SUB_REAL].owner;
3046 old_chan->subs[SUB_REAL].owner = NULL;
3047 }
3048 /* Copy any DSP that may be present */
3049 new_chan->dsp = old_chan->dsp;
3050 new_chan->dsp_features = old_chan->dsp_features;
3051 old_chan->dsp = NULL;
3052 old_chan->dsp_features = 0;
3053
3054 /* Transfer flags from the old channel. */
3055 new_chan->dialing = old_chan->dialing;
3056 new_chan->digital = old_chan->digital;
3057 new_chan->outgoing = old_chan->outgoing;
3058 old_chan->dialing = 0;
3059 old_chan->digital = 0;
3060 old_chan->outgoing = 0;
3061
3062 /* More stuff to transfer to the new channel. */
3063 new_chan->law = old_chan->law;
3064 strcpy(new_chan->dialstring, old_chan->dialstring);
3065}
3066#endif /* defined(HAVE_PRI) */
3067
3068#if defined(HAVE_PRI)
3069static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
3070{
3071 switch (tone) {
3073 return DAHDI_TONE_RINGTONE;
3075 return DAHDI_TONE_STUTTER;
3077 return DAHDI_TONE_CONGESTION;
3079 return DAHDI_TONE_DIALTONE;
3081 return DAHDI_TONE_DIALRECALL;
3082 case SIG_PRI_TONE_INFO:
3083 return DAHDI_TONE_INFO;
3084 case SIG_PRI_TONE_BUSY:
3085 return DAHDI_TONE_BUSY;
3086 default:
3087 return -1;
3088 }
3089}
3090#endif /* defined(HAVE_PRI) */
3091
3092#if defined(HAVE_PRI)
3093static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
3094{
3095 int x;
3096
3097 ioctl(pri->fds[index], DAHDI_GETEVENT, &x);
3098 switch (x) {
3099 case DAHDI_EVENT_NONE:
3100 break;
3101 case DAHDI_EVENT_ALARM:
3102 case DAHDI_EVENT_NOALARM:
3103 if (sig_pri_is_alarm_ignored(pri)) {
3104 break;
3105 }
3106 /* Fall through */
3107 default:
3108 ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
3109 event2str(x), x, pri->span);
3110 break;
3111 }
3112 /* Keep track of alarm state */
3113 switch (x) {
3114 case DAHDI_EVENT_ALARM:
3115 pri_event_alarm(pri, index, 0);
3116 break;
3117 case DAHDI_EVENT_NOALARM:
3118 pri_event_noalarm(pri, index, 0);
3119 break;
3120 case DAHDI_EVENT_REMOVED:
3121 pri_queue_for_destruction(pri);
3122 break;
3123 default:
3124 break;
3125 }
3126}
3127#endif /* defined(HAVE_PRI) */
3128
3129#if defined(HAVE_PRI)
3130static int my_pri_play_tone(void *pvt, enum sig_pri_tone tone)
3131{
3132 struct dahdi_pvt *p = pvt;
3133
3134 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_pri_tone_to_dahditone(tone));
3135}
3136#endif /* defined(HAVE_PRI) */
3137
3138#if defined(HAVE_PRI) || defined(HAVE_SS7)
3139/*!
3140 * \internal
3141 * \brief Set the caller id information.
3142 * \since 1.8
3143 *
3144 * \param pvt DAHDI private structure
3145 * \param caller Caller-id information to set.
3146 */
3147static void my_set_callerid(void *pvt, const struct ast_party_caller *caller)
3148{
3149 struct dahdi_pvt *p = pvt;
3150
3152 S_COR(caller->id.number.valid, caller->id.number.str, ""),
3153 sizeof(p->cid_num));
3155 S_COR(caller->id.name.valid, caller->id.name.str, ""),
3156 sizeof(p->cid_name));
3158 S_COR(caller->id.subaddress.valid, caller->id.subaddress.str, ""),
3159 sizeof(p->cid_subaddr));
3160 p->cid_ton = caller->id.number.plan;
3162 if (caller->id.tag) {
3163 ast_copy_string(p->cid_tag, caller->id.tag, sizeof(p->cid_tag));
3164 }
3165 ast_copy_string(p->cid_ani,
3166 S_COR(caller->ani.number.valid, caller->ani.number.str, ""),
3167 sizeof(p->cid_ani));
3168 p->cid_ani2 = caller->ani2;
3169}
3170#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3171
3172#if defined(HAVE_PRI) || defined(HAVE_SS7)
3173/*!
3174 * \internal
3175 * \brief Set the Dialed Number Identifier.
3176 * \since 1.8
3177 *
3178 * \param pvt DAHDI private structure
3179 * \param dnid Dialed Number Identifier string.
3180 */
3181static void my_set_dnid(void *pvt, const char *dnid)
3182{
3183 struct dahdi_pvt *p = pvt;
3184
3185 ast_copy_string(p->dnid, dnid, sizeof(p->dnid));
3186}
3187#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
3188
3189#if defined(HAVE_PRI)
3190/*!
3191 * \internal
3192 * \brief Set the Redirecting Directory Number Information Service (RDNIS).
3193 * \since 1.8
3194 *
3195 * \param pvt DAHDI private structure
3196 * \param rdnis Redirecting Directory Number Information Service (RDNIS) string.
3197 */
3198static void my_set_rdnis(void *pvt, const char *rdnis)
3199{
3200 struct dahdi_pvt *p = pvt;
3201
3202 ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
3203}
3204#endif /* defined(HAVE_PRI) */
3205
3206#if defined(HAVE_PRI)
3207/*!
3208 * \internal
3209 * \brief Make a dialstring for native ISDN CC to recall properly.
3210 * \since 1.8
3211 *
3212 * \param priv Channel private control structure.
3213 * \param buf Where to put the modified dialstring.
3214 * \param buf_size Size of modified dialstring buffer.
3215 *
3216 * \details
3217 * original dialstring:
3218 * \verbatim
3219 DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3220 \endverbatim
3221 *
3222 * The modified dialstring will have prefixed the channel-group section
3223 * with the ISDN channel restriction.
3224 *
3225 * buf:
3226 * \verbatim
3227 DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]]
3228 \endverbatim
3229 *
3230 * The routine will check to see if the ISDN channel restriction is already
3231 * in the original dialstring.
3232 */
3233static void my_pri_make_cc_dialstring(void *priv, char *buf, size_t buf_size)
3234{
3235 char *dial;
3236 struct dahdi_pvt *pvt;
3238 AST_APP_ARG(tech); /* channel technology token */
3239 AST_APP_ARG(group); /* channel/group token */
3240 //AST_APP_ARG(ext); /* extension token */
3241 //AST_APP_ARG(opts); /* options token */
3242 //AST_APP_ARG(other); /* Any remaining unused arguments */
3243 );
3244
3245 pvt = priv;
3246 dial = ast_strdupa(pvt->dialstring);
3247 AST_NONSTANDARD_APP_ARGS(args, dial, '/');
3248 if (!args.tech) {
3249 ast_copy_string(buf, pvt->dialstring, buf_size);
3250 return;
3251 }
3252 if (!args.group) {
3253 /* Append the ISDN span channel restriction to the dialstring. */
3254 snprintf(buf, buf_size, "%s/i%d-", args.tech, pvt->pri->span);
3255 return;
3256 }
3257 if (isdigit(args.group[0]) || args.group[0] == 'i' || strchr(args.group, '!')) {
3258 /* The ISDN span channel restriction is not needed or already
3259 * in the dialstring. */
3260 ast_copy_string(buf, pvt->dialstring, buf_size);
3261 return;
3262 }
3263 /* Insert the ISDN span channel restriction into the dialstring. */
3264 snprintf(buf, buf_size, "%s/i%d-%s", args.tech, pvt->pri->span, args.group);
3265}
3266#endif /* defined(HAVE_PRI) */
3267
3268#if defined(HAVE_PRI)
3269/*!
3270 * \internal
3271 * \brief Reevaluate the PRI span device state.
3272 * \since 1.8
3273 *
3274 * \param pri Asterisk D channel control structure.
3275 *
3276 * \note Assumes the pri->lock is already obtained.
3277 */
3278static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
3279{
3280 unsigned idx;
3281 unsigned num_b_chans; /* Number of B channels provisioned on the span. */
3282 unsigned in_use; /* Number of B channels in use on the span. */
3283 unsigned in_alarm; /* TRUE if the span is in alarm condition. */
3284 enum ast_device_state new_state;
3285
3286 /* Count the number of B channels and the number of B channels in use. */
3287 num_b_chans = 0;
3288 in_use = 0;
3289 in_alarm = 1;
3290 for (idx = pri->numchans; idx--;) {
3291 if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
3292 /* This is a B channel interface. */
3293 ++num_b_chans;
3294 if (!sig_pri_is_chan_available(pri->pvts[idx])) {
3295 ++in_use;
3296 }
3297 if (!pri->pvts[idx]->inalarm) {
3298 /* There is a channel that is not in alarm. */
3299 in_alarm = 0;
3300 }
3301 }
3302 }
3303
3304 /* Update the span congestion device state and report any change. */
3305 if (in_alarm) {
3306 new_state = AST_DEVICE_UNAVAILABLE;
3307 } else {
3308 new_state = num_b_chans == in_use ? AST_DEVICE_BUSY : AST_DEVICE_NOT_INUSE;
3309 }
3310 if (pri->congestion_devstate != new_state) {
3311 pri->congestion_devstate = new_state;
3312 ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "DAHDI/I%d/congestion", pri->span);
3313 }
3314#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
3315 /* Update the span threshold device state and report any change. */
3316 if (in_alarm) {
3317 new_state = AST_DEVICE_UNAVAILABLE;
3318 } else if (!in_use) {
3319 new_state = AST_DEVICE_NOT_INUSE;
3320 } else if (!pri->user_busy_threshold) {
3321 new_state = in_use < num_b_chans ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
3322 } else {
3323 new_state = in_use < pri->user_busy_threshold ? AST_DEVICE_INUSE
3325 }
3326 if (pri->threshold_devstate != new_state) {
3327 pri->threshold_devstate = new_state;
3329 }
3330#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
3331}
3332#endif /* defined(HAVE_PRI) */
3333
3334#if defined(HAVE_PRI)
3335/*!
3336 * \internal
3337 * \brief Reference this module.
3338 * \since 1.8
3339 */
3340static void my_module_ref(void)
3341{
3343}
3344#endif /* defined(HAVE_PRI) */
3345
3346#if defined(HAVE_PRI)
3347/*!
3348 * \internal
3349 * \brief Unreference this module.
3350 * \since 1.8
3351 */
3352static void my_module_unref(void)
3353{
3355}
3356#endif /* defined(HAVE_PRI) */
3357
3358#if defined(HAVE_PRI)
3359#if defined(HAVE_PRI_CALL_WAITING)
3360static void my_pri_init_config(void *priv, struct sig_pri_span *pri);
3361#endif /* defined(HAVE_PRI_CALL_WAITING) */
3362static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri);
3363
3365{
3366 .handle_dchan_exception = my_handle_dchan_exception,
3367 .play_tone = my_pri_play_tone,
3368 .set_echocanceller = my_set_echocanceller,
3369 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3370 .lock_private = my_lock_private,
3371 .unlock_private = my_unlock_private,
3372 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3373 .new_ast_channel = my_new_pri_ast_channel,
3374 .fixup_chans = my_pri_fixup_chans,
3375 .set_alarm = my_set_alarm,
3376 .set_dialing = my_set_dialing,
3377 .set_outgoing = my_set_outgoing,
3378 .set_digital = my_set_digital,
3379 .set_callerid = my_set_callerid,
3380 .set_dnid = my_set_dnid,
3381 .set_rdnis = my_set_rdnis,
3382 .new_nobch_intf = dahdi_new_pri_nobch_channel,
3383#if defined(HAVE_PRI_CALL_WAITING)
3384 .init_config = my_pri_init_config,
3385#endif /* defined(HAVE_PRI_CALL_WAITING) */
3386 .get_orig_dialstring = my_get_orig_dialstring,
3387 .make_cc_dialstring = my_pri_make_cc_dialstring,
3388 .update_span_devstate = dahdi_pri_update_span_devstate,
3389 .module_ref = my_module_ref,
3390 .module_unref = my_module_unref,
3391 .dial_digits = my_pri_dial_digits,
3392 .open_media = my_pri_ss7_open_media,
3393 .ami_channel_event = my_ami_channel_event,
3394 .destroy_later = pri_queue_for_destruction,
3395};
3396#endif /* defined(HAVE_PRI) */
3397
3398#if defined(HAVE_SS7)
3399/*!
3400 * \internal
3401 * \brief Handle the SS7 link exception.
3402 * \since 1.8
3403 *
3404 * \param linkset Controlling linkset for the channel.
3405 * \param which Link index of the signaling channel.
3406 */
3407static void my_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
3408{
3409 int event;
3410
3411 if (ioctl(linkset->fds[which], DAHDI_GETEVENT, &event)) {
3412 ast_log(LOG_ERROR, "SS7: Error in exception retrieval on span %d/%d!\n",
3413 linkset->span, which);
3414 return;
3415 }
3416 switch (event) {
3417 case DAHDI_EVENT_NONE:
3418 break;
3419 case DAHDI_EVENT_ALARM:
3420 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3421 event2str(event), event, linkset->span, which);
3422 sig_ss7_link_alarm(linkset, which);
3423 break;
3424 case DAHDI_EVENT_NOALARM:
3425 ast_log(LOG_ERROR, "SS7 got event: %s(%d) on span %d/%d\n",
3426 event2str(event), event, linkset->span, which);
3427 sig_ss7_link_noalarm(linkset, which);
3428 break;
3429 default:
3430 ast_log(LOG_NOTICE, "SS7 got event: %s(%d) on span %d/%d\n",
3431 event2str(event), event, linkset->span, which);
3432 break;
3433 }
3434}
3435#endif /* defined(HAVE_SS7) */
3436
3437#if defined(HAVE_SS7)
3438static void my_ss7_set_loopback(void *pvt, int enable)
3439{
3440 struct dahdi_pvt *p = pvt;
3441
3442 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
3443 ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel,
3444 strerror(errno));
3445 }
3446}
3447#endif /* defined(HAVE_SS7) */
3448
3449#if defined(HAVE_SS7)
3450/*!
3451 * \internal
3452 * \brief Find the linkset to which SS7 belongs.
3453 * \since 11.0
3454 *
3455 * \param ss7 structure to match on.
3456 *
3457 * \retval linkset if found.
3458 * \retval NULL if not found.
3459 */
3460static struct sig_ss7_linkset *my_ss7_find_linkset(struct ss7 *ss7)
3461{
3462 int idx;
3463
3464 if (!ss7) {
3465 return NULL;
3466 }
3467
3468 for (idx = 0; idx < NUM_SPANS; ++idx) {
3469 if (linksets[idx].ss7.ss7 == ss7) {
3470 return &linksets[idx].ss7;
3471 }
3472 }
3473 return NULL;
3474}
3475#endif /* defined(HAVE_SS7) */
3476
3477#if defined(HAVE_SS7)
3478/*!
3479 * \internal
3480 * \brief Create a new asterisk channel structure for SS7.
3481 * \since 1.8
3482 *
3483 * \param pvt Private channel structure.
3484 * \param state Initial state of new channel.
3485 * \param law Companding law to use.
3486 * \param exten Dialplan extension for incoming call.
3487 * \param requestor Channel requesting this new channel.
3488 * \param assignedids
3489 *
3490 * \retval ast_channel on success.
3491 * \retval NULL on error.
3492 */
3493static 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)
3494{
3495 struct dahdi_pvt *p = pvt;
3496 int audio;
3497 int newlaw;
3498 ast_callid callid = 0;
3499 int callid_created = ast_callid_threadstorage_auto(&callid);
3500
3501 /* Set to audio mode at this point */
3502 audio = 1;
3503 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1)
3504 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
3505 p->channel, audio, strerror(errno));
3506
3507 if (law != SIG_SS7_DEFLAW) {
3508 dahdi_setlaw(p->subs[SUB_REAL].dfd,
3509 (law == SIG_SS7_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
3510 }
3511
3512 ast_copy_string(p->exten, exten, sizeof(p->exten));
3513
3514 newlaw = -1;
3515 switch (law) {
3516 case SIG_SS7_DEFLAW:
3517 newlaw = 0;
3518 break;
3519 case SIG_SS7_ALAW:
3520 newlaw = DAHDI_LAW_ALAW;
3521 break;
3522 case SIG_SS7_ULAW:
3523 newlaw = DAHDI_LAW_MULAW;
3524 break;
3525 }
3526 return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, assignedids, requestor, callid, callid_created);
3527}
3528#endif /* defined(HAVE_SS7) */
3529
3530#if defined(HAVE_SS7)
3531static int sig_ss7_tone_to_dahditone(enum sig_ss7_tone tone)
3532{
3533 switch (tone) {
3535 return DAHDI_TONE_RINGTONE;
3537 return DAHDI_TONE_STUTTER;
3539 return DAHDI_TONE_CONGESTION;
3541 return DAHDI_TONE_DIALTONE;
3543 return DAHDI_TONE_DIALRECALL;
3544 case SIG_SS7_TONE_INFO:
3545 return DAHDI_TONE_INFO;
3546 case SIG_SS7_TONE_BUSY:
3547 return DAHDI_TONE_BUSY;
3548 default:
3549 return -1;
3550 }
3551}
3552#endif /* defined(HAVE_SS7) */
3553
3554#if defined(HAVE_SS7)
3555static int my_ss7_play_tone(void *pvt, enum sig_ss7_tone tone)
3556{
3557 struct dahdi_pvt *p = pvt;
3558
3559 return tone_zone_play_tone(p->subs[SUB_REAL].dfd, sig_ss7_tone_to_dahditone(tone));
3560}
3561#endif /* defined(HAVE_SS7) */
3562
3563#if defined(HAVE_SS7)
3565{
3567 .unlock_private = my_unlock_private,
3568 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3569
3570 .set_echocanceller = my_set_echocanceller,
3571 .set_loopback = my_ss7_set_loopback,
3572
3573 .new_ast_channel = my_new_ss7_ast_channel,
3574 .play_tone = my_ss7_play_tone,
3575
3576 .handle_link_exception = my_handle_link_exception,
3577 .set_alarm = my_set_alarm,
3578 .set_dialing = my_set_dialing,
3579 .set_outgoing = my_set_outgoing,
3580 .set_digital = my_set_digital,
3581 .set_inservice = my_set_inservice,
3582 .set_locallyblocked = my_set_locallyblocked,
3583 .set_remotelyblocked = my_set_remotelyblocked,
3584 .set_callerid = my_set_callerid,
3585 .set_dnid = my_set_dnid,
3586 .open_media = my_pri_ss7_open_media,
3587 .find_linkset = my_ss7_find_linkset,
3588};
3589#endif /* defined(HAVE_SS7) */
3590
3591/*!
3592 * \brief Send MWI state change
3593 *
3594 * \param mailbox This is the mailbox associated with the FXO line that the
3595 * MWI state has changed on.
3596 * \param thereornot This argument should simply be set to 1 or 0, to indicate
3597 * whether there are messages waiting or not.
3598 *
3599 * This function does two things:
3600 *
3601 * 1) It generates an internal Asterisk event notifying any other module that
3602 * cares about MWI that the state of a mailbox has changed.
3603 *
3604 * 2) It runs the script specified by the mwimonitornotify option to allow
3605 * some custom handling of the state change.
3606 */
3607static void notify_message(char *mailbox, int thereornot)
3608{
3609 char s[sizeof(mwimonitornotify) + 164];
3610
3611 if (ast_strlen_zero(mailbox)) {
3612 return;
3613 }
3614
3615 ast_publish_mwi_state(mailbox, NULL, thereornot, thereornot);
3617 snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
3618 ast_safe_system(s);
3619 }
3620}
3621
3622static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
3623{
3624 struct dahdi_pvt *p = pvt;
3625
3626 if (neon_mwievent > -1 && !p->mwimonitor_neon)
3627 return;
3628
3629 if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
3630 ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
3631 notify_message(p->mailbox, 1);
3632 } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
3633 ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
3634 notify_message(p->mailbox, 0);
3635 }
3636 /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
3637 /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
3638 if (neon_mwievent == -1 && p->mwimonitor_rpas) {
3639 ast_hangup(chan);
3640 return;
3641 }
3642}
3643
3644static int my_have_progressdetect(void *pvt)
3645{
3646 struct dahdi_pvt *p = pvt;
3647
3649 && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
3650 return 1;
3651 } else {
3652 /* Don't have progress detection. */
3653 return 0;
3654 }
3655}
3656
3657#define gen_pvt_field_callback(type, field) \
3658 static type my_get_##field(void *pvt) \
3659 { \
3660 struct dahdi_pvt *p = pvt; \
3661 return p->field; \
3662 }
3663
3667
3668#undef gen_pvt_field_callback
3669
3671{
3673 .get_event = my_get_event,
3674 .wait_event = my_wait_event,
3675 .is_off_hook = my_is_off_hook,
3676 .set_echocanceller = my_set_echocanceller,
3677 .ring = my_ring,
3678 .flash = my_flash,
3679 .off_hook = my_off_hook,
3680 .dial_digits = my_dial_digits,
3681 .train_echocanceller = my_train_echocanceller,
3682 .on_hook = my_on_hook,
3683 .is_dialing = my_is_dialing,
3684 .allocate_sub = my_allocate_sub,
3685 .unallocate_sub = my_unallocate_sub,
3686 .swap_subs = my_swap_subchannels,
3687 .has_voicemail = my_has_voicemail,
3688 .check_for_conference = my_check_for_conference,
3689 .conf_add = my_conf_add,
3690 .conf_del = my_conf_del,
3691 .complete_conference_update = my_complete_conference_update,
3692 .start = my_start,
3693 .all_subchannels_hungup = my_all_subchannels_hungup,
3694 .lock_private = my_lock_private,
3695 .unlock_private = my_unlock_private,
3696 .deadlock_avoidance_private = my_deadlock_avoidance_private,
3697 .handle_dtmf = my_handle_dtmf,
3698 .wink = my_wink,
3699 .new_ast_channel = my_new_analog_ast_channel,
3700 .dsp_set_digitmode = my_dsp_set_digitmode,
3701 .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
3702 .send_callerid = my_send_callerid,
3703 .callwait = my_callwait,
3704 .stop_callwait = my_stop_callwait,
3705 .get_callerid = my_get_callerid,
3706 .start_cid_detect = my_start_cid_detect,
3707 .stop_cid_detect = my_stop_cid_detect,
3708 .handle_notify_message = my_handle_notify_message,
3709 .increase_ss_count = my_increase_ss_count,
3710 .decrease_ss_count = my_decrease_ss_count,
3711 .distinctive_ring = my_distinctive_ring,
3712 .set_linear_mode = my_set_linear_mode,
3713 .set_inthreeway = my_set_inthreeway,
3714 .get_and_handle_alarms = my_get_and_handle_alarms,
3715 .get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
3716 .get_sub_fd = my_get_sub_fd,
3717 .set_cadence = my_set_cadence,
3718 .set_alarm = my_set_alarm,
3719 .set_dialing = my_set_dialing,
3720 .set_outgoing = my_set_outgoing,
3721 .set_ringtimeout = my_set_ringtimeout,
3722 .set_waitingfordt = my_set_waitingfordt,
3723 .check_waitingfordt = my_check_waitingfordt,
3724 .set_confirmanswer = my_set_confirmanswer,
3725 .check_confirmanswer = my_check_confirmanswer,
3726 .set_callwaiting = my_set_callwaiting,
3727 .cancel_cidspill = my_cancel_cidspill,
3728 .confmute = my_confmute,
3729 .set_pulsedial = my_set_pulsedial,
3730 .set_new_owner = my_set_new_owner,
3731 .get_orig_dialstring = my_get_orig_dialstring,
3732 .set_needringing = my_set_needringing,
3733 .set_polarity = my_set_polarity,
3734 .start_polarityswitch = my_start_polarityswitch,
3735 .answer_polarityswitch = my_answer_polarityswitch,
3736 .hangup_polarityswitch = my_hangup_polarityswitch,
3737 .have_progressdetect = my_have_progressdetect,
3738 .get_firstdigit_timeout = my_get_firstdigit_timeout,
3739 .get_matchdigit_timeout = my_get_matchdigit_timeout,
3740 .get_interdigit_timeout = my_get_interdigit_timeout,
3741};
3742
3743/*! Round robin search locations. */
3744static struct dahdi_pvt *round_robin[64]; /* groups can range from 0-63 */
3745
3746int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
3747{
3748 int res;
3749 if (p->subs[SUB_REAL].owner == ast)
3750 res = 0;
3751 else if (p->subs[SUB_CALLWAIT].owner == ast)
3752 res = 1;
3753 else if (p->subs[SUB_THREEWAY].owner == ast)
3754 res = 2;
3755 else {
3756 res = -1;
3757 if (!nullok)
3759 "Unable to get index for '%s' on channel %d (%s(), line %lu)\n",
3760 ast ? ast_channel_name(ast) : "", p->channel, fname, line);
3761 }
3762 return res;
3763}
3764
3765/*!
3766 * \internal
3767 * \brief Obtain the specified subchannel owner lock if the owner exists.
3768 *
3769 * \param pvt Channel private struct.
3770 * \param sub_idx Subchannel owner to lock.
3771 *
3772 * \note Assumes the pvt->lock is already obtained.
3773 *
3774 * \note
3775 * Because deadlock avoidance may have been necessary, you need to confirm
3776 * the state of things before continuing.
3777 */
3778static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
3779{
3780 for (;;) {
3781 if (!pvt->subs[sub_idx].owner) {
3782 /* No subchannel owner pointer */
3783 break;
3784 }
3785 if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) {
3786 /* Got subchannel owner lock */
3787 break;
3788 }
3789 /* We must unlock the private to avoid the possibility of a deadlock */
3790 DEADLOCK_AVOIDANCE(&pvt->lock);
3791 }
3792}
3793
3794static void wakeup_sub(struct dahdi_pvt *p, int a)
3795{
3797 if (p->subs[a].owner) {
3800 }
3801}
3802
3803static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
3804{
3805 for (;;) {
3806 if (p->owner) {
3807 if (ast_channel_trylock(p->owner)) {
3809 } else {
3810 ast_queue_frame(p->owner, f);
3812 break;
3813 }
3814 } else
3815 break;
3816 }
3817}
3818
3820{
3821 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3822 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
3823 if (!dahdi_chan) {
3824 return;
3825 }
3826
3827 ast_str_set(&dahdi_chan, 0, "%d", channel);
3828 ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
3829 body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
3830 if (!body) {
3831 return;
3832 }
3833
3834 ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
3835}
3836
3838{
3839 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
3840
3841 ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
3842 body = ast_json_pack("{s: i}", "Span", span);
3843 if (!body) {
3844 return;
3845 }
3846
3847 ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
3848}
3849
3850static void handle_clear_alarms(struct dahdi_pvt *p)
3851{
3852#if defined(HAVE_PRI)
3854 return;
3855 }
3856#endif /* defined(HAVE_PRI) */
3857
3860 }
3863 }
3864}
3865
3866#ifdef HAVE_OPENR2
3867static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
3868{
3869 const struct dahdi_mfcr2 *r2link = p->mfcr2;
3870 struct r2link_entry *cur;
3871 AST_LIST_LOCK(&r2links);
3872 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
3873 if (r2link == &cur->mfcr2) {
3874 ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
3875 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
3876 break;
3877 }
3878 }
3880 AST_LIST_UNLOCK(&r2links);
3881}
3882
3883static int dahdi_r2_answer(struct dahdi_pvt *p)
3884{
3885 int res = 0;
3886 /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
3887 * and does not has support for openr2_chan_answer_call_with_mode
3888 * */
3889#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
3890 const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
3891 int wants_double_answer = ast_true(double_answer) ? 1 : 0;
3892 if (!double_answer) {
3893 /* this still can result in double answer if the channel context
3894 * was configured that way */
3895 res = openr2_chan_answer_call(p->r2chan);
3896 } else if (wants_double_answer) {
3897 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
3898 } else {
3899 res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
3900 }
3901#else
3902 res = openr2_chan_answer_call(p->r2chan);
3903#endif
3904 return res;
3905}
3906
3907
3908
3909/* should be called with the ast_channel locked */
3910static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
3911{
3912 openr2_calling_party_category_t cat;
3913 const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
3914 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
3915 if (ast_strlen_zero(catstr)) {
3916 ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
3917 ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3918 return p->mfcr2_category;
3919 }
3920 if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
3921 ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
3922 catstr, ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
3923 return p->mfcr2_category;
3924 }
3925 ast_debug(1, "Using category %s\n", catstr);
3926 return cat;
3927}
3928
3929static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
3930{
3931 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3932 ast_mutex_lock(&p->lock);
3933 if (p->mfcr2call) {
3935 /* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
3936 interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
3937 can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
3938 the other end will see our seize as a forced release and drop the call, we will see an invalid
3939 pattern that will be seen and treated as protocol error. */
3940 ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
3941 return;
3942 }
3943 p->mfcr2call = 1;
3944 /* better safe than sorry ... */
3945 p->cid_name[0] = '\0';
3946 p->cid_num[0] = '\0';
3947 p->cid_subaddr[0] = '\0';
3948 p->rdnis[0] = '\0';
3949 p->exten[0] = '\0';
3950 p->mfcr2_ani_index = '\0';
3951 p->mfcr2_dnis_index = '\0';
3952 p->mfcr2_dnis_matched = 0;
3953 p->mfcr2_answer_pending = 0;
3954 p->mfcr2_call_accepted = 0;
3956 ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
3957}
3958
3959static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
3960{
3961 int res;
3962 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3963 ast_mutex_lock(&p->lock);
3964 p->inalarm = alarm ? 1 : 0;
3965 if (p->inalarm) {
3966 res = get_alarms(p);
3967 if (res == DAHDI_ALARM_NOTOPEN) {
3968 mfcr2_queue_for_destruction(p);
3969 }
3970 handle_alarms(p, res);
3971 } else {
3973 }
3975}
3976
3977static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
3978{
3979 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3980
3981 ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
3982 ast_mutex_lock(&p->lock);
3983 /* Disconnected? */
3984 if (errorcode == ENODEV) {
3985 struct dahdi_mfcr2 *r2link = p->mfcr2;
3986 p->mfcr2call = 0;
3987 if (r2link) {
3988 r2link->nodev = 1;
3989 }
3990 }
3992}
3993
3994static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
3995{
3996 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
3997 ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
3998 if (p->owner) {
4001 }
4002 ast_mutex_lock(&p->lock);
4003 p->mfcr2call = 0;
4005}
4006
4007static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
4008{
4009 if (openr2_chan_disconnect_call(p->r2chan, cause)) {
4010 ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
4011 p->channel, openr2_proto_get_disconnect_string(cause));
4012 /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
4013 openr2_chan_set_idle(p->r2chan);
4014 ast_mutex_lock(&p->lock);
4015 p->mfcr2call = 0;
4017 }
4018}
4019
4020static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
4021{
4022 struct dahdi_pvt *p;
4023 struct ast_channel *c;
4024 ast_callid callid = 0;
4025 int callid_created = ast_callid_threadstorage_auto(&callid);
4026 ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
4027 openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
4028 openr2_proto_get_category_string(category));
4029 p = openr2_chan_get_client_data(r2chan);
4030 /* if collect calls are not allowed and this is a collect call, reject it! */
4031 if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
4032 ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
4033 dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
4034 goto dahdi_r2_on_call_offered_cleanup;
4035 }
4036 ast_mutex_lock(&p->lock);
4037 p->mfcr2_recvd_category = category;
4038 /* if we're not supposed to use CID, clear whatever we have */
4039 if (!p->use_callerid) {
4040 ast_debug(1, "No CID allowed in configuration, CID is being cleared!\n");
4041 p->cid_num[0] = 0;
4042 p->cid_name[0] = 0;
4043 }
4044 /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
4045 if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
4046 ast_debug(1, "Setting exten => s because of immediate or 0 DNIS configured\n");
4047 p->exten[0] = 's';
4048 p->exten[1] = 0;
4049 }
4051 if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
4052 ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
4053 p->channel, p->exten, p->context);
4054 dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
4055 goto dahdi_r2_on_call_offered_cleanup;
4056 }
4057 if (!p->mfcr2_accept_on_offer) {
4058 /* The user wants us to start the PBX thread right away without accepting the call first */
4059 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4060 if (c) {
4061 /* Done here, don't disable reading now since we still need to generate MF tones to accept
4062 the call or reject it and detect the tone off condition of the other end, all of this
4063 will be done in the PBX thread now */
4064 goto dahdi_r2_on_call_offered_cleanup;
4065 }
4066 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4067 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4068 } else if (p->mfcr2_charge_calls) {
4069 ast_debug(1, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
4070 openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
4071 } else {
4072 ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
4073 openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
4074 }
4075
4076dahdi_r2_on_call_offered_cleanup:
4078}
4079
4080static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
4081{
4082 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4083 ast_verbose("MFC/R2 call end on channel %d\n", p->channel);
4084 ast_mutex_lock(&p->lock);
4085 p->mfcr2call = 0;
4087}
4088
4089static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
4090{
4091 struct dahdi_pvt *p = NULL;
4092 struct ast_channel *c = NULL;
4093 ast_callid callid = 0;
4094 int callid_created = ast_callid_threadstorage_auto(&callid);
4095 p = openr2_chan_get_client_data(r2chan);
4096 dahdi_ec_enable(p);
4097 p->mfcr2_call_accepted = 1;
4098 /* if it's an incoming call ... */
4099 if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
4100 ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
4101 /* If accept on offer is not set, it means at this point the PBX thread is already
4102 launched (was launched in the 'on call offered' handler) and therefore this callback
4103 is being executed already in the PBX thread rather than the monitor thread, don't launch
4104 any other thread, just disable the openr2 reading and answer the call if needed */
4105 if (!p->mfcr2_accept_on_offer) {
4106 openr2_chan_disable_read(r2chan);
4107 if (p->mfcr2_answer_pending) {
4108 ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
4109 dahdi_r2_answer(p);
4110 }
4111 goto dahdi_r2_on_call_accepted_cleanup;
4112 }
4113 c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, NULL, callid);
4114 if (c) {
4115 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
4116 library to forget about it */
4117 openr2_chan_disable_read(r2chan);
4118 goto dahdi_r2_on_call_accepted_cleanup;
4119 }
4120 ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
4121 /* failed to create the channel, bail out and report it as an out of order line */
4122 dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
4123 goto dahdi_r2_on_call_accepted_cleanup;
4124 }
4125 /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
4126 ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p->channel);
4127 p->subs[SUB_REAL].needringing = 1;
4128 p->dialing = 0;
4129 /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
4130 openr2_chan_disable_read(r2chan);
4131
4132dahdi_r2_on_call_accepted_cleanup:
4134}
4135
4136static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
4137{
4138 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4139 ast_verbose("MFC/R2 call has been answered on channel %d\n", openr2_chan_get_number(r2chan));
4140 p->subs[SUB_REAL].needanswer = 1;
4141}
4142
4143static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
4144{
4145 /*ast_debug(1, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
4146}
4147
4148static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
4149{
4150 switch (cause) {
4151 case OR2_CAUSE_BUSY_NUMBER:
4152 return AST_CAUSE_BUSY;
4153 case OR2_CAUSE_NETWORK_CONGESTION:
4154 return AST_CAUSE_CONGESTION;
4155 case OR2_CAUSE_OUT_OF_ORDER:
4157 case OR2_CAUSE_UNALLOCATED_NUMBER:
4159 case OR2_CAUSE_NO_ANSWER:
4160 return AST_CAUSE_NO_ANSWER;
4161 case OR2_CAUSE_NORMAL_CLEARING:
4163 case OR2_CAUSE_UNSPECIFIED:
4164 default:
4165 return AST_CAUSE_NOTDEFINED;
4166 }
4167}
4168
4169static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
4170{
4171 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4172 char cause_str[50];
4173 struct ast_control_pvt_cause_code *cause_code;
4174 int datalen = sizeof(*cause_code);
4175
4176 ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
4177 ast_mutex_lock(&p->lock);
4178 if (!p->owner) {
4180 /* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
4181 dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
4182 return;
4183 }
4184
4185 snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
4186 datalen += strlen(cause_str);
4187 cause_code = ast_alloca(datalen);
4188 memset(cause_code, 0, datalen);
4189 cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
4191 ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
4193 ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
4195
4196 /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
4197 be done in dahdi_hangup */
4201 } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
4202 /* being the forward side we must report what happened to the call to whoever requested it */
4203 switch (cause) {
4204 case OR2_CAUSE_BUSY_NUMBER:
4205 p->subs[SUB_REAL].needbusy = 1;
4206 break;
4207 case OR2_CAUSE_NETWORK_CONGESTION:
4208 case OR2_CAUSE_OUT_OF_ORDER:
4209 case OR2_CAUSE_UNALLOCATED_NUMBER:
4210 case OR2_CAUSE_NO_ANSWER:
4211 case OR2_CAUSE_UNSPECIFIED:
4212 case OR2_CAUSE_NORMAL_CLEARING:
4214 break;
4215 default:
4217 }
4219 } else {
4221 /* being the backward side and not UP yet, we only need to request hangup */
4222 /* TODO: what about doing this same thing when were AST_STATE_UP? */
4223 ast_queue_hangup_with_cause(p->owner, dahdi_r2_cause_to_ast_cause(cause));
4224 }
4225}
4226
4227static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
4228{
4229 switch (level) {
4230 case OR2_LOG_NOTICE:
4231 ast_verbose("%s", logmessage);
4232 break;
4233 case OR2_LOG_WARNING:
4234 ast_log(LOG_WARNING, "%s", logmessage);
4235 break;
4236 case OR2_LOG_ERROR:
4237 ast_log(LOG_ERROR, "%s", logmessage);
4238 break;
4239 case OR2_LOG_STACK_TRACE:
4240 case OR2_LOG_MF_TRACE:
4241 case OR2_LOG_CAS_TRACE:
4242 case OR2_LOG_DEBUG:
4243 case OR2_LOG_EX_DEBUG:
4244 ast_debug(1, "%s", logmessage);
4245 break;
4246 default:
4247 ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
4248 ast_debug(1, "%s", logmessage);
4249 break;
4250 }
4251}
4252
4253static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
4254{
4255 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4256 ast_mutex_lock(&p->lock);
4257 p->remotelyblocked = 1;
4259 ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
4260}
4261
4262static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
4263{
4264 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4265 ast_mutex_lock(&p->lock);
4266 p->remotelyblocked = 0;
4268 ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
4269}
4270
4271static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4272 __attribute__((format (printf, 3, 0)));
4273static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
4274{
4275#define CONTEXT_TAG "Context - "
4276 char logmsg[256];
4277 char completemsg[sizeof(logmsg) * 2];
4278 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4279 snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
4280 dahdi_r2_write_log(level, completemsg);
4281#undef CONTEXT_TAG
4282}
4283
4284static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4285 __attribute__((format (printf, 3, 0)));
4286static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
4287{
4288#define CHAN_TAG "Chan "
4289 char logmsg[256];
4290 char completemsg[sizeof(logmsg) * 2];
4291 vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
4292 snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
4293 dahdi_r2_write_log(level, completemsg);
4294#undef CHAN_TAG
4295}
4296
4297static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
4298{
4299 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4300 /* if 'immediate' is set, let's stop requesting DNIS */
4301 if (p->immediate) {
4302 return 0;
4303 }
4304 p->exten[p->mfcr2_dnis_index] = digit;
4305 p->rdnis[p->mfcr2_dnis_index] = digit;
4306 p->mfcr2_dnis_index++;
4307 p->exten[p->mfcr2_dnis_index] = 0;
4308 p->rdnis[p->mfcr2_dnis_index] = 0;
4309 /* if the DNIS is a match and cannot match more, stop requesting DNIS */
4310 if ((p->mfcr2_dnis_matched ||
4311 (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
4313 return 0;
4314 }
4315 /* otherwise keep going */
4316 return 1;
4317}
4318
4319static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
4320{
4321 struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
4322 p->cid_num[p->mfcr2_ani_index] = digit;
4323 p->cid_name[p->mfcr2_ani_index] = digit;
4324 p->mfcr2_ani_index++;
4325 p->cid_num[p->mfcr2_ani_index] = 0;
4326 p->cid_name[p->mfcr2_ani_index] = 0;
4327}
4328
4329static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
4330{
4331 ast_verbose("MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
4332}
4333
4334static openr2_event_interface_t dahdi_r2_event_iface = {
4335 .on_call_init = dahdi_r2_on_call_init,
4336 .on_call_offered = dahdi_r2_on_call_offered,
4337 .on_call_accepted = dahdi_r2_on_call_accepted,
4338 .on_call_answered = dahdi_r2_on_call_answered,
4339 .on_call_disconnect = dahdi_r2_on_call_disconnect,
4340 .on_call_end = dahdi_r2_on_call_end,
4341 .on_call_read = dahdi_r2_on_call_read,
4342 .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
4343 .on_os_error = dahdi_r2_on_os_error,
4344 .on_protocol_error = dahdi_r2_on_protocol_error,
4345 .on_line_blocked = dahdi_r2_on_line_blocked,
4346 .on_line_idle = dahdi_r2_on_line_idle,
4347 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
4348 .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
4349 .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
4350 .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
4351 /* so far we do nothing with billing pulses */
4352 .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
4353};
4354
4355static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
4356{
4357 return AST_ALAW(sample);
4358}
4359
4360static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
4361{
4362 return AST_LIN2A(sample);
4363}
4364
4365static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
4366 dahdi_r2_alaw_to_linear,
4367 dahdi_r2_linear_to_alaw
4368};
4369
4370#endif /* HAVE_OPENR2 */
4371
4372static void swap_subs(struct dahdi_pvt *p, int a, int b)
4373{
4374 int tchan;
4375 int tinthreeway;
4376 struct ast_channel *towner;
4377
4378 ast_debug(1, "Swapping %d and %d\n", a, b);
4379
4380 tchan = p->subs[a].chan;
4381 towner = p->subs[a].owner;
4382 tinthreeway = p->subs[a].inthreeway;
4383
4384 p->subs[a].chan = p->subs[b].chan;
4385 p->subs[a].owner = p->subs[b].owner;
4386 p->subs[a].inthreeway = p->subs[b].inthreeway;
4387
4388 p->subs[b].chan = tchan;
4389 p->subs[b].owner = towner;
4390 p->subs[b].inthreeway = tinthreeway;
4391
4392 if (p->subs[a].owner)
4393 ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
4394 if (p->subs[b].owner)
4395 ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
4396 wakeup_sub(p, a);
4397 wakeup_sub(p, b);
4398}
4399
4400static int dahdi_open(char *fn)
4401{
4402 int fd;
4403 int isnum;
4404 int chan = 0;
4405 int bs;
4406 int x;
4407 isnum = 1;
4408 for (x = 0; x < strlen(fn); x++) {
4409 if (!isdigit(fn[x])) {
4410 isnum = 0;
4411 break;
4412 }
4413 }
4414 if (isnum) {
4415 chan = atoi(fn);
4416 if (chan < 1) {
4417 ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
4418 return -1;
4419 }
4420 fn = "/dev/dahdi/channel";
4421 }
4422 fd = open(fn, O_RDWR | O_NONBLOCK);
4423 if (fd < 0) {
4424 ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
4425 return -1;
4426 }
4427 if (chan) {
4428 if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
4429 x = errno;
4430 close(fd);
4431 errno = x;
4432 ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
4433 return -1;
4434 }
4435 }
4436 bs = READ_SIZE;
4437 if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
4438 ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
4439 x = errno;
4440 close(fd);
4441 errno = x;
4442 return -1;
4443 }
4444 return fd;
4445}
4446
4447static void dahdi_close(int fd)
4448{
4449 if (fd > 0)
4450 close(fd);
4451}
4452
4453static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
4454{
4455 dahdi_close(chan_pvt->subs[sub_num].dfd);
4456 chan_pvt->subs[sub_num].dfd = -1;
4457}
4458
4459#if defined(HAVE_PRI)
4460static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
4461{
4462 dahdi_close(pri->pri.fds[fd_num]);
4463 pri->pri.fds[fd_num] = -1;
4464}
4465#endif /* defined(HAVE_PRI) */
4466
4467#if defined(HAVE_SS7)
4468static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
4469{
4470 dahdi_close(ss7->ss7.fds[fd_num]);
4471 ss7->ss7.fds[fd_num] = -1;
4472}
4473#endif /* defined(HAVE_SS7) */
4474
4475static int dahdi_setlinear(int dfd, int linear)
4476{
4477 return ioctl(dfd, DAHDI_SETLINEAR, &linear);
4478}
4479
4480
4481static int alloc_sub(struct dahdi_pvt *p, int x)
4482{
4483 struct dahdi_bufferinfo bi;
4484 int res;
4485 if (p->subs[x].dfd >= 0) {
4486 ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
4487 return -1;
4488 }
4489
4490 p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
4491 if (p->subs[x].dfd <= -1) {
4492 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
4493 return -1;
4494 }
4495
4496 res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
4497 if (!res) {
4498 bi.txbufpolicy = p->buf_policy;
4499 bi.rxbufpolicy = p->buf_policy;
4500 bi.numbufs = p->buf_no;
4501 res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
4502 if (res < 0) {
4503 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
4504 }
4505 } else
4506 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
4507
4508 if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
4509 ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
4510 dahdi_close_sub(p, x);
4511 p->subs[x].dfd = -1;
4512 return -1;
4513 }
4514 ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
4515 return 0;
4516}
4517
4518static int unalloc_sub(struct dahdi_pvt *p, int x)
4519{
4520 if (!x) {
4521 ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
4522 return -1;
4523 }
4524 ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
4525 dahdi_close_sub(p, x);
4526 p->subs[x].linear = 0;
4527 p->subs[x].chan = 0;
4528 p->subs[x].owner = NULL;
4529 p->subs[x].inthreeway = 0;
4531 memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
4532 return 0;
4533}
4534
4536{
4537 if (isdigit(digit))
4538 return DAHDI_TONE_DTMF_BASE + (digit - '0');
4539 else if (digit >= 'A' && digit <= 'D')
4540 return DAHDI_TONE_DTMF_A + (digit - 'A');
4541 else if (digit >= 'a' && digit <= 'd')
4542 return DAHDI_TONE_DTMF_A + (digit - 'a');
4543 else if (digit == '*')
4544 return DAHDI_TONE_DTMF_s;
4545 else if (digit == '#')
4546 return DAHDI_TONE_DTMF_p;
4547 else
4548 return -1;
4549}
4550
4551static int dahdi_digit_begin(struct ast_channel *chan, char digit)
4552{
4553 struct dahdi_pvt *pvt;
4554 int idx;
4555 int dtmf;
4556 int res;
4557
4558 pvt = ast_channel_tech_pvt(chan);
4559
4560 ast_mutex_lock(&pvt->lock);
4561
4562 idx = dahdi_get_index(chan, pvt, 0);
4563
4564 if ((idx != SUB_REAL) || !pvt->owner)
4565 goto out;
4566
4567#ifdef HAVE_PRI
4568 switch (pvt->sig) {
4570 res = sig_pri_digit_begin(pvt->sig_pvt, chan, digit);
4571 if (!res)
4572 goto out;
4573 break;
4574 default:
4575 break;
4576 }
4577#endif
4578 dtmf = digit_to_dtmfindex(digit);
4579 if (dtmf == -1) {
4580 /* Not a valid DTMF digit */
4581 goto out;
4582 }
4583
4584 if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
4585 char dial_str[] = { 'T', digit, '\0' };
4586
4587 res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
4588 if (!res) {
4589 pvt->dialing = 1;
4590 }
4591 } else {
4592 pvt->dialing = 1;
4593 pvt->begindigit = digit;
4594
4595 /* Flush the write buffer in DAHDI to start sending the digit immediately. */
4596 dtmf = DAHDI_FLUSH_WRITE;
4597 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
4598 if (res) {
4599 ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
4600 pvt->channel, strerror(errno));
4601 }
4602
4603 ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
4604 ast_channel_name(chan), digit);
4605 }
4606
4607out:
4608 ast_mutex_unlock(&pvt->lock);
4609
4610 return 0;
4611}
4612
4613static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
4614{
4615 struct dahdi_pvt *pvt;
4616 int res = 0;
4617 int idx;
4618 int x;
4619
4620 pvt = ast_channel_tech_pvt(chan);
4621
4622 ast_mutex_lock(&pvt->lock);
4623
4624 idx = dahdi_get_index(chan, pvt, 0);
4625
4626 if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
4627 goto out;
4628
4629#ifdef HAVE_PRI
4630 /* This means that the digit was already sent via PRI signalling */
4631 if (dahdi_sig_pri_lib_handles(pvt->sig) && !pvt->begindigit) {
4632 goto out;
4633 }
4634#endif
4635
4636 if (pvt->begindigit) {
4637 x = -1;
4638 ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
4639 ast_channel_name(chan), digit);
4640 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
4641 pvt->dialing = 0;
4642 pvt->begindigit = 0;
4643 }
4644
4645out:
4646 ast_mutex_unlock(&pvt->lock);
4647
4648 return res;
4649}
4650
4651static const char * const events[] = {
4652 "No event",
4653 "On hook",
4654 "Ring/Answered",
4655 "Wink/Flash",
4656 "Alarm",
4657 "No more alarm",
4658 "HDLC Abort",
4659 "HDLC Overrun",
4660 "HDLC Bad FCS",
4661 "Dial Complete",
4662 "Ringer On",
4663 "Ringer Off",
4664 "Hook Transition Complete",
4665 "Bits Changed",
4666 "Pulse Start",
4667 "Timer Expired",
4668 "Timer Ping",
4669 "Polarity Reversal",
4670 "Ring Begin",
4671};
4672
4673static struct {
4675 char *name;
4676} alarms[] = {
4677 { DAHDI_ALARM_RED, "Red Alarm" },
4678 { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
4679 { DAHDI_ALARM_BLUE, "Blue Alarm" },
4680 { DAHDI_ALARM_RECOVER, "Recovering" },
4681 { DAHDI_ALARM_LOOPBACK, "Loopback" },
4682 { DAHDI_ALARM_NOTOPEN, "Not Open" },
4683 { DAHDI_ALARM_NONE, "None" },
4685
4686static char *alarm2str(int alm)
4687{
4688 int x;
4689 for (x = 0; x < ARRAY_LEN(alarms); x++) {
4690 if (alarms[x].alarm & alm)
4691 return alarms[x].name;
4692 }
4693 return alm ? "Unknown Alarm" : "No Alarm";
4694}
4695
4696static const char *event2str(int event)
4697{
4698 static char buf[256];
4699 if ((event > -1) && (event < (ARRAY_LEN(events))) )
4700 return events[event];
4701 sprintf(buf, "Event %d", event); /* safe */
4702 return buf;
4703}
4704
4705static char *dahdi_sig2str(int sig)
4706{
4707 static char buf[256];
4708 switch (sig) {
4709 case SIG_EM:
4710 return "E & M Immediate";
4711 case SIG_EMWINK:
4712 return "E & M Wink";
4713 case SIG_EM_E1:
4714 return "E & M E1";
4715 case SIG_FEATD:
4716 return "Feature Group D (DTMF)";
4717 case SIG_FEATDMF:
4718 return "Feature Group D (MF)";
4719 case SIG_FEATDMF_TA:
4720 return "Feature Group D (MF) Tandem Access";
4721 case SIG_FEATB:
4722 return "Feature Group B (MF)";
4723 case SIG_E911:
4724 return "E911 (MF)";
4725 case SIG_FGC_CAMA:
4726 return "FGC/CAMA (Dialpulse)";
4727 case SIG_FGC_CAMAMF:
4728 return "FGC/CAMA (MF)";
4729 case SIG_FXSLS:
4730 return "FXS Loopstart";
4731 case SIG_FXSGS:
4732 return "FXS Groundstart";
4733 case SIG_FXSKS:
4734 return "FXS Kewlstart";
4735 case SIG_FXOLS:
4736 return "FXO Loopstart";
4737 case SIG_FXOGS:
4738 return "FXO Groundstart";
4739 case SIG_FXOKS:
4740 return "FXO Kewlstart";
4741 case SIG_PRI:
4742 return "ISDN PRI";
4743 case SIG_BRI:
4744 return "ISDN BRI Point to Point";
4745 case SIG_BRI_PTMP:
4746 return "ISDN BRI Point to MultiPoint";
4747 case SIG_SS7:
4748 return "SS7";
4749 case SIG_MFCR2:
4750 return "MFC/R2";
4751 case SIG_SF:
4752 return "SF (Tone) Immediate";
4753 case SIG_SFWINK:
4754 return "SF (Tone) Wink";
4755 case SIG_SF_FEATD:
4756 return "SF (Tone) with Feature Group D (DTMF)";
4757 case SIG_SF_FEATDMF:
4758 return "SF (Tone) with Feature Group D (MF)";
4759 case SIG_SF_FEATB:
4760 return "SF (Tone) with Feature Group B (MF)";
4761 case 0:
4762 return "Pseudo";
4763 default:
4764 snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
4765 return buf;
4766 }
4767}
4768
4769#define sig2str dahdi_sig2str
4770
4771static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
4772{
4773 /* If the conference already exists, and we're already in it
4774 don't bother doing anything */
4775 struct dahdi_confinfo zi;
4776
4777 memset(&zi, 0, sizeof(zi));
4778 zi.chan = 0;
4779
4780 if (slavechannel > 0) {
4781 /* If we have only one slave, do a digital mon */
4782 zi.confmode = DAHDI_CONF_DIGITALMON;
4783 zi.confno = slavechannel;
4784 } else {
4785 if (!idx) {
4786 /* Real-side and pseudo-side both participate in conference */
4787 zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
4788 DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
4789 } else
4790 zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
4791 zi.confno = p->confno;
4792 }
4793 if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
4794 return 0;
4795 if (c->dfd < 0)
4796 return 0;
4797 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4798 ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
4799 return -1;
4800 }
4801 if (slavechannel < 1) {
4802 p->confno = zi.confno;
4803 }
4804 c->curconf = zi;
4805 ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4806 return 0;
4807}
4808
4809static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
4810{
4811 /* If they're listening to our channel, they're ours */
4812 if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
4813 return 1;
4814 /* If they're a talker on our (allocated) conference, they're ours */
4815 if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
4816 return 1;
4817 return 0;
4818}
4819
4820static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
4821{
4822 struct dahdi_confinfo zi;
4823 if (/* Can't delete if there's no dfd */
4824 (c->dfd < 0) ||
4825 /* Don't delete from the conference if it's not our conference */
4826 !isourconf(p, c)
4827 /* Don't delete if we don't think it's conferenced at all (implied) */
4828 ) return 0;
4829 memset(&zi, 0, sizeof(zi));
4830 if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
4831 ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
4832 return -1;
4833 }
4834 ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
4835 memcpy(&c->curconf, &zi, sizeof(c->curconf));
4836 return 0;
4837}
4838
4839static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
4840{
4841 int x;
4842 int useslavenative;
4843 struct dahdi_pvt *slave = NULL;
4844 /* Start out optimistic */
4845 useslavenative = 1;
4846 /* Update conference state in a stateless fashion */
4847 for (x = 0; x < 3; x++) {
4848 /* Any three-way calling makes slave native mode *definitely* out
4849 of the question */
4850 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
4851 useslavenative = 0;
4852 }
4853 /* If we don't have any 3-way calls, check to see if we have
4854 precisely one slave */
4855 if (useslavenative) {
4856 for (x = 0; x < MAX_SLAVES; x++) {
4857 if (p->slaves[x]) {
4858 if (slave) {
4859 /* Whoops already have a slave! No
4860 slave native and stop right away */
4861 slave = NULL;
4862 useslavenative = 0;
4863 break;
4864 } else {
4865 /* We have one slave so far */
4866 slave = p->slaves[x];
4867 }
4868 }
4869 }
4870 }
4871 /* If no slave, slave native definitely out */
4872 if (!slave)
4873 useslavenative = 0;
4874 else if (slave->law != p->law) {
4875 useslavenative = 0;
4876 slave = NULL;
4877 }
4878 if (out)
4879 *out = slave;
4880 return useslavenative;
4881}
4882
4883static int reset_conf(struct dahdi_pvt *p)
4884{
4885 p->confno = -1;
4886 memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
4887 if (p->subs[SUB_REAL].dfd > -1) {
4888 struct dahdi_confinfo zi;
4889
4890 memset(&zi, 0, sizeof(zi));
4891 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
4892 ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
4893 }
4894 return 0;
4895}
4896
4898{
4899 int needconf = 0;
4900 int x;
4901 int useslavenative;
4902 struct dahdi_pvt *slave = NULL;
4903
4904 useslavenative = isslavenative(p, &slave);
4905 /* Start with the obvious, general stuff */
4906 for (x = 0; x < 3; x++) {
4907 /* Look for three way calls */
4908 if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
4909 conf_add(p, &p->subs[x], x, 0);
4910 needconf++;
4911 } else {
4912 conf_del(p, &p->subs[x], x);
4913 }
4914 }
4915 /* If we have a slave, add him to our conference now. or DAX
4916 if this is slave native */
4917 for (x = 0; x < MAX_SLAVES; x++) {
4918 if (p->slaves[x]) {
4919 if (useslavenative)
4920 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
4921 else {
4922 conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
4923 needconf++;
4924 }
4925 }
4926 }
4927 /* If we're supposed to be in there, do so now */
4928 if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
4929 if (useslavenative)
4930 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
4931 else {
4932 conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
4933 needconf++;
4934 }
4935 }
4936 /* If we have a master, add ourselves to his conference */
4937 if (p->master) {
4938 if (isslavenative(p->master, NULL)) {
4940 } else {
4941 conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
4942 }
4943 }
4944 if (!needconf) {
4945 /* Nobody is left (or should be left) in our conference.
4946 Kill it. */
4947 p->confno = -1;
4948 }
4949 ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
4950}
4951
4953{
4954 int res;
4955 if (!p)
4956 return;
4957 if (p->echocanon) {
4958 ast_debug(1, "Echo cancellation already on\n");
4959 return;
4960 }
4961 if (p->digital) {
4962 ast_debug(1, "Echo cancellation isn't required on digital connection\n");
4963 return;
4964 }
4965 if (p->echocancel.head.tap_length) {
4966#if defined(HAVE_PRI) || defined(HAVE_SS7)
4967 switch (p->sig) {
4968#if defined(HAVE_PRI)
4970 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
4971 /*
4972 * PRI nobch pseudo channel. Does not need ec anyway.
4973 * Does not handle ioctl(DAHDI_AUDIOMODE)
4974 */
4975 return;
4976 }
4977 /* Fall through */
4978#endif /* defined(HAVE_PRI) */
4979#if defined(HAVE_SS7)
4980 case SIG_SS7:
4981#endif /* defined(HAVE_SS7) */
4982 {
4983 int x = 1;
4984
4985 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
4986 if (res)
4988 "Unable to enable audio mode on channel %d (%s)\n",
4989 p->channel, strerror(errno));
4990 }
4991 break;
4992 default:
4993 break;
4994 }
4995#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
4996 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
4997 if (res) {
4998 ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
4999 } else {
5000 p->echocanon = 1;
5001 ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
5002 }
5003 } else
5004 ast_debug(1, "No echo cancellation requested\n");
5005}
5006
5007static void dahdi_train_ec(struct dahdi_pvt *p)
5008{
5009 int x;
5010 int res;
5011
5012 if (p && p->echocanon && p->echotraining) {
5013 x = p->echotraining;
5014 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
5015 if (res)
5016 ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
5017 else
5018 ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
5019 } else {
5020 ast_debug(1, "No echo training requested\n");
5021 }
5022}
5023
5025{
5026 int res;
5027
5028 if (p->echocanon) {
5029 struct dahdi_echocanparams ecp = { .tap_length = 0 };
5030
5031 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
5032
5033 if (res)
5034 ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
5035 else
5036 ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
5037 }
5038
5039 p->echocanon = 0;
5040}
5041
5042static int set_hwgain(int fd, float gain, int tx_direction)
5043{
5044 struct dahdi_hwgain hwgain;
5045
5046 hwgain.newgain = gain * 10.0;
5047 hwgain.tx = tx_direction;
5048 return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
5049}
5050
5051/* perform a dynamic range compression transform on the given sample */
5052static int drc_sample(int sample, float drc)
5053{
5054 float neg;
5055 float shallow, steep;
5056 float max = SHRT_MAX;
5057
5058 neg = (sample < 0 ? -1 : 1);
5059 steep = drc*sample;
5060 shallow = neg*(max-max/drc)+(float)sample/drc;
5061 if (fabsf(steep) < fabsf(shallow)) {
5062 sample = steep;
5063 }
5064 else {
5065 sample = shallow;
5066 }
5067
5068 return sample;
5069}
5070
5071
5072static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
5073{
5074 int j;
5075 int k;
5076
5077 float linear_gain = pow(10.0, gain / 20.0);
5078
5079 switch (law) {
5080 case DAHDI_LAW_ALAW:
5081 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5082 if (gain || drc) {
5083 k = AST_ALAW(j);
5084 if (drc) {
5085 k = drc_sample(k, drc);
5086 }
5087 k = (float)k * linear_gain;
5088 if (k > 32767) {
5089 k = 32767;
5090 } else if (k < -32768) {
5091 k = -32768;
5092 }
5093 g->txgain[j] = AST_LIN2A(k);
5094 } else {
5095 g->txgain[j] = j;
5096 }
5097 }
5098 break;
5099 case DAHDI_LAW_MULAW:
5100 for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
5101 if (gain || drc) {
5102 k = AST_MULAW(j);
5103 if (drc) {
5104 k = drc_sample(k, drc);
5105 }
5106 k = (float)k * linear_gain;
5107 if (k > 32767) {
5108 k = 32767;
5109 } else if (k < -32768) {
5110 k = -32768;
5111 }
5112 g->txgain[j] = AST_LIN2MU(k);
5113
5114 } else {
5115 g->txgain[j] = j;
5116 }
5117 }
5118 break;
5119 }
5120}
5121
5122static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
5123{
5124 int j;
5125 int k;
5126 float linear_gain = pow(10.0, gain / 20.0);
5127
5128 switch (law) {
5129 case DAHDI_LAW_ALAW:
5130 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5131 if (gain || drc) {
5132 k = AST_ALAW(j);
5133 if (drc) {
5134 k = drc_sample(k, drc);
5135 }
5136 k = (float)k * linear_gain;
5137 if (k > 32767) {
5138 k = 32767;
5139 } else if (k < -32768) {
5140 k = -32768;
5141 }
5142 g->rxgain[j] = AST_LIN2A(k);
5143 } else {
5144 g->rxgain[j] = j;
5145 }
5146 }
5147 break;
5148 case DAHDI_LAW_MULAW:
5149 for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
5150 if (gain || drc) {
5151 k = AST_MULAW(j);
5152 if (drc) {
5153 k = drc_sample(k, drc);
5154 }
5155 k = (float)k * linear_gain;
5156 if (k > 32767) {
5157 k = 32767;
5158 } else if (k < -32768) {
5159 k = -32768;
5160 }
5161 g->rxgain[j] = AST_LIN2MU(k);
5162 } else {
5163 g->rxgain[j] = j;
5164 }
5165 }
5166 break;
5167 }
5168}
5169
5170static int set_actual_txgain(int fd, float gain, float drc, int law)
5171{
5172 struct dahdi_gains g;
5173 int res;
5174
5175 memset(&g, 0, sizeof(g));
5176 res = ioctl(fd, DAHDI_GETGAINS, &g);
5177 if (res) {
5178 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5179 return res;
5180 }
5181
5182 fill_txgain(&g, gain, drc, law);
5183
5184 return ioctl(fd, DAHDI_SETGAINS, &g);
5185}
5186
5187static int set_actual_rxgain(int fd, float gain, float drc, int law)
5188{
5189 struct dahdi_gains g;
5190 int res;
5191
5192 memset(&g, 0, sizeof(g));
5193 res = ioctl(fd, DAHDI_GETGAINS, &g);
5194 if (res) {
5195 ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
5196 return res;
5197 }
5198
5199 fill_rxgain(&g, gain, drc, law);
5200
5201 return ioctl(fd, DAHDI_SETGAINS, &g);
5202}
5203
5204static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
5205{
5206 return set_actual_txgain(fd, txgain, txdrc, law) | set_actual_rxgain(fd, rxgain, rxdrc, law);
5207}
5208
5209static int bump_gains(struct dahdi_pvt *p)
5210{
5211 int res;
5212
5213 /* Bump receive gain by value stored in cid_rxgain */
5214 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain + p->cid_rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5215 if (res) {
5216 ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
5217 return -1;
5218 }
5219
5220 return 0;
5221}
5222
5223static int restore_gains(struct dahdi_pvt *p)
5224{
5225 int res;
5226
5227 res = set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5228 if (res) {
5229 ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
5230 return -1;
5231 }
5232
5233 return 0;
5234}
5235
5236static inline int dahdi_set_hook(int fd, int hs)
5237{
5238 int x, res;
5239
5240 x = hs;
5241 res = ioctl(fd, DAHDI_HOOK, &x);
5242
5243 if (res < 0) {
5244 if (errno == EINPROGRESS)
5245 return 0;
5246 ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
5247 /* will expectedly fail if phone is off hook during operation, such as during a restart */
5248 }
5249
5250 return res;
5251}
5252
5253static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
5254{
5255 int x, res;
5256
5257 x = muted;
5258#if defined(HAVE_PRI) || defined(HAVE_SS7)
5259 switch (p->sig) {
5260#if defined(HAVE_PRI)
5262 if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
5263 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
5264 break;
5265 }
5266 /* Fall through */
5267#endif /* defined(HAVE_PRI) */
5268#if defined(HAVE_SS7)
5269 case SIG_SS7:
5270#endif /* defined(HAVE_SS7) */
5271 {
5272 int y = 1;
5273
5274 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
5275 if (res)
5276 ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n",
5277 p->channel, strerror(errno));
5278 }
5279 break;
5280 default:
5281 break;
5282 }
5283#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
5284 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
5285 if (res < 0)
5286 ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
5287 return res;
5288}
5289
5290static int save_conference(struct dahdi_pvt *p)
5291{
5292 struct dahdi_confinfo c;
5293 int res;
5294 if (p->saveconf.confmode) {
5295 ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
5296 return -1;
5297 }
5298 p->saveconf.chan = 0;
5299 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
5300 if (res) {
5301 ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
5302 p->saveconf.confmode = 0;
5303 return -1;
5304 }
5305 memset(&c, 0, sizeof(c));
5306 c.confmode = DAHDI_CONF_NORMAL;
5307 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
5308 if (res) {
5309 ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
5310 return -1;
5311 }
5312 ast_debug(1, "Disabled conferencing\n");
5313 return 0;
5314}
5315
5316static int restore_conference(struct dahdi_pvt *p)
5317{
5318 int res;
5319 if (p->saveconf.confmode) {
5320 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
5321 p->saveconf.confmode = 0;
5322 if (res) {
5323 ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
5324 return -1;
5325 }
5326 ast_debug(1, "Restored conferencing\n");
5327 }
5328 return 0;
5329}
5330
5331static int send_cwcidspill(struct dahdi_pvt *p)
5332{
5333 p->callwaitcas = 0;
5334 p->cidcwexpire = 0;
5335 p->cid_suppress_expire = 0;
5337 return -1;
5339 /* Make sure we account for the end */
5340 p->cidlen += READ_SIZE * 4;
5341 p->cidpos = 0;
5342 send_callerid(p);
5343 ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
5344 return 0;
5345}
5346
5347static int has_voicemail(struct dahdi_pvt *p)
5348{
5349 int new_msgs;
5350 RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
5351
5352 /* A manual MWI disposition has been requested, use that instead
5353 * if this is for sending the new MWI indication. */
5354 if (p->mwioverride_active) {
5355 /* We don't clear p->mwioverride_active automatically,
5356 * because otherwise do_monitor would just change it back to the way it was.
5357 * We need to keep the override active until explicitly disabled by the user,
5358 * so that we can keep returning the correct answer in subsequent calls to do_monitor. */
5359 ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
5360 p->channel, p->mwioverride_disposition ? "active" : "inactive");
5361 return p->mwioverride_disposition;
5362 }
5363
5365 if (mwi_message) {
5366 struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
5367 new_msgs = mwi_state->new_msgs;
5368 } else {
5370 }
5371
5372 return new_msgs;
5373}
5374
5375
5376
5377static int send_callerid(struct dahdi_pvt *p)
5378{
5379 /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
5380 int res;
5381 /* Take out of linear mode if necessary */
5382 if (p->subs[SUB_REAL].linear) {
5383 p->subs[SUB_REAL].linear = 0;
5385 }
5386 while (p->cidpos < p->cidlen) {
5387 res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
5388 ast_debug(4, "writing callerid at pos %d of %d, res = %d\n", p->cidpos, p->cidlen, res);
5389 if (res < 0) {
5390 if (errno == EAGAIN)
5391 return 0;
5392 else {
5393 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
5394 return -1;
5395 }
5396 }
5397 if (!res)
5398 return 0;
5399 p->cidpos += res;
5400 }
5402 ast_free(p->cidspill);
5403 p->cidspill = NULL;
5404 if (p->callwaitcas) {
5405 /* Wait for CID/CW to expire */
5408 } else
5410 return 0;
5411}
5412
5413static int dahdi_callwait(struct ast_channel *ast)
5414{
5415 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5416
5418 if (p->cidspill) {
5419 ast_log(LOG_WARNING, "Spill already exists?!?\n");
5420 ast_free(p->cidspill);
5421 }
5422
5423 /*
5424 * SAS: Subscriber Alert Signal, 440Hz for 300ms
5425 * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
5426 */
5427 if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
5428 return -1;
5429 save_conference(p);
5430 /* Silence */
5431 memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
5432 if (!p->callwaitrings && p->callwaitingcallerid) {
5433 ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
5434 p->callwaitcas = 1;
5435 p->cidlen = 2400 + 680 + READ_SIZE * 4;
5436 } else {
5437 ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
5438 p->callwaitcas = 0;
5439 p->cidlen = 2400 + READ_SIZE * 4;
5440 }
5441 p->cidpos = 0;
5442 send_callerid(p);
5443
5444 return 0;
5445}
5446
5447static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
5448{
5449 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
5450 int x, res, mysig;
5451 char *dest;
5453 AST_APP_ARG(group); /* channel/group token */
5454 AST_APP_ARG(ext); /* extension token */
5455 //AST_APP_ARG(opts); /* options token */
5456 AST_APP_ARG(other); /* Any remaining unused arguments */
5457 );
5458
5459 ast_mutex_lock(&p->lock);
5460 ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
5461
5462 /* Split the dialstring */
5463 dest = ast_strdupa(rdest);
5464 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
5465 if (!args.ext) {
5466 args.ext = "";
5467 }
5468
5469#if defined(HAVE_PRI)
5471 char *subaddr;
5472
5473 sig_pri_extract_called_num_subaddr(p->sig_pvt, rdest, p->exten, sizeof(p->exten));
5474
5475 /* Remove any subaddress for uniformity with incoming calls. */
5476 subaddr = strchr(p->exten, ':');
5477 if (subaddr) {
5478 *subaddr = '\0';
5479 }
5480 } else
5481#endif /* defined(HAVE_PRI) */
5482 {
5483 ast_copy_string(p->exten, args.ext, sizeof(p->exten));
5484 }
5485
5486 if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
5487 p->subs[SUB_REAL].needbusy = 1;
5489 return 0;
5490 }
5492 ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
5494 return -1;
5495 }
5496 p->waitingfordt.tv_sec = 0;
5497 p->dialednone = 0;
5498 if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
5499 {
5500 /* Special pseudo -- automatically up */
5503 return 0;
5504 }
5505 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
5506 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
5507 if (res)
5508 ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
5509 p->outgoing = 1;
5510
5512 set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
5513 } else {
5514 set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
5515 }
5516
5517#ifdef HAVE_PRI
5519 res = sig_pri_call(p->sig_pvt, ast, rdest, timeout,
5520 (p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW);
5522 return res;
5523 }
5524#endif
5525
5526#if defined(HAVE_SS7)
5527 if (p->sig == SIG_SS7) {
5528 res = sig_ss7_call(p->sig_pvt, ast, rdest);
5530 return res;
5531 }
5532#endif /* defined(HAVE_SS7) */
5533
5534 /* If this is analog signalling we can exit here */
5535 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
5536 p->callwaitrings = 0;
5537 res = analog_call(p->sig_pvt, ast, rdest, timeout);
5539 return res;
5540 }
5541
5542 mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
5543 switch (mysig) {
5544 case 0:
5545 /* Special pseudo -- automatically up*/
5547 break;
5548 case SIG_MFCR2:
5549 break;
5550 default:
5551 ast_debug(1, "not yet implemented\n");
5553 return -1;
5554 }
5555
5556#ifdef HAVE_OPENR2
5557 if (p->mfcr2) {
5558 openr2_calling_party_category_t chancat;
5559 int callres = 0;
5560 char *c, *l;
5561
5562 /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
5563 p->dialdest[0] = '\0';
5564
5565 c = args.ext;
5566 if (!p->hidecallerid) {
5568 } else {
5569 l = NULL;
5570 }
5571 if (strlen(c) < p->stripmsd) {
5572 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
5574 return -1;
5575 }
5576 p->dialing = 1;
5577 chancat = dahdi_r2_get_channel_category(ast);
5578 callres = openr2_chan_make_call(p->r2chan, l, (c + p->stripmsd), chancat);
5579 if (-1 == callres) {
5581 ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
5582 return -1;
5583 }
5584 p->mfcr2_call_accepted = 0;
5585 p->mfcr2_progress_sent = 0;
5587 }
5588#endif /* HAVE_OPENR2 */
5590 return 0;
5591}
5592
5593/*!
5594 * \internal
5595 * \brief Insert the given chan_dahdi interface structure into the interface list.
5596 * \since 1.8
5597 *
5598 * \param pvt chan_dahdi private interface structure to insert.
5599 *
5600 * \details
5601 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5602 * Any duplicates are inserted after the existing entries.
5603 *
5604 * \note The new interface must not already be in the list.
5605 */
5606static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
5607{
5608 struct dahdi_pvt *cur;
5609
5611
5612 /* Find place in middle of list for the new interface. */
5613 for (cur = iflist; cur; cur = cur->next) {
5614 if (pvt->channel < cur->channel) {
5615 /* New interface goes before the current interface. */
5616 pvt->prev = cur->prev;
5617 pvt->next = cur;
5618 if (cur->prev) {
5619 /* Insert into the middle of the list. */
5620 cur->prev->next = pvt;
5621 } else {
5622 /* Insert at head of list. */
5623 iflist = pvt;
5624 }
5625 cur->prev = pvt;
5626 return;
5627 }
5628 }
5629
5630 /* New interface goes onto the end of the list */
5631 pvt->prev = ifend;
5632 pvt->next = NULL;
5633 if (ifend) {
5634 ifend->next = pvt;
5635 }
5636 ifend = pvt;
5637 if (!iflist) {
5638 /* List was empty */
5639 iflist = pvt;
5640 }
5641}
5642
5643/*!
5644 * \internal
5645 * \brief Extract the given chan_dahdi interface structure from the interface list.
5646 * \since 1.8
5647 *
5648 * \param pvt chan_dahdi private interface structure to extract.
5649 *
5650 * \note
5651 * The given interface structure can be either in the interface list or a stand alone
5652 * structure that has not been put in the list if the next and prev pointers are NULL.
5653 */
5654static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
5655{
5656 /* Extract from the forward chain. */
5657 if (pvt->prev) {
5658 pvt->prev->next = pvt->next;
5659 } else if (iflist == pvt) {
5660 /* Node is at the head of the list. */
5661 iflist = pvt->next;
5662 }
5663
5664 /* Extract from the reverse chain. */
5665 if (pvt->next) {
5666 pvt->next->prev = pvt->prev;
5667 } else if (ifend == pvt) {
5668 /* Node is at the end of the list. */
5669 ifend = pvt->prev;
5670 }
5671
5672 /* Node is no longer in the list. */
5674 pvt->prev = NULL;
5675 pvt->next = NULL;
5676}
5677
5678#if defined(HAVE_PRI)
5679/*!
5680 * \internal
5681 * \brief Insert the given chan_dahdi interface structure into the no B channel list.
5682 * \since 1.8
5683 *
5684 * \param pri sig_pri span control structure holding no B channel list.
5685 * \param pvt chan_dahdi private interface structure to insert.
5686 *
5687 * \details
5688 * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
5689 * Any duplicates are inserted after the existing entries.
5690 *
5691 * \note The new interface must not already be in the list.
5692 */
5693static void dahdi_nobch_insert(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5694{
5695 struct dahdi_pvt *cur;
5696
5697 pvt->which_iflist = DAHDI_IFLIST_NO_B_CHAN;
5698
5699 /* Find place in middle of list for the new interface. */
5700 for (cur = pri->no_b_chan_iflist; cur; cur = cur->next) {
5701 if (pvt->channel < cur->channel) {
5702 /* New interface goes before the current interface. */
5703 pvt->prev = cur->prev;
5704 pvt->next = cur;
5705 if (cur->prev) {
5706 /* Insert into the middle of the list. */
5707 cur->prev->next = pvt;
5708 } else {
5709 /* Insert at head of list. */
5710 pri->no_b_chan_iflist = pvt;
5711 }
5712 cur->prev = pvt;
5713 return;
5714 }
5715 }
5716
5717 /* New interface goes onto the end of the list */
5718 pvt->prev = pri->no_b_chan_end;
5719 pvt->next = NULL;
5720 if (pri->no_b_chan_end) {
5721 ((struct dahdi_pvt *) pri->no_b_chan_end)->next = pvt;
5722 }
5723 pri->no_b_chan_end = pvt;
5724 if (!pri->no_b_chan_iflist) {
5725 /* List was empty */
5726 pri->no_b_chan_iflist = pvt;
5727 }
5728}
5729#endif /* defined(HAVE_PRI) */
5730
5731#if defined(HAVE_PRI)
5732/*!
5733 * \internal
5734 * \brief Extract the given chan_dahdi interface structure from the no B channel list.
5735 * \since 1.8
5736 *
5737 * \param pri sig_pri span control structure holding no B channel list.
5738 * \param pvt chan_dahdi private interface structure to extract.
5739 *
5740 * \note
5741 * The given interface structure can be either in the interface list or a stand alone
5742 * structure that has not been put in the list if the next and prev pointers are NULL.
5743 */
5744static void dahdi_nobch_extract(struct sig_pri_span *pri, struct dahdi_pvt *pvt)
5745{
5746 /* Extract from the forward chain. */
5747 if (pvt->prev) {
5748 pvt->prev->next = pvt->next;
5749 } else if (pri->no_b_chan_iflist == pvt) {
5750 /* Node is at the head of the list. */
5751 pri->no_b_chan_iflist = pvt->next;
5752 }
5753
5754 /* Extract from the reverse chain. */
5755 if (pvt->next) {
5756 pvt->next->prev = pvt->prev;
5757 } else if (pri->no_b_chan_end == pvt) {
5758 /* Node is at the end of the list. */
5759 pri->no_b_chan_end = pvt->prev;
5760 }
5761
5762 /* Node is no longer in the list. */
5764 pvt->prev = NULL;
5765 pvt->next = NULL;
5766}
5767#endif /* defined(HAVE_PRI) */
5768
5769#if defined(HAVE_PRI)
5770/*!
5771 * \internal
5772 * \brief Unlink the channel interface from the PRI private pointer array.
5773 * \since 1.8
5774 *
5775 * \param pvt chan_dahdi private interface structure to unlink.
5776 */
5777static void dahdi_unlink_pri_pvt(struct dahdi_pvt *pvt)
5778{
5779 unsigned idx;
5780 struct sig_pri_span *pri;
5781
5782 pri = pvt->pri;
5783 if (!pri) {
5784 /* Not PRI signaling so cannot be in a PRI private pointer array. */
5785 return;
5786 }
5787 ast_mutex_lock(&pri->lock);
5788 for (idx = 0; idx < pri->numchans; ++idx) {
5789 if (pri->pvts[idx] == pvt->sig_pvt) {
5790 pri->pvts[idx] = NULL;
5791 ast_mutex_unlock(&pri->lock);
5792 return;
5793 }
5794 }
5795 ast_mutex_unlock(&pri->lock);
5796}
5797#endif /* defined(HAVE_PRI) */
5798
5799#if defined(HAVE_SS7)
5800/*!
5801 * \internal
5802 * \brief Unlink the channel interface from the SS7 private pointer array.
5803 * \since 1.8
5804 *
5805 * \param pvt chan_dahdi private interface structure to unlink.
5806 */
5807static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
5808{
5809 unsigned idx;
5810 struct sig_ss7_linkset *ss7;
5811
5812 ss7 = pvt->ss7;
5813 if (!ss7) {
5814 /* Not SS7 signaling so cannot be in a SS7 private pointer array. */
5815 return;
5816 }
5817 ast_mutex_lock(&ss7->lock);
5818 for (idx = 0; idx < ss7->numchans; ++idx) {
5819 if (ss7->pvts[idx] == pvt->sig_pvt) {
5820 ss7->pvts[idx] = NULL;
5821 ast_mutex_unlock(&ss7->lock);
5822 return;
5823 }
5824 }
5825 ast_mutex_unlock(&ss7->lock);
5826}
5827#endif /* defined(HAVE_SS7) */
5828
5829#if defined(HAVE_OPENR2)
5830/*!
5831 * \internal
5832 * \brief Unlink the channel interface from the MFC/R2 private pointer array.
5833 *
5834 * \param pvt chan_dahdi private interface structure to unlink.
5835 */
5836static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
5837{
5838 unsigned idx;
5839 struct dahdi_mfcr2 *mfcr2;
5840 int should_destroy_link = 0;
5841
5842 ast_mutex_lock(&pvt->lock);
5843 if (pvt->r2chan) {
5844 ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
5845 openr2_chan_disable_read(pvt->r2chan);
5846 }
5847 mfcr2 = pvt->mfcr2;
5848 if (mfcr2) {
5849 for (idx = 0; idx < mfcr2->numchans; ++idx) {
5850 if (mfcr2->pvts[idx] == pvt) {
5851 ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
5852 mfcr2->pvts[idx] = NULL;
5853 mfcr2->live_chans--;
5854 break;
5855 }
5856 }
5857 if (!mfcr2->live_chans) {
5858 ast_debug(1, "MFC/R2 link is now empty\n");
5859 should_destroy_link = 1;
5860 }
5861 }
5862 ast_mutex_unlock(&pvt->lock);
5863 if (should_destroy_link) {
5864 ast_debug(1, "MFC/R2 link is now empty\n");
5865 mfcr2_queue_for_destruction(pvt);
5866 }
5867}
5868#endif /* defined(HAVE_OPENR2) */
5869
5871{
5872 if (cur->next && cur->next->span == cur->span) {
5873 return cur->next;
5874 } else if (cur->prev && cur->prev->span == cur->span) {
5875 return cur->prev;
5876 }
5877
5878 return NULL;
5879}
5880
5881static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
5882{
5883 struct dahdi_pvt *p = pvt;
5884
5885 if (p->manages_span_alarms) {
5887 if (next) {
5889 }
5890 }
5891
5892 /* Remove channel from the list */
5893#if defined(HAVE_PRI)
5894 dahdi_unlink_pri_pvt(p);
5895#endif /* defined(HAVE_PRI) */
5896#if defined(HAVE_SS7)
5897 dahdi_unlink_ss7_pvt(p);
5898#endif /* defined(HAVE_SS7) */
5899#if defined(HAVE_OPENR2)
5900 dahdi_unlink_mfcr2_pvt(p);
5901#endif /* defined(HAVE_SS7) */
5902 switch (pvt->which_iflist) {
5903 case DAHDI_IFLIST_NONE:
5904 break;
5905 case DAHDI_IFLIST_MAIN:
5907 break;
5908#if defined(HAVE_PRI)
5909 case DAHDI_IFLIST_NO_B_CHAN:
5910 if (p->pri) {
5911 dahdi_nobch_extract(p->pri, p);
5912 }
5913 break;
5914#endif /* defined(HAVE_PRI) */
5915 }
5916
5917 if (p->sig_pvt) {
5918 if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
5920 }
5921 switch (p->sig) {
5922#if defined(HAVE_PRI)
5925 break;
5926#endif /* defined(HAVE_PRI) */
5927#if defined(HAVE_SS7)
5928 case SIG_SS7:
5930 break;
5931#endif /* defined(HAVE_SS7) */
5932 default:
5933 break;
5934 }
5935 }
5936 ast_free(p->cidspill);
5937 if (p->use_smdi) {
5939 }
5940 if (p->mwi_event_sub) {
5942 }
5943 if (p->vars) {
5945 }
5946 if (p->cc_params) {
5948 }
5949
5952
5955 if (p->owner) {
5957 }
5958 ast_free(p);
5959}
5960
5961static void destroy_channel(struct dahdi_pvt *cur, int now)
5962{
5963 int i;
5964
5965 if (!now) {
5966 /* Do not destroy the channel now if it is owned by someone. */
5967 if (cur->owner) {
5968 return;
5969 }
5970 for (i = 0; i < 3; i++) {
5971 if (cur->subs[i].owner) {
5972 return;
5973 }
5974 }
5975 }
5976 destroy_dahdi_pvt(cur);
5977}
5978
5979static void destroy_all_channels(void)
5980{
5981 int chan;
5982#if defined(HAVE_PRI)
5983 unsigned span;
5984 struct sig_pri_span *pri;
5985#endif /* defined(HAVE_PRI) */
5986 struct dahdi_pvt *p;
5987
5988 while (num_restart_pending) {
5989 usleep(1);
5990 }
5991
5993 /* Destroy all the interfaces and free their memory */
5994 while (iflist) {
5995 p = iflist;
5996
5997 chan = p->channel;
5998#if defined(HAVE_PRI_SERVICE_MESSAGES)
5999 {
6000 char db_chan_name[20];
6001 char db_answer[5];
6002 char state;
6003 int why = -1;
6004
6005 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, p->span, chan);
6006 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
6007 sscanf(db_answer, "%1c:%30d", &state, &why);
6008 }
6009 if (!why) {
6010 /* SRVST persistence is not required */
6011 ast_db_del(db_chan_name, SRVST_DBKEY);
6012 }
6013 }
6014#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
6015 /* Free associated memory */
6017 ast_verb(3, "Unregistered channel %d\n", chan);
6018 }
6019 ifcount = 0;
6021
6022#if defined(HAVE_PRI)
6023 /* Destroy all of the no B channel interface lists */
6024 for (span = 0; span < NUM_SPANS; ++span) {
6025 if (!pris[span].dchannels[0]) {
6026 break;
6027 }
6028 pri = &pris[span].pri;
6029 ast_mutex_lock(&pri->lock);
6030 while (pri->no_b_chan_iflist) {
6031 p = pri->no_b_chan_iflist;
6032
6033 /* Free associated memory */
6035 }
6036 ast_mutex_unlock(&pri->lock);
6037 }
6038#endif /* defined(HAVE_PRI) */
6039}
6040
6041#if defined(HAVE_PRI)
6042static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
6043
6044static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char *digits)
6045{
6046 /* Data will be our digit string */
6047 struct dahdi_pvt *p;
6048
6049 if (ast_strlen_zero(digits)) {
6050 ast_debug(1, "No digit string sent to application!\n");
6051 return -1;
6052 }
6053
6054 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6055
6056 if (!p) {
6057 ast_debug(1, "Unable to find technology private\n");
6058 return -1;
6059 }
6060
6062
6063 return 0;
6064}
6065#endif /* defined(HAVE_PRI) */
6066
6067#if defined(HAVE_PRI)
6068#if defined(HAVE_PRI_PROG_W_CAUSE)
6069static char *dahdi_send_callrerouting_facility_app = "DAHDISendCallreroutingFacility";
6070
6071static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
6072{
6073 /* Data will be our digit string */
6074 struct dahdi_pvt *pvt;
6075 char *parse;
6076 int res;
6078 AST_APP_ARG(destination);
6079 AST_APP_ARG(original);
6080 AST_APP_ARG(reason);
6081 );
6082
6083 if (ast_strlen_zero(data)) {
6084 ast_debug(1, "No data sent to application!\n");
6085 return -1;
6086 }
6087 if (ast_channel_tech(chan) != &dahdi_tech) {
6088 ast_debug(1, "Only DAHDI technology accepted!\n");
6089 return -1;
6090 }
6091 pvt = (struct dahdi_pvt *) ast_channel_tech_pvt(chan);
6092 if (!pvt) {
6093 ast_debug(1, "Unable to find technology private\n");
6094 return -1;
6095 }
6096 switch (pvt->sig) {
6098 break;
6099 default:
6100 ast_debug(1, "callrerouting attempted on non-ISDN channel %s\n",
6101 ast_channel_name(chan));
6102 return -1;
6103 }
6104
6105 parse = ast_strdupa(data);
6107
6108 if (ast_strlen_zero(args.destination)) {
6109 ast_log(LOG_WARNING, "callrerouting facility requires at least destination number argument\n");
6110 return -1;
6111 }
6112
6113 if (ast_strlen_zero(args.original)) {
6114 ast_log(LOG_WARNING, "Callrerouting Facility without original called number argument\n");
6115 args.original = NULL;
6116 }
6117
6118 if (ast_strlen_zero(args.reason)) {
6119 ast_log(LOG_NOTICE, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n");
6120 args.reason = NULL;
6121 }
6122
6124 args.destination, args.original, args.reason);
6125 if (!res) {
6126 /*
6127 * Wait up to 5 seconds for a reply before hanging up this call
6128 * leg if the peer does not disconnect first.
6129 */
6130 ast_safe_sleep(chan, 5000);
6131 }
6132
6133 return -1;
6134}
6135#endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
6136#endif /* defined(HAVE_PRI) */
6137
6138#if defined(HAVE_OPENR2)
6139static const char * const dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
6140
6141static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
6142{
6143 /* data is whether to accept with charge or no charge */
6144 openr2_call_mode_t accept_mode;
6145 int res, timeout, maxloops;
6146 struct ast_frame *f;
6147 struct dahdi_pvt *p;
6148 char *parse;
6150 AST_APP_ARG(charge);
6151 );
6152
6153 if (ast_strlen_zero(data)) {
6154 ast_debug(1, "No data sent to application!\n");
6155 return -1;
6156 }
6157
6158 if (ast_channel_tech(chan) != &dahdi_tech) {
6159 ast_debug(1, "Only DAHDI technology accepted!\n");
6160 return -1;
6161 }
6162
6163 p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
6164 if (!p) {
6165 ast_debug(1, "Unable to find technology private!\n");
6166 return -1;
6167 }
6168
6169 parse = ast_strdupa(data);
6171
6172 if (ast_strlen_zero(args.charge)) {
6173 ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
6174 return -1;
6175 }
6176
6177 ast_mutex_lock(&p->lock);
6178 if (!p->mfcr2 || !p->mfcr2call) {
6180 ast_debug(1, "Channel %s does not seems to be an R2 active channel!\n", ast_channel_name(chan));
6181 return -1;
6182 }
6183
6184 if (p->mfcr2_call_accepted) {
6186 ast_debug(1, "MFC/R2 call already accepted on channel %s!\n", ast_channel_name(chan));
6187 return 0;
6188 }
6189 accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
6190 if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
6192 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6193 return -1;
6194 }
6196
6197 res = 0;
6198 timeout = 100;
6199 maxloops = 50; /* wait up to 5 seconds */
6200 /* we need to read() until the call is accepted */
6201 while (maxloops > 0) {
6202 maxloops--;
6203 if (ast_check_hangup(chan)) {
6204 break;
6205 }
6206 res = ast_waitfor(chan, timeout);
6207 if (res < 0) {
6208 ast_debug(1, "ast_waitfor failed on channel %s, going out ...\n", ast_channel_name(chan));
6209 res = -1;
6210 break;
6211 }
6212 if (res == 0) {
6213 continue;
6214 }
6215 res = 0;
6216 f = ast_read(chan);
6217 if (!f) {
6218 ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
6219 res = -1;
6220 break;
6221 }
6223 ast_debug(1, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
6224 ast_frfree(f);
6225 res = -1;
6226 break;
6227 }
6228 ast_frfree(f);
6229 ast_mutex_lock(&p->lock);
6230 if (p->mfcr2_call_accepted) {
6232 ast_debug(1, "Accepted MFC/R2 call!\n");
6233 break;
6234 }
6236 }
6237 if (res == -1) {
6238 ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
6239 }
6240 return res;
6241}
6242
6243static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
6244{
6245 openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
6246 switch (cause) {
6249 case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
6250 r2cause = OR2_CAUSE_BUSY_NUMBER;
6251 break;
6252
6255 r2cause = OR2_CAUSE_NETWORK_CONGESTION;
6256 break;
6257
6259 r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
6260 break;
6261
6264 r2cause = OR2_CAUSE_OUT_OF_ORDER;
6265 break;
6266
6269 r2cause = OR2_CAUSE_NO_ANSWER;
6270 break;
6271
6272 default:
6273 r2cause = OR2_CAUSE_NORMAL_CLEARING;
6274 break;
6275 }
6276 ast_debug(1, "ast cause %d resulted in openr2 cause %d/%s\n",
6277 cause, r2cause, openr2_proto_get_disconnect_string(r2cause));
6278 return r2cause;
6279}
6280#endif
6281
6282static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
6283{
6284 if (p->bufferoverrideinuse) {
6285 /* faxbuffers are in use, revert them */
6286 struct dahdi_bufferinfo bi = {
6287 .txbufpolicy = p->buf_policy,
6288 .rxbufpolicy = p->buf_policy,
6289 .bufsize = p->bufsize,
6290 .numbufs = p->buf_no
6291 };
6292 int bpres;
6293
6294 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
6295 ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast_channel_name(ast), strerror(errno));
6296 }
6297 p->bufferoverrideinuse = 0;
6298 return bpres;
6299 }
6300
6301 return -1;
6302}
6303
6304static int dahdi_hangup(struct ast_channel *ast)
6305{
6306 int res = 0;
6307 int idx,x;
6308 int law;
6309 /*static int restore_gains(struct dahdi_pvt *p);*/
6310 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6311 struct dahdi_params par;
6312
6313 ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast));
6314 if (!ast_channel_tech_pvt(ast)) {
6315 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
6316 return 0;
6317 }
6318
6319 ast_mutex_lock(&p->lock);
6320 p->exten[0] = '\0';
6321 /* Always use sig_analog hangup handling for operator mode */
6322 if (dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6323 p->oprmode = 0;
6324 dahdi_confmute(p, 0);
6325 restore_gains(p);
6326 p->ignoredtmf = 0;
6327 p->waitingfordt.tv_sec = 0;
6328
6329 res = analog_hangup(p->sig_pvt, ast);
6330 revert_fax_buffers(p, ast);
6331
6332 goto hangup_out;
6333 } else {
6334 p->cid_num[0] = '\0';
6335 p->cid_name[0] = '\0';
6336 p->cid_subaddr[0] = '\0';
6337 }
6338
6339#if defined(HAVE_PRI)
6341 x = 1;
6342 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6343
6344 dahdi_confmute(p, 0);
6345 p->muting = 0;
6346 restore_gains(p);
6347 if (p->dsp) {
6348 ast_dsp_free(p->dsp);
6349 p->dsp = NULL;
6350 }
6351 p->ignoredtmf = 0;
6352
6353 /* Real channel, do some fixup */
6354 p->subs[SUB_REAL].owner = NULL;
6355 p->subs[SUB_REAL].needbusy = 0;
6357
6358 p->owner = NULL;
6359 p->cid_tag[0] = '\0';
6360 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6361 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6362 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6363 p->outgoing = 0;
6364 p->digital = 0;
6365 p->faxhandled = 0;
6366 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6367
6368 revert_fax_buffers(p, ast);
6369
6370 p->law = p->law_default;
6371 law = p->law_default;
6372 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6373 if (res < 0) {
6374 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6375 p->channel, strerror(errno));
6376 }
6377
6378 sig_pri_hangup(p->sig_pvt, ast);
6379
6380 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6382
6383 x = 0;
6384 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6385 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6386
6387 p->rdnis[0] = '\0';
6389 reset_conf(p);
6390
6391 /* Restore data mode */
6392 x = 0;
6393 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6394
6395 if (num_restart_pending == 0) {
6397 }
6398 goto hangup_out;
6399 }
6400#endif /* defined(HAVE_PRI) */
6401
6402#if defined(HAVE_SS7)
6403 if (p->sig == SIG_SS7) {
6404 x = 1;
6405 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6406
6407 dahdi_confmute(p, 0);
6408 p->muting = 0;
6409 restore_gains(p);
6410 if (p->dsp) {
6411 ast_dsp_free(p->dsp);
6412 p->dsp = NULL;
6413 }
6414 p->ignoredtmf = 0;
6415
6416 /* Real channel, do some fixup */
6417 p->subs[SUB_REAL].owner = NULL;
6418 p->subs[SUB_REAL].needbusy = 0;
6420
6421 p->owner = NULL;
6422 p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
6423 p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
6424 p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
6425 p->outgoing = 0;
6426 p->digital = 0;
6427 p->faxhandled = 0;
6428 p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
6429
6430 revert_fax_buffers(p, ast);
6431
6432 p->law = p->law_default;
6433 law = p->law_default;
6434 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6435 if (res < 0) {
6436 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
6437 p->channel, strerror(errno));
6438 }
6439
6440 sig_ss7_hangup(p->sig_pvt, ast);
6441
6442 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6444
6445 x = 0;
6446 ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
6447 p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
6448
6450 reset_conf(p);
6451
6452 /* Restore data mode */
6453 x = 0;
6454 ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
6455
6456 if (num_restart_pending == 0) {
6458 }
6459 goto hangup_out;
6460 }
6461#endif /* defined(HAVE_SS7) */
6462
6463 idx = dahdi_get_index(ast, p, 1);
6464
6465 dahdi_confmute(p, 0);
6466 p->muting = 0;
6467 restore_gains(p);
6468 if (p->origcid_num) {
6469 ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
6471 p->origcid_num = NULL;
6472 }
6473 if (p->origcid_name) {
6474 ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
6476 p->origcid_name = NULL;
6477 }
6478 if (p->dsp)
6480
6481 ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
6482 p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
6483 p->ignoredtmf = 0;
6484
6485 if (idx > -1) {
6486 /* Real channel, do some fixup */
6487 p->subs[idx].owner = NULL;
6488 p->subs[idx].needanswer = 0;
6489 p->subs[idx].needflash = 0;
6490 p->subs[idx].needringing = 0;
6491 p->subs[idx].needbusy = 0;
6492 p->subs[idx].needcongestion = 0;
6493 p->subs[idx].linear = 0;
6495 dahdi_setlinear(p->subs[idx].dfd, 0);
6496 if (idx == SUB_REAL) {
6497 if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
6498 ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
6499 if (p->subs[SUB_CALLWAIT].inthreeway) {
6500 /* We had flipped over to answer a callwait and now it's gone */
6501 ast_debug(1, "We were flipped over to the callwait, moving back and not owning.\n");
6502 /* Move to the call-wait, but un-own us until they flip back. */
6505 p->owner = NULL;
6506 } else {
6507 /* The three way hung up, but we still have a call wait */
6508 ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
6511 if (p->subs[SUB_REAL].inthreeway) {
6512 /* This was part of a three way call. Immediately make way for
6513 another call */
6514 ast_debug(1, "Call was complete, setting owner to former third call\n");
6515 p->owner = p->subs[SUB_REAL].owner;
6516 } else {
6517 /* This call hasn't been completed yet... Set owner to NULL */
6518 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6519 p->owner = NULL;
6520 }
6521 p->subs[SUB_REAL].inthreeway = 0;
6522 }
6523 } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
6524 /* Move to the call-wait and switch back to them. */
6527 p->owner = p->subs[SUB_REAL].owner;
6529 p->subs[SUB_REAL].needanswer = 1;
6531 } else if (p->subs[SUB_THREEWAY].dfd > -1) {
6534 if (p->subs[SUB_REAL].inthreeway) {
6535 /* This was part of a three way call. Immediately make way for
6536 another call */
6537 ast_debug(1, "Call was complete, setting owner to former third call\n");
6538 p->owner = p->subs[SUB_REAL].owner;
6539 } else {
6540 /* This call hasn't been completed yet... Set owner to NULL */
6541 ast_debug(1, "Call was incomplete, setting owner to NULL\n");
6542 p->owner = NULL;
6543 }
6544 p->subs[SUB_REAL].inthreeway = 0;
6545 }
6546 } else if (idx == SUB_CALLWAIT) {
6547 /* Ditch the holding callwait call, and immediately make it available */
6548 if (p->subs[SUB_CALLWAIT].inthreeway) {
6549 /* This is actually part of a three way, placed on hold. Place the third part
6550 on music on hold now */
6551 if (p->subs[SUB_THREEWAY].owner) {
6553 }
6555 /* Make it the call wait now */
6558 } else
6560 } else if (idx == SUB_THREEWAY) {
6561 if (p->subs[SUB_CALLWAIT].inthreeway) {
6562 /* The other party of the three way call is currently in a call-wait state.
6563 Start music on hold for them, and take the main guy out of the third call */
6564 if (p->subs[SUB_CALLWAIT].owner) {
6566 }
6568 }
6569 p->subs[SUB_REAL].inthreeway = 0;
6570 /* If this was part of a three way call index, let us make
6571 another three way call */
6573 } else {
6574 /* This wasn't any sort of call, but how are we an index? */
6575 ast_log(LOG_WARNING, "Index found but not any type of call?\n");
6576 }
6577 }
6578
6579 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
6580 p->owner = NULL;
6581 p->ringt = 0;
6582 p->distinctivering = 0;
6583 p->confirmanswer = 0;
6584 p->outgoing = 0;
6585 p->digital = 0;
6586 p->faxhandled = 0;
6587 p->pulsedial = 0;
6588 if (p->dsp) {
6589 ast_dsp_free(p->dsp);
6590 p->dsp = NULL;
6591 }
6592
6593 revert_fax_buffers(p, ast);
6594
6595 p->law = p->law_default;
6596 law = p->law_default;
6597 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
6598 if (res < 0)
6599 ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
6600 /* Perform low level hangup if no owner left */
6601#ifdef HAVE_OPENR2
6602 if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
6603 ast_debug(1, "disconnecting MFC/R2 call on chan %d\n", p->channel);
6604 /* If it's an incoming call, check the mfcr2_forced_release setting */
6605 if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
6606 dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
6607 } else {
6608 const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
6609 int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
6610 openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
6611 : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast));
6612 dahdi_r2_disconnect_call(p, r2cause);
6613 }
6614 } else if (p->mfcr2call) {
6615 ast_debug(1, "Clearing call request on channel %d\n", p->channel);
6616 /* since ast_request() was called but not ast_call() we have not yet dialed
6617 and the openr2 stack will not call on_call_end callback, we need to unset
6618 the mfcr2call flag and bump the monitor count so the monitor thread can take
6619 care of this channel events from now on */
6620 p->mfcr2call = 0;
6621 }
6622#endif
6623 switch (p->sig) {
6624 case SIG_SS7:
6625 case SIG_MFCR2:
6627 case 0:
6628 break;
6629 default:
6630 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
6631 break;
6632 }
6633 if (res < 0) {
6634 ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast_channel_name(ast));
6635 }
6636 switch (p->sig) {
6637 case SIG_FXOGS:
6638 case SIG_FXOLS:
6639 case SIG_FXOKS:
6640 memset(&par, 0, sizeof(par));
6641 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
6642 if (!res) {
6643 struct analog_pvt *analog_p = p->sig_pvt;
6644#if 0
6645 ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
6646#endif
6647 /* If they're off hook, try playing congestion */
6648 if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
6649 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
6650 else
6651 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6652 analog_p->fxsoffhookstate = par.rxisoffhook;
6653 }
6654 break;
6655 case SIG_FXSGS:
6656 case SIG_FXSLS:
6657 case SIG_FXSKS:
6658 /* Make sure we're not made available for at least two seconds assuming
6659 we were actually used for an inbound or outbound call. */
6661 time(&p->guardtime);
6662 p->guardtime += 2;
6663 }
6664 break;
6665 default:
6666 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
6667 break;
6668 }
6669 if (p->sig)
6671 x = 0;
6672 ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
6673 ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
6674 p->didtdd = 0;
6675 p->callwaitcas = 0;
6678 if (dahdi_analog_lib_handles(p->sig, p->radio, 0) && !p->owner) {
6679 /* The code in sig_analog handles resetting to permdialmode on originations;
6680 * this addresses the edge case of multiple calls that do not involve
6681 * origination inbetween, i.e. multiple incoming calls. */
6682 struct analog_pvt *analog_p = p->sig_pvt;
6683 /* If no calls remain, reset dialmode.
6684 * This way, if the next call is an incoming call,
6685 * it's already been reset. */
6686 analog_p->dialmode = analog_p->permdialmode;
6687 }
6688 p->waitingfordt.tv_sec = 0;
6689 p->dialing = 0;
6690 p->rdnis[0] = '\0';
6692 reset_conf(p);
6693 /* Restore data mode */
6694 switch (p->sig) {
6696 case SIG_SS7:
6697 x = 0;
6698 ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
6699 break;
6700 default:
6701 break;
6702 }
6703 if (num_restart_pending == 0)
6705 }
6706
6707 p->callwaitingrepeat = 0;
6708 p->cidcwexpire = 0;
6709 p->cid_suppress_expire = 0;
6710 p->oprmode = 0;
6711hangup_out:
6713 ast_free(p->cidspill);
6714 p->cidspill = NULL;
6715
6716 if (p->reoriginate && p->sig == SIG_FXOKS && dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
6717 /* Automatic reorigination: if all calls towards a user have hung up,
6718 * give dial tone again, so user doesn't need to cycle the hook state manually. */
6719 if (my_is_off_hook(p) && !p->owner) {
6720 /* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
6721 ast_debug(1, "Queuing reorigination for channel %d\n", p->channel);
6722 my_play_tone(p, SUB_REAL, -1); /* Stop any congestion tone that may be present. */
6723 /* Must wait for the loop disconnect to end.
6724 * Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
6725 * Calling usleep on an active DAHDI channel is a no-no, but this is okay.
6726 */
6727 usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
6728 /* If the line is still off-hook and ownerless, actually queue the reorigination.
6729 * do_monitor will actually go ahead and do it. */
6730 if (!p->owner && my_is_off_hook(p)) {
6731 p->doreoriginate = 1; /* Tell do_monitor to reoriginate this channel */
6732 /* Note, my_off_hook will fail if called before the loop disconnect has finished
6733 * (important for FXOKS signaled channels). This is because DAHDI will reject
6734 * DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
6735 * so we have to wait for that to finish (see comment above).
6736 * do_monitor itself cannot block, so make the blocking usleep call
6737 * here in the channel thread instead.
6738 */
6739 my_off_hook(p); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
6740 } else {
6741 ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p->channel);
6742 }
6743 }
6744 }
6745
6747 ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
6748
6750 if (p->restartpending) {
6752 }
6753
6754 if (p->destroy) {
6755 destroy_channel(p, 0);
6756 }
6758
6760 return 0;
6761}
6762
6763static int dahdi_answer(struct ast_channel *ast)
6764{
6765 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
6766 int res = 0;
6767 int idx;
6768 ast_setstate(ast, AST_STATE_UP);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
6769 ast_mutex_lock(&p->lock);
6770 idx = dahdi_get_index(ast, p, 0);
6771 if (idx < 0)
6772 idx = SUB_REAL;
6773 /* nothing to do if a radio channel */
6774 if ((p->radio || (p->oprmode < 0))) {
6776 return 0;
6777 }
6778
6779 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
6780 res = analog_answer(p->sig_pvt, ast);
6782 return res;
6783 }
6784
6785 switch (p->sig) {
6786#if defined(HAVE_PRI)
6788 res = sig_pri_answer(p->sig_pvt, ast);
6789 break;
6790#endif /* defined(HAVE_PRI) */
6791#if defined(HAVE_SS7)
6792 case SIG_SS7:
6793 res = sig_ss7_answer(p->sig_pvt, ast);
6794 break;
6795#endif /* defined(HAVE_SS7) */
6796#ifdef HAVE_OPENR2
6797 case SIG_MFCR2:
6798 if (!p->mfcr2_call_accepted) {
6799 /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
6800 openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
6801 p->mfcr2_answer_pending = 1;
6802 if (p->mfcr2_charge_calls) {
6803 ast_debug(1, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
6804 openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
6805 } else {
6806 ast_debug(1, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
6807 openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
6808 }
6809 } else {
6810 ast_debug(1, "Answering MFC/R2 call on chan %d\n", p->channel);
6811 dahdi_r2_answer(p);
6812 }
6813 break;
6814#endif
6815 case 0:
6817 return 0;
6818 default:
6819 ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
6820 res = -1;
6821 break;
6822 }
6824 return res;
6825}
6826
6828{
6829 int val = 0;
6830
6831 p->ignoredtmf = 1;
6832
6833 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6834
6835 if (!p->hardwaredtmf && p->dsp) {
6836 p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
6838 }
6839}
6840
6842{
6843 int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
6844
6845 if (p->channel == CHAN_PSEUDO)
6846 return;
6847
6848 p->ignoredtmf = 0;
6849
6850 ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
6851
6852 if (!p->hardwaredtmf && p->dsp) {
6855 }
6856}
6857
6858static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
6859{
6860 char *cp;
6861 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
6862
6863 /* all supported options require data */
6864 if (!p || !data || (*datalen < 1)) {
6865 errno = EINVAL;
6866 return -1;
6867 }
6868
6869 switch (option) {
6870 case AST_OPTION_TDD:
6871 cp = (char *) data;
6872 if (p->mate) {
6873 *cp = 2;
6874 } else {
6875 *cp = p->tdd ? 1 : 0;
6876 }
6877 break;
6879 cp = (char *) data;
6880 *cp = p->ignoredtmf ? 0 : 1;
6881 ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6882 break;
6884 cp = (char *) data;
6885 *cp = (p->dsp_features & DSP_FEATURE_FAX_DETECT) ? 0 : 1;
6886 ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", ast_channel_name(chan));
6887 break;
6889#if defined(HAVE_PRI)
6890#if defined(HAVE_PRI_CCSS)
6892 ast_copy_string((char *) data, dahdi_pri_cc_type, *datalen);
6893 break;
6894 }
6895#endif /* defined(HAVE_PRI_CCSS) */
6896#endif /* defined(HAVE_PRI) */
6897 return -1;
6898 default:
6899 return -1;
6900 }
6901
6902 errno = 0;
6903
6904 return 0;
6905}
6906
6907static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
6908{
6909 char *cp;
6910 signed char *scp;
6911 int x;
6912 int idx;
6913 struct dahdi_pvt *p = ast_channel_tech_pvt(chan), *pp;
6914 struct oprmode *oprmode;
6915
6916
6917 /* all supported options require data */
6918 if (!p || !data || (datalen < 1)) {
6919 errno = EINVAL;
6920 return -1;
6921 }
6922
6923 switch (option) {
6924 case AST_OPTION_TXGAIN:
6925 scp = (signed char *) data;
6926 idx = dahdi_get_index(chan, p, 0);
6927 if (idx < 0) {
6928 ast_log(LOG_WARNING, "No index in TXGAIN?\n");
6929 return -1;
6930 }
6931 ast_debug(1, "Setting actual tx gain on %s to %f\n", ast_channel_name(chan), p->txgain + (float) *scp);
6932 return set_actual_txgain(p->subs[idx].dfd, p->txgain + (float) *scp, p->txdrc, p->law);
6933 case AST_OPTION_RXGAIN:
6934 scp = (signed char *) data;
6935 idx = dahdi_get_index(chan, p, 0);
6936 if (idx < 0) {
6937 ast_log(LOG_WARNING, "No index in RXGAIN?\n");
6938 return -1;
6939 }
6940 ast_debug(1, "Setting actual rx gain on %s to %f\n", ast_channel_name(chan), p->rxgain + (float) *scp);
6941 return set_actual_rxgain(p->subs[idx].dfd, p->rxgain + (float) *scp, p->rxdrc, p->law);
6943 if (!p->dsp)
6944 break;
6945 cp = (char *) data;
6946 switch (*cp) {
6947 case 1:
6948 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",ast_channel_name(chan));
6949 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
6950 break;
6951 case 2:
6952 ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",ast_channel_name(chan));
6953 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
6954 break;
6955 default:
6956 ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",ast_channel_name(chan));
6957 ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
6958 break;
6959 }
6960 break;
6961 case AST_OPTION_TDD:
6962 /* turn on or off TDD */
6963 cp = (char *) data;
6964 p->mate = 0;
6965 if (!*cp) { /* turn it off */
6966 ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",ast_channel_name(chan));
6967 if (p->tdd)
6968 tdd_free(p->tdd);
6969 p->tdd = 0;
6970 break;
6971 }
6972 ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
6973 (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
6975 /* otherwise, turn it on */
6976 if (!p->didtdd) { /* if haven't done it yet */
6977 unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
6978 unsigned char *buf;
6979 int size, res, fd, len;
6980 struct pollfd fds[1];
6981
6982 buf = mybuf;
6983 memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
6984 ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
6985 len = 40000;
6986 idx = dahdi_get_index(chan, p, 0);
6987 if (idx < 0) {
6988 ast_log(LOG_WARNING, "No index in TDD?\n");
6989 return -1;
6990 }
6991 fd = p->subs[idx].dfd;
6992 while (len) {
6993 if (ast_check_hangup(chan))
6994 return -1;
6995 size = len;
6996 if (size > READ_SIZE)
6997 size = READ_SIZE;
6998 fds[0].fd = fd;
6999 fds[0].events = POLLPRI | POLLOUT;
7000 fds[0].revents = 0;
7001 res = poll(fds, 1, -1);
7002 if (!res) {
7003 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
7004 continue;
7005 }
7006 /* if got exception */
7007 if (fds[0].revents & POLLPRI)
7008 return -1;
7009 if (!(fds[0].revents & POLLOUT)) {
7010 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
7011 continue;
7012 }
7013 res = write(fd, buf, size);
7014 if (res != size) {
7015 if (res == -1) return -1;
7016 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
7017 break;
7018 }
7019 len -= size;
7020 buf += size;
7021 }
7022 p->didtdd = 1; /* set to have done it now */
7023 }
7024 if (*cp == 2) { /* Mate mode */
7025 if (p->tdd)
7026 tdd_free(p->tdd);
7027 p->tdd = 0;
7028 p->mate = 1;
7029 break;
7030 }
7031 if (!p->tdd) { /* if we don't have one yet */
7032 p->tdd = tdd_new(); /* allocate one */
7033 }
7034 break;
7035 case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
7036 if (!p->dsp)
7037 break;
7038 cp = (char *) data;
7039 ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
7040 *cp ? "ON" : "OFF", (int) *cp, ast_channel_name(chan));
7042 break;
7043 case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
7044#if defined(HAVE_PRI)
7046 && ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
7047 /* PRI nobch pseudo channel. Does not handle ioctl(DAHDI_AUDIOMODE) */
7048 break;
7049 }
7050#endif /* defined(HAVE_PRI) */
7051
7052 cp = (char *) data;
7053 if (!*cp) {
7054 ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
7055 x = 0;
7057 } else {
7058 ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
7059 x = 1;
7060 }
7061 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
7062 ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
7063 break;
7064 case AST_OPTION_OPRMODE: /* Operator services mode */
7065 oprmode = (struct oprmode *) data;
7066 /* We don't support operator mode across technologies */
7067 if (strcasecmp(ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type)) {
7068 ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n",
7070 errno = EINVAL;
7071 return -1;
7072 }
7074 p->oprmode = pp->oprmode = 0;
7075 /* setup peers */
7076 p->oprpeer = pp;
7077 pp->oprpeer = p;
7078 /* setup modes, if any */
7079 if (oprmode->mode)
7080 {
7081 pp->oprmode = oprmode->mode;
7082 p->oprmode = -oprmode->mode;
7083 }
7084 ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
7086 break;
7087 case AST_OPTION_ECHOCAN:
7088 cp = (char *) data;
7089 if (*cp) {
7090 ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
7091 dahdi_ec_enable(p);
7092 } else {
7093 ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
7095 }
7096 break;
7098 cp = (char *) data;
7099 ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7100 if (*cp) {
7102 } else {
7104 }
7105 break;
7107 cp = (char *) data;
7108 if (p->dsp) {
7109 ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
7110 if (*cp) {
7112 } else {
7113 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7114 }
7116 }
7117 break;
7118 default:
7119 return -1;
7120 }
7121 errno = 0;
7122
7123 return 0;
7124}
7125
7126static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
7127{
7128 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7129 int res = 0;
7130
7131 if (!p) {
7132 /* No private structure! */
7133 *buf = '\0';
7134 return -1;
7135 }
7136
7137 if (!strcasecmp(data, "rxgain")) {
7138 ast_mutex_lock(&p->lock);
7139 snprintf(buf, len, "%f", p->rxgain);
7141 } else if (!strcasecmp(data, "txgain")) {
7142 ast_mutex_lock(&p->lock);
7143 snprintf(buf, len, "%f", p->txgain);
7145 } else if (!strcasecmp(data, "dahdi_channel")) {
7146 ast_mutex_lock(&p->lock);
7147 snprintf(buf, len, "%d", p->channel);
7149 } else if (!strcasecmp(data, "dahdi_span")) {
7150 ast_mutex_lock(&p->lock);
7151 snprintf(buf, len, "%d", p->span);
7153 } else if (!strcasecmp(data, "dahdi_group")) {
7154 ast_mutex_lock(&p->lock);
7155 snprintf(buf, len, "%llu", p->group);
7157 } else if (!strcasecmp(data, "dahdi_type")) {
7158 ast_mutex_lock(&p->lock);
7159 switch (p->sig) {
7160#if defined(HAVE_OPENR2)
7161 case SIG_MFCR2:
7162 ast_copy_string(buf, "mfc/r2", len);
7163 break;
7164#endif /* defined(HAVE_OPENR2) */
7165#if defined(HAVE_PRI)
7167 ast_copy_string(buf, "pri", len);
7168 break;
7169#endif /* defined(HAVE_PRI) */
7170 case 0:
7171 ast_copy_string(buf, "pseudo", len);
7172 break;
7173#if defined(HAVE_SS7)
7174 case SIG_SS7:
7175 ast_copy_string(buf, "ss7", len);
7176 break;
7177#endif /* defined(HAVE_SS7) */
7178 default:
7179 /* The only thing left is analog ports. */
7180 ast_copy_string(buf, "analog", len);
7181 break;
7182 }
7184#if defined(HAVE_PRI)
7185#if defined(HAVE_PRI_REVERSE_CHARGE)
7186 } else if (!strcasecmp(data, "reversecharge")) {
7187 ast_mutex_lock(&p->lock);
7188 switch (p->sig) {
7190 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->reverse_charging_indication);
7191 break;
7192 default:
7193 *buf = '\0';
7194 res = -1;
7195 break;
7196 }
7198#endif
7199#if defined(HAVE_PRI_SETUP_KEYPAD)
7200 } else if (!strcasecmp(data, "keypad_digits")) {
7201 ast_mutex_lock(&p->lock);
7202 switch (p->sig) {
7204 ast_copy_string(buf, ((struct sig_pri_chan *) p->sig_pvt)->keypad_digits,
7205 len);
7206 break;
7207 default:
7208 *buf = '\0';
7209 res = -1;
7210 break;
7211 }
7213#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
7214 } else if (!strcasecmp(data, "no_media_path")) {
7215 ast_mutex_lock(&p->lock);
7216 switch (p->sig) {
7218 /*
7219 * TRUE if the call is on hold or is call waiting because
7220 * there is no media path available.
7221 */
7222 snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel);
7223 break;
7224 default:
7225 *buf = '\0';
7226 res = -1;
7227 break;
7228 }
7230#endif /* defined(HAVE_PRI) */
7231 } else if (!strcasecmp(data, "dialmode")) {
7232 struct analog_pvt *analog_p;
7233 ast_mutex_lock(&p->lock);
7234 analog_p = p->sig_pvt;
7235 /* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
7236 if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
7237 switch (analog_p->dialmode) {
7239 ast_copy_string(buf, "both", len);
7240 break;
7242 ast_copy_string(buf, "pulse", len);
7243 break;
7245 ast_copy_string(buf, "dtmf", len);
7246 break;
7248 ast_copy_string(buf, "none", len);
7249 break;
7250 }
7251 } else {
7252 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7253 *buf = '\0';
7254 res = -1;
7255 }
7257 } else {
7258 *buf = '\0';
7259 res = -1;
7260 }
7261
7262 return res;
7263}
7264
7265
7266static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
7267{
7268 int res;
7269 char policy_str[21] = "";
7270
7271 if ((res = sscanf(parse, "%30d,%20s", num_buffers, policy_str)) != 2) {
7272 ast_log(LOG_WARNING, "Parsing buffer string '%s' failed.\n", parse);
7273 return 1;
7274 }
7275 if (*num_buffers < 0) {
7276 ast_log(LOG_WARNING, "Invalid buffer count given '%d'.\n", *num_buffers);
7277 return -1;
7278 }
7279 if (!strcasecmp(policy_str, "full")) {
7280 *policy = DAHDI_POLICY_WHEN_FULL;
7281 } else if (!strcasecmp(policy_str, "immediate")) {
7282 *policy = DAHDI_POLICY_IMMEDIATE;
7283#if defined(HAVE_DAHDI_HALF_FULL)
7284 } else if (!strcasecmp(policy_str, "half")) {
7285 *policy = DAHDI_POLICY_HALF_FULL;
7286#endif
7287 } else {
7288 ast_log(LOG_WARNING, "Invalid policy name given '%s'.\n", policy_str);
7289 return -1;
7290 }
7291
7292 return 0;
7293}
7294
7295static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
7296{
7297 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
7298 int res = 0;
7299
7300 if (!p) {
7301 /* No private structure! */
7302 return -1;
7303 }
7304
7305 if (!strcasecmp(data, "buffers")) {
7306 int num_bufs, policy;
7307
7308 if (!(parse_buffers_policy(value, &num_bufs, &policy))) {
7309 struct dahdi_bufferinfo bi = {
7310 .txbufpolicy = policy,
7311 .rxbufpolicy = policy,
7312 .bufsize = p->bufsize,
7313 .numbufs = num_bufs,
7314 };
7315 int bpres;
7316
7317 if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7318 ast_log(LOG_WARNING, "Channel '%d' unable to override buffer policy: %s\n", p->channel, strerror(errno));
7319 } else {
7320 p->bufferoverrideinuse = 1;
7321 }
7322 } else {
7323 res = -1;
7324 }
7325 } else if (!strcasecmp(data, "echocan_mode")) {
7326 if (!strcasecmp(value, "on")) {
7327 ast_mutex_lock(&p->lock);
7328 dahdi_ec_enable(p);
7330 } else if (!strcasecmp(value, "off")) {
7331 ast_mutex_lock(&p->lock);
7334#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7335 } else if (!strcasecmp(value, "fax")) {
7336 int blah = 1;
7337
7338 ast_mutex_lock(&p->lock);
7339 if (!p->echocanon) {
7340 dahdi_ec_enable(p);
7341 }
7342 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7343 ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
7344 }
7346 } else if (!strcasecmp(value, "voice")) {
7347 int blah = 0;
7348
7349 ast_mutex_lock(&p->lock);
7350 if (!p->echocanon) {
7351 dahdi_ec_enable(p);
7352 }
7353 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
7354 ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
7355 }
7357#endif
7358 } else {
7359 ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
7360 res = -1;
7361 }
7362 } else if (!strcasecmp(data, "dialmode")) {
7363 struct analog_pvt *analog_p;
7364
7365 ast_mutex_lock(&p->lock);
7366 analog_p = p->sig_pvt;
7367 if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
7368 ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
7370 return -1;
7371 }
7372 /* analog pvt is used for pulse dialing, so update both */
7373 if (!strcasecmp(value, "pulse")) {
7374 analog_p->dialmode = ANALOG_DIALMODE_PULSE;
7375 } else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
7376 analog_p->dialmode = ANALOG_DIALMODE_DTMF;
7377 } else if (!strcasecmp(value, "none")) {
7378 analog_p->dialmode = ANALOG_DIALMODE_NONE;
7379 } else if (!strcasecmp(value, "both")) {
7380 analog_p->dialmode = ANALOG_DIALMODE_BOTH;
7381 } else {
7382 ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
7383 res = -1;
7384 }
7386 } else if (!strcasecmp(data, "waitfordialtone")) {
7387 if (ast_strlen_zero(value)) {
7388 ast_log(LOG_WARNING, "waitfordialtone requires a duration in ms\n");
7389 return -1;
7390 }
7391
7392 ast_mutex_lock(&p->lock);
7393 if (!CANPROGRESSDETECT(p)) {
7394 ast_log(LOG_WARNING, "%s only supported on analog trunks\n", data);
7396 return -1;
7397 }
7398 /* Only set the temp waitfordialtone setting, not the permanent one. */
7399 p->waitfordialtonetemp = atoi(value);
7401 } else {
7402 res = -1;
7403 }
7404
7405 return res;
7406}
7407
7408void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
7409{
7410 /* Unlink a specific slave or all slaves/masters from a given master */
7411 int x;
7412 int hasslaves;
7413 if (!master)
7414 return;
7415 if (needlock) {
7416 ast_mutex_lock(&master->lock);
7417 if (slave) {
7418 while (ast_mutex_trylock(&slave->lock)) {
7419 DEADLOCK_AVOIDANCE(&master->lock);
7420 }
7421 }
7422 }
7423 hasslaves = 0;
7424 for (x = 0; x < MAX_SLAVES; x++) {
7425 if (master->slaves[x]) {
7426 if (!slave || (master->slaves[x] == slave)) {
7427 /* Take slave out of the conference */
7428 ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
7429 conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
7430 conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
7431 master->slaves[x]->master = NULL;
7432 master->slaves[x] = NULL;
7433 } else
7434 hasslaves = 1;
7435 }
7436 if (!hasslaves)
7437 master->inconference = 0;
7438 }
7439 if (!slave) {
7440 if (master->master) {
7441 /* Take master out of the conference */
7442 conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
7443 conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
7444 hasslaves = 0;
7445 for (x = 0; x < MAX_SLAVES; x++) {
7446 if (master->master->slaves[x] == master)
7447 master->master->slaves[x] = NULL;
7448 else if (master->master->slaves[x])
7449 hasslaves = 1;
7450 }
7451 if (!hasslaves)
7452 master->master->inconference = 0;
7453 }
7454 master->master = NULL;
7455 }
7456 dahdi_conf_update(master);
7457 if (needlock) {
7458 if (slave)
7459 ast_mutex_unlock(&slave->lock);
7460 ast_mutex_unlock(&master->lock);
7461 }
7462}
7463
7464void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
7465{
7466 int x;
7467 if (!slave || !master) {
7468 ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
7469 return;
7470 }
7471 for (x = 0; x < MAX_SLAVES; x++) {
7472 if (!master->slaves[x]) {
7473 master->slaves[x] = slave;
7474 break;
7475 }
7476 }
7477 if (x >= MAX_SLAVES) {
7478 ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
7479 master->slaves[MAX_SLAVES - 1] = slave;
7480 }
7481 if (slave->master)
7482 ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
7483 slave->master = master;
7484
7485 ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
7486}
7487
7488static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
7489{
7490 struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
7491 int x;
7492
7493 ast_mutex_lock(&p->lock);
7494
7495 ast_debug(1, "New owner for channel %d is %s\n", p->channel, ast_channel_name(newchan));
7496 if (p->owner == oldchan) {
7497 p->owner = newchan;
7498 }
7499 for (x = 0; x < 3; x++) {
7500 if (p->subs[x].owner == oldchan) {
7501 if (!x) {
7503 }
7504 p->subs[x].owner = newchan;
7505 }
7506 }
7507 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
7508 analog_fixup(oldchan, newchan, p->sig_pvt);
7509#if defined(HAVE_PRI)
7510 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
7511 sig_pri_fixup(oldchan, newchan, p->sig_pvt);
7512#endif /* defined(HAVE_PRI) */
7513#if defined(HAVE_SS7)
7514 } else if (p->sig == SIG_SS7) {
7515 sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
7516#endif /* defined(HAVE_SS7) */
7517 }
7519
7521
7522 if (ast_channel_state(newchan) == AST_STATE_RINGING) {
7524 }
7525 return 0;
7526}
7527
7528static int dahdi_ring_phone(struct dahdi_pvt *p)
7529{
7530 int x;
7531 int res;
7532 /* Make sure our transmit state is on hook */
7533 x = 0;
7534 x = DAHDI_ONHOOK;
7535 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7536 do {
7537 x = DAHDI_RING;
7538 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
7539 if (res) {
7540 switch (errno) {
7541 case EBUSY:
7542 case EINTR:
7543 /* Wait just in case */
7544 usleep(10000);
7545 continue;
7546 case EINPROGRESS:
7547 res = 0;
7548 break;
7549 default:
7550 ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
7551 res = 0;
7552 }
7553 }
7554 } while (res);
7555 return res;
7556}
7557
7558static void *analog_ss_thread(void *data);
7559
7560/*!
7561 * \internal
7562 * \brief Attempt to transfer 3-way call.
7563 *
7564 * \param p DAHDI private structure.
7565 *
7566 * \note On entry these locks are held: real-call, private, 3-way call.
7567 * \note On exit these locks are held: real-call, private.
7568 *
7569 * \retval 0 on success.
7570 * \retval -1 on error.
7571 */
7572static int attempt_transfer(struct dahdi_pvt *p)
7573{
7574 struct ast_channel *owner_real;
7575 struct ast_channel *owner_3way;
7576 enum ast_transfer_result xfer_res;
7577 int res = 0;
7578
7579 owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
7580 owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
7581
7582 ast_verb(3, "TRANSFERRING %s to %s\n",
7583 ast_channel_name(owner_3way), ast_channel_name(owner_real));
7584
7585 ast_channel_unlock(owner_real);
7586 ast_channel_unlock(owner_3way);
7588
7589 xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
7590 if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
7592 res = -1;
7593 }
7594
7595 /* Must leave with these locked. */
7596 ast_channel_lock(owner_real);
7597 ast_mutex_lock(&p->lock);
7598
7599 ast_channel_unref(owner_real);
7600 ast_channel_unref(owner_3way);
7601
7602 return res;
7603}
7604
7605static int check_for_conference(struct dahdi_pvt *p)
7606{
7607 struct dahdi_confinfo ci;
7608 /* Fine if we already have a master, etc */
7609 if (p->master || (p->confno > -1))
7610 return 0;
7611 memset(&ci, 0, sizeof(ci));
7612 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
7613 ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
7614 return 0;
7615 }
7616 /* If we have no master and don't have a confno, then
7617 if we're in a conference, it's probably a MeetMe room or
7618 some such, so don't let us 3-way out! */
7619 if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
7620 ast_verb(3, "Avoiding 3-way call when in an external conference\n");
7621 return 1;
7622 }
7623 return 0;
7624}
7625
7626/*! Checks channel for alarms
7627 * \param p a channel to check for alarms.
7628 * \returns the alarms on the span to which the channel belongs, or alarms on
7629 * the channel if no span alarms.
7630 */
7631static int get_alarms(struct dahdi_pvt *p)
7632{
7633 int res;
7634 struct dahdi_spaninfo zi;
7635 struct dahdi_params params;
7636
7637 memset(&zi, 0, sizeof(zi));
7638 zi.spanno = p->span;
7639
7640 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
7641 if (zi.alarms != DAHDI_ALARM_NONE)
7642 return zi.alarms;
7643 } else {
7644 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
7645 return 0;
7646 }
7647
7648 /* No alarms on the span. Check for channel alarms. */
7649 memset(&params, 0, sizeof(params));
7650 if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
7651 return params.chan_alarms;
7652
7653 ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
7654
7655 return DAHDI_ALARM_NONE;
7656}
7657
7658static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
7659{
7660 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7661 struct ast_frame *f = *dest;
7662
7663 ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
7664 f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
7665 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
7666
7667 if (p->confirmanswer) {
7668 if (f->frametype == AST_FRAME_DTMF_END) {
7669 ast_debug(1, "Confirm answer on %s!\n", ast_channel_name(ast));
7670 /* Upon receiving a DTMF digit, consider this an answer confirmation instead
7671 of a DTMF digit */
7674 /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
7675 p->confirmanswer = 0;
7676 } else {
7677 p->subs[idx].f.frametype = AST_FRAME_NULL;
7678 p->subs[idx].f.subclass.integer = 0;
7679 }
7680 *dest = &p->subs[idx].f;
7681 } else if (p->callwaitcas) {
7682 if (f->frametype == AST_FRAME_DTMF_END) {
7683 if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
7684 ast_debug(1, "Got some DTMF, but it's for the CAS\n");
7685 ast_free(p->cidspill);
7686 p->cidspill = NULL;
7687 send_cwcidspill(p);
7688 }
7689 p->callwaitcas = 0;
7690 }
7691 p->subs[idx].f.frametype = AST_FRAME_NULL;
7692 p->subs[idx].f.subclass.integer = 0;
7693 *dest = &p->subs[idx].f;
7694 } else if (f->subclass.integer == 'f') {
7695 if (f->frametype == AST_FRAME_DTMF_END) {
7696 /* Fax tone -- Handle and return NULL */
7697 if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
7698 /* If faxbuffers are configured, use them for the fax transmission */
7699 if (p->usefaxbuffers && !p->bufferoverrideinuse) {
7700 struct dahdi_bufferinfo bi = {
7701 .txbufpolicy = p->faxbuf_policy,
7702 .bufsize = p->bufsize,
7703 .numbufs = p->faxbuf_no
7704 };
7705 int res;
7706
7707 if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
7708 ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast_channel_name(ast), strerror(errno));
7709 } else {
7710 p->bufferoverrideinuse = 1;
7711 }
7712 }
7713 p->faxhandled = 1;
7714 if (p->dsp) {
7715 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
7717 ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
7718 }
7719 if (strcmp(ast_channel_exten(ast), "fax")) {
7720 const char *target_context = ast_channel_context(ast);
7721
7722 /*
7723 * We need to unlock 'ast' here because ast_exists_extension has the
7724 * potential to start autoservice on the channel. Such action is prone
7725 * to deadlock if the channel is locked.
7726 *
7727 * ast_async_goto() has its own restriction on not holding the
7728 * channel lock.
7729 */
7731 ast_channel_unlock(ast);
7732 if (ast_exists_extension(ast, target_context, "fax", 1,
7733 S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
7734 ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
7735 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
7736 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
7737 if (ast_async_goto(ast, target_context, "fax", 1))
7738 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
7739 } else {
7740 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
7741 }
7742 ast_channel_lock(ast);
7743 ast_mutex_lock(&p->lock);
7744 } else {
7745 ast_debug(1, "Already in a fax extension, not redirecting\n");
7746 }
7747 } else {
7748 ast_debug(1, "Fax already handled\n");
7749 }
7750 dahdi_confmute(p, 0);
7751 }
7752 p->subs[idx].f.frametype = AST_FRAME_NULL;
7753 p->subs[idx].f.subclass.integer = 0;
7754 *dest = &p->subs[idx].f;
7755 }
7756}
7757
7758static void publish_span_alarm(int span, const char *alarm_txt)
7759{
7760 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7761
7762 body = ast_json_pack("{s: i, s: s}",
7763 "Span", span,
7764 "Alarm", alarm_txt);
7765 if (!body) {
7766 return;
7767 }
7768
7769 ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
7770}
7771
7772static void publish_channel_alarm(int channel, const char *alarm_txt)
7773{
7774 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
7775 RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
7776 if (!dahdi_chan) {
7777 return;
7778 }
7779
7780 ast_str_set(&dahdi_chan, 0, "%d", channel);
7781 body = ast_json_pack("{s: s, s: s}",
7782 "DAHDIChannel", ast_str_buffer(dahdi_chan),
7783 "Alarm", alarm_txt);
7784 if (!body) {
7785 return;
7786 }
7787
7789}
7790
7791static void handle_alarms(struct dahdi_pvt *p, int alms)
7792{
7793 const char *alarm_str;
7794
7795#if defined(HAVE_PRI)
7797 return;
7798 }
7799#endif /* defined(HAVE_PRI) */
7800
7801 alarm_str = alarm2str(alms);
7803 ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
7804 publish_channel_alarm(p->channel, alarm_str);
7805 }
7806
7808 ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
7809 publish_span_alarm(p->span, alarm_str);
7810 }
7811}
7812
7813static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
7814{
7815 int res, x;
7816 int idx, mysig;
7817 char *c;
7818 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
7819 pthread_t threadid;
7820 struct ast_channel *chan;
7821 struct ast_frame *f;
7822
7823 idx = dahdi_get_index(ast, p, 0);
7824 if (idx < 0) {
7825 return &ast_null_frame;
7826 }
7827 mysig = p->sig;
7828 if (p->outsigmod > -1)
7829 mysig = p->outsigmod;
7830 p->subs[idx].f.frametype = AST_FRAME_NULL;
7831 p->subs[idx].f.subclass.integer = 0;
7832 p->subs[idx].f.datalen = 0;
7833 p->subs[idx].f.samples = 0;
7834 p->subs[idx].f.mallocd = 0;
7835 p->subs[idx].f.offset = 0;
7836 p->subs[idx].f.src = "dahdi_handle_event";
7837 p->subs[idx].f.data.ptr = NULL;
7838 f = &p->subs[idx].f;
7839
7840 if (p->fake_event) {
7841 res = p->fake_event;
7842 p->fake_event = 0;
7843 } else
7844 res = dahdi_get_event(p->subs[idx].dfd);
7845
7846 ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
7847
7848 if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
7849 p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
7850 ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
7851#if defined(HAVE_PRI)
7853 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7854 && p->pri
7855 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7856 /* absorb event */
7857 } else
7858#endif /* defined(HAVE_PRI) */
7859 {
7860 /* Unmute conference */
7861 dahdi_confmute(p, 0);
7863 p->subs[idx].f.subclass.integer = res & 0xff;
7864 dahdi_handle_dtmf(ast, idx, &f);
7865 }
7866 return f;
7867 }
7868
7869 if (res & DAHDI_EVENT_DTMFDOWN) {
7870 ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
7871#if defined(HAVE_PRI)
7873 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
7874 && p->pri
7875 && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
7876 /* absorb event */
7877 } else
7878#endif /* defined(HAVE_PRI) */
7879 {
7880 /* Mute conference */
7881 dahdi_confmute(p, 1);
7883 p->subs[idx].f.subclass.integer = res & 0xff;
7884 dahdi_handle_dtmf(ast, idx, &f);
7885 }
7886 return &p->subs[idx].f;
7887 }
7888
7889 switch (res) {
7890 case DAHDI_EVENT_EC_DISABLED:
7891 ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
7892 p->echocanon = 0;
7893 break;
7894#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
7895 case DAHDI_EVENT_TX_CED_DETECTED:
7896 ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
7897 break;
7898 case DAHDI_EVENT_RX_CED_DETECTED:
7899 ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
7900 break;
7901 case DAHDI_EVENT_EC_NLP_DISABLED:
7902 ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
7903 break;
7904 case DAHDI_EVENT_EC_NLP_ENABLED:
7905 ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
7906 break;
7907#endif
7908 case DAHDI_EVENT_BITSCHANGED:
7909#ifdef HAVE_OPENR2
7910 if (p->sig != SIG_MFCR2) {
7911 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7912 } else {
7913 ast_debug(1, "bits changed in chan %d\n", p->channel);
7914 openr2_chan_handle_cas(p->r2chan);
7915 }
7916#else
7917 ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
7918#endif
7919 break;
7920 case DAHDI_EVENT_PULSE_START:
7921 /* Stop tone if there's a pulse start and the PBX isn't started */
7922 if (!ast_channel_pbx(ast))
7923 tone_zone_play_tone(p->subs[idx].dfd, -1);
7924 break;
7925 case DAHDI_EVENT_DIALCOMPLETE:
7926 /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
7927#if defined(HAVE_PRI)
7929 if (p->inalarm) {
7930 break;
7931 }
7932 if (ioctl(p->subs[idx].dfd, DAHDI_DIALING, &x) == -1) {
7933 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
7934 ast_channel_name(ast), strerror(errno));
7935 return NULL;
7936 }
7937 if (x) {
7938 /* Still dialing in DAHDI driver */
7939 break;
7940 }
7941 /*
7942 * The ast channel is locked and the private may be locked more
7943 * than once.
7944 */
7946 break;
7947 }
7948#endif /* defined(HAVE_PRI) */
7949#ifdef HAVE_OPENR2
7950 if ((p->sig & SIG_MFCR2) && p->r2chan && ast_channel_state(ast) != AST_STATE_UP) {
7951 /* we don't need to do anything for this event for R2 signaling
7952 if the call is being setup */
7953 break;
7954 }
7955#endif
7956 if (p->inalarm) break;
7957 if ((p->radio || (p->oprmode < 0))) break;
7958 if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
7959 ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",ast_channel_name(ast), strerror(errno));
7960 return NULL;
7961 }
7962 if (!x) { /* if not still dialing in driver */
7963 dahdi_ec_enable(p);
7964 if (p->echobreak) {
7965 dahdi_train_ec(p);
7966 ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
7967 p->dop.op = DAHDI_DIAL_OP_REPLACE;
7968 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
7969 p->echobreak = 0;
7970 } else {
7971 p->dialing = 0;
7972 if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
7973 /* if thru with dialing after offhook */
7978 break;
7979 } else { /* if to state wait for offhook to dial rest */
7980 /* we now wait for off hook */
7982 }
7983 }
7985 if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
7986 ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
7987 } else if (p->confirmanswer || (!p->dialednone
7988 && ((mysig == SIG_EM) || (mysig == SIG_EM_E1)
7989 || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD)
7990 || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF)
7991 || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA)
7992 || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB)
7993 || (mysig == SIG_SF) || (mysig == SIG_SFWINK)
7994 || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF)
7995 || (mysig == SIG_SF_FEATB)))) {
7997 } else if (!p->answeronpolarityswitch) {
8001 /* If aops=0 and hops=1, this is necessary */
8003 } else {
8004 /* Start clean, so we can catch the change to REV polarity when party answers */
8006 }
8007 }
8008 }
8009 }
8010 break;
8011 case DAHDI_EVENT_ALARM:
8012 switch (p->sig) {
8013#if defined(HAVE_PRI)
8016 break;
8017#endif /* defined(HAVE_PRI) */
8018#if defined(HAVE_SS7)
8019 case SIG_SS7:
8021 break;
8022#endif /* defined(HAVE_SS7) */
8023 default:
8024 p->inalarm = 1;
8025 break;
8026 }
8027 res = get_alarms(p);
8028 handle_alarms(p, res);
8029#ifdef HAVE_PRI
8030 if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
8031 /* fall through intentionally */
8032 } else {
8033 break;
8034 }
8035#endif
8036#if defined(HAVE_SS7)
8037 if (p->sig == SIG_SS7)
8038 break;
8039#endif /* defined(HAVE_SS7) */
8040#ifdef HAVE_OPENR2
8041 if (p->sig == SIG_MFCR2)
8042 break;
8043#endif
8044 case DAHDI_EVENT_ONHOOK:
8045 if (p->radio) {
8048 break;
8049 }
8050 if (p->oprmode < 0)
8051 {
8052 if (p->oprmode != -1) { /* Operator flash recall */
8053 ast_verb(4, "Operator mode enabled on channel %d, holding line for channel %d\n", p->channel, p->oprpeer->channel);
8054 break;
8055 }
8056 /* Otherwise, immediate recall */
8057 if (IS_FXO_SIG(p)) {
8058 /* Make sure it starts ringing */
8059 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8060 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
8062 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8063 ast_verb(4, "Operator recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8064 }
8065 break;
8066 }
8067 switch (p->sig) {
8068 case SIG_FXOLS:
8069 case SIG_FXOGS:
8070 case SIG_FXOKS:
8071 /* Check for some special conditions regarding call waiting */
8072 if (idx == SUB_REAL) {
8073 /* The normal line was hung up */
8074 if (p->subs[SUB_CALLWAIT].owner) {
8075 /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
8077 ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
8079#if 0
8080 p->subs[idx].needanswer = 0;
8081 p->subs[idx].needringing = 0;
8082#endif
8083 p->callwaitingrepeat = 0;
8084 p->cidcwexpire = 0;
8085 p->cid_suppress_expire = 0;
8086 p->owner = NULL;
8087 /* Don't start streaming audio yet if the incoming call isn't up yet */
8089 p->dialing = 1;
8091 } else if (p->subs[SUB_THREEWAY].owner) {
8092 unsigned int mssinceflash;
8093 /* Here we have to retain the lock on both the main channel, the 3-way channel, and
8094 the private structure -- not especially easy or clean */
8096 /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
8097 DLA_UNLOCK(&p->lock);
8099 /* We can grab ast and p in that order, without worry. We should make sure
8100 nothing seriously bad has happened though like some sort of bizarre double
8101 masquerade! */
8102 DLA_LOCK(&p->lock);
8103 if (p->owner != ast) {
8104 ast_log(LOG_WARNING, "This isn't good...\n");
8105 return NULL;
8106 }
8107 }
8108 if (!p->subs[SUB_THREEWAY].owner) {
8109 ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
8110 return NULL;
8111 }
8112 mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
8113 ast_debug(1, "Last flash was %u ms ago\n", mssinceflash);
8114 if (mssinceflash < MIN_MS_SINCE_FLASH) {
8115 /* It hasn't been long enough since the last flashook. This is probably a bounce on
8116 hanging up. Hangup both channels now */
8117 if (p->subs[SUB_THREEWAY].owner)
8120 ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
8122 } else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
8123 if (p->transfer) {
8124 /* In any case this isn't a threeway call anymore */
8125 p->subs[SUB_REAL].inthreeway = 0;
8127 /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
8128 if (!p->transfertobusy && ast_channel_state(ast) == AST_STATE_BUSY) {
8130 /* Swap subs and dis-own channel */
8132 p->owner = NULL;
8133 /* Ring the phone */
8135 } else if (!attempt_transfer(p)) {
8136 /*
8137 * Transfer successful. Don't actually hang up at this point.
8138 * Let our channel legs of the calls die off as the transfer
8139 * percolates through the core.
8140 */
8141 break;
8142 }
8143 } else {
8145 if (p->subs[SUB_THREEWAY].owner)
8147 }
8148 } else {
8150 /* Swap subs and dis-own channel */
8152 p->owner = NULL;
8153 /* Ring the phone */
8155 }
8156 }
8157 } else {
8158 ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
8159 }
8160 /* Fall through */
8161 default:
8163 return NULL;
8164 }
8165 break;
8166 case DAHDI_EVENT_RINGOFFHOOK:
8167 if (p->inalarm) break;
8168 if (p->oprmode < 0)
8169 {
8170 if (IS_FXO_SIG(p)) {
8171 /* Make sure it stops ringing */
8172 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8173 tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
8175 ast_debug(1, "Operator recall by channel %d for channel %d complete\n", p->oprpeer->channel, p->channel);
8176 }
8177 break;
8178 }
8179 if (p->radio)
8180 {
8183 break;
8184 }
8185 /* for E911, its supposed to wait for offhook then dial
8186 the second half of the dial string */
8187 if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK)) {
8188 c = strchr(p->dialdest, '/');
8189 if (c)
8190 c++;
8191 else
8192 c = p->dialdest;
8193
8194 if (*c) {
8195 int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
8196 if (numchars >= sizeof(p->dop.dialstr)) {
8197 ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
8198 }
8199 } else {
8200 ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
8201 }
8202
8203 if (strlen(p->dop.dialstr) > 4) {
8204 memset(p->echorest, 'w', sizeof(p->echorest) - 1);
8205 strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
8206 p->echorest[sizeof(p->echorest) - 1] = '\0';
8207 p->echobreak = 1;
8208 p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
8209 } else
8210 p->echobreak = 0;
8211 if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
8212 x = DAHDI_ONHOOK;
8213 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
8214 return NULL;
8215 }
8216 p->dialing = 1;
8217 return &p->subs[idx].f;
8218 }
8219 switch (p->sig) {
8220 case SIG_FXOLS:
8221 case SIG_FXOGS:
8222 case SIG_FXOKS:
8223 switch (ast_channel_state(ast)) {
8224 case AST_STATE_RINGING:
8225 dahdi_ec_enable(p);
8226 dahdi_train_ec(p);
8229 /* Make sure it stops ringing */
8230 p->subs[SUB_REAL].needringing = 0;
8231 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8232 ast_debug(1, "channel %d answered\n", p->channel);
8233
8234 /* Cancel any running CallerID spill */
8235 ast_free(p->cidspill);
8236 p->cidspill = NULL;
8238
8239 p->dialing = 0;
8240 p->callwaitcas = 0;
8241 if (p->confirmanswer) {
8242 /* Ignore answer if "confirm answer" is enabled */
8243 p->subs[idx].f.frametype = AST_FRAME_NULL;
8244 p->subs[idx].f.subclass.integer = 0;
8245 } else if (!ast_strlen_zero(p->dop.dialstr)) {
8246 /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
8247 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8248 if (res) {
8249 p->dop.dialstr[0] = '\0';
8250 return NULL;
8251 } else {
8252 ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
8253 p->subs[idx].f.frametype = AST_FRAME_NULL;
8254 p->subs[idx].f.subclass.integer = 0;
8255 p->dialing = 1;
8256 }
8257 p->dop.dialstr[0] = '\0';
8259 } else
8261 return &p->subs[idx].f;
8262 case AST_STATE_DOWN:
8264 ast_channel_rings_set(ast, 1);
8267 ast_debug(1, "channel %d picked up\n", p->channel);
8268 return &p->subs[idx].f;
8269 case AST_STATE_UP:
8270 /* Make sure it stops ringing */
8271 dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
8272 /* Okay -- probably call waiting*/
8274 p->subs[idx].needunhold = 1;
8275 break;
8276 case AST_STATE_RESERVED:
8277 /* Start up dialtone */
8278 if (has_voicemail(p))
8279 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
8280 else
8281 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
8282 break;
8283 default:
8284 ast_log(LOG_WARNING, "FXO phone off hook in weird state %u??\n", ast_channel_state(ast));
8285 }
8286 break;
8287 case SIG_FXSLS:
8288 case SIG_FXSGS:
8289 case SIG_FXSKS:
8290 if (ast_channel_state(ast) == AST_STATE_RING) {
8291 p->ringt = p->ringt_base;
8292 }
8293
8294 /* If we get a ring then we cannot be in
8295 * reversed polarity. So we reset to idle */
8296 ast_debug(1, "Setting IDLE polarity due "
8297 "to ring. Old polarity was %d\n",
8298 p->polarity);
8300
8301 /* Fall through */
8302 case SIG_EM:
8303 case SIG_EM_E1:
8304 case SIG_EMWINK:
8305 case SIG_FEATD:
8306 case SIG_FEATDMF:
8307 case SIG_FEATDMF_TA:
8308 case SIG_E911:
8309 case SIG_FGC_CAMA:
8310 case SIG_FGC_CAMAMF:
8311 case SIG_FEATB:
8312 case SIG_SF:
8313 case SIG_SFWINK:
8314 case SIG_SF_FEATD:
8315 case SIG_SF_FEATDMF:
8316 case SIG_SF_FEATB:
8320 ast_debug(1, "Ring detected\n");
8323 } else if (p->outgoing && ((ast_channel_state(ast) == AST_STATE_RINGING) || (ast_channel_state(ast) == AST_STATE_DIALING))) {
8324 ast_debug(1, "Line answered\n");
8325 if (p->confirmanswer) {
8326 p->subs[idx].f.frametype = AST_FRAME_NULL;
8327 p->subs[idx].f.subclass.integer = 0;
8328 } else {
8332 }
8333 } else if (ast_channel_state(ast) != AST_STATE_RING)
8334 ast_log(LOG_WARNING, "Ring/Off-hook in strange state %u on channel %d\n", ast_channel_state(ast), p->channel);
8335 break;
8336 default:
8337 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8338 }
8339 break;
8340 case DAHDI_EVENT_RINGBEGIN:
8341 switch (p->sig) {
8342 case SIG_FXSLS:
8343 case SIG_FXSGS:
8344 case SIG_FXSKS:
8345 if (ast_channel_state(ast) == AST_STATE_RING) {
8346 p->ringt = p->ringt_base;
8347 }
8348 break;
8349 }
8350 break;
8351 case DAHDI_EVENT_RINGERON:
8352 break;
8353 case DAHDI_EVENT_NOALARM:
8354 switch (p->sig) {
8355#if defined(HAVE_PRI)
8358 break;
8359#endif /* defined(HAVE_PRI) */
8360#if defined(HAVE_SS7)
8361 case SIG_SS7:
8363 break;
8364#endif /* defined(HAVE_SS7) */
8365 default:
8366 p->inalarm = 0;
8367 break;
8368 }
8370 break;
8371 case DAHDI_EVENT_WINKFLASH:
8372 if (p->inalarm) break;
8373 if (p->radio) break;
8374 if (p->oprmode < 0) break;
8375 if (p->oprmode > 1)
8376 {
8377 struct dahdi_params par;
8378
8379 memset(&par, 0, sizeof(par));
8380 if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
8381 {
8382 if (!par.rxisoffhook)
8383 {
8384 /* Make sure it stops ringing */
8385 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
8386 dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
8387 save_conference(p);
8388 tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
8389 ast_verb(4, "Operator flash recall, channel %d ringing back channel %d\n", p->oprpeer->channel, p->channel);
8390 }
8391 }
8392 break;
8393 }
8394 /* Remember last time we got a flash-hook */
8395 p->flashtime = ast_tvnow();
8396 switch (mysig) {
8397 case SIG_FXOLS:
8398 case SIG_FXOGS:
8399 case SIG_FXOKS:
8400 ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
8402
8403 /* Cancel any running CallerID spill */
8404 ast_free(p->cidspill);
8405 p->cidspill = NULL;
8407 p->callwaitcas = 0;
8408
8409 if (idx != SUB_REAL) {
8410 ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
8411 goto winkflashdone;
8412 }
8413
8414 if (p->subs[SUB_CALLWAIT].owner) {
8415 /* Swap to call-wait */
8417 tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
8418 p->owner = p->subs[SUB_REAL].owner;
8419 ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
8422 p->subs[SUB_REAL].needanswer = 1;
8423 }
8424 p->callwaitingrepeat = 0;
8425 p->cidcwexpire = 0;
8426 p->cid_suppress_expire = 0;
8427 /* Start music on hold if appropriate */
8428 if (!p->subs[SUB_CALLWAIT].inthreeway) {
8430 }
8431 p->subs[SUB_CALLWAIT].needhold = 1;
8433 p->subs[SUB_REAL].needunhold = 1;
8434 } else if (!p->subs[SUB_THREEWAY].owner) {
8435 if (!p->threewaycalling) {
8436 /* Just send a flash if no 3-way calling */
8437 p->subs[SUB_REAL].needflash = 1;
8438 goto winkflashdone;
8439 } else if (!check_for_conference(p)) {
8440 ast_callid callid = 0;
8441 int callid_created;
8442 char cid_num[256];
8443 char cid_name[256];
8444
8445 cid_num[0] = 0;
8446 cid_name[0] = 0;
8447 if (p->dahditrcallerid && p->owner) {
8451 sizeof(cid_num));
8452 }
8456 sizeof(cid_name));
8457 }
8458 }
8459 /* XXX This section needs much more error checking!!! XXX */
8460 /* Start a 3-way call if feasible */
8461 if (!((ast_channel_pbx(ast)) ||
8462 (ast_channel_state(ast) == AST_STATE_UP) ||
8463 (ast_channel_state(ast) == AST_STATE_RING))) {
8464 ast_debug(1, "Flash when call not up or ringing\n");
8465 goto winkflashdone;
8466 }
8467 if (alloc_sub(p, SUB_THREEWAY)) {
8468 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
8469 goto winkflashdone;
8470 }
8471 callid_created = ast_callid_threadstorage_auto(&callid);
8472 /*
8473 * Make new channel
8474 *
8475 * We cannot hold the p or ast locks while creating a new
8476 * channel.
8477 */
8479 ast_channel_unlock(ast);
8480 chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, NULL, callid);
8481 ast_channel_lock(ast);
8482 ast_mutex_lock(&p->lock);
8483 if (p->dahditrcallerid) {
8484 if (!p->origcid_num)
8486 if (!p->origcid_name)
8488 ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
8489 ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
8490 }
8491 /* Swap things around between the three-way and real call */
8493 /* Disable echo canceller for better dialing */
8495 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
8496 if (res)
8497 ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
8498 p->owner = chan;
8499 if (!chan) {
8500 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
8501 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
8502 ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
8503 res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
8504 dahdi_ec_enable(p);
8505 ast_hangup(chan);
8506 } else {
8507 ast_verb(3, "Started three way call on channel %d\n", p->channel);
8508
8509 /* Start music on hold */
8511 p->subs[SUB_THREEWAY].needhold = 1;
8512 }
8513 ast_callid_threadstorage_auto_clean(callid, callid_created);
8514 }
8515 } else {
8516 /* Already have a 3 way call */
8517 if (p->subs[SUB_THREEWAY].inthreeway) {
8518 /* Call is already up, drop the last person */
8519 ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
8520 /* If the primary call isn't answered yet, use it */
8522 /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
8524 p->owner = p->subs[SUB_REAL].owner;
8525 }
8526 /* Drop the last call and stop the conference */
8527 ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8529 p->subs[SUB_REAL].inthreeway = 0;
8531 } else {
8532 /* Lets see what we're up to */
8533 if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
8535 int otherindex = SUB_THREEWAY;
8536
8537 ast_verb(3, "Building conference call with %s and %s\n",
8540 /* Put them in the threeway, and flip */
8542 p->subs[SUB_REAL].inthreeway = 1;
8543 if (ast_channel_state(ast) == AST_STATE_UP) {
8545 otherindex = SUB_REAL;
8546 }
8547 if (p->subs[otherindex].owner) {
8548 ast_queue_unhold(p->subs[otherindex].owner);
8549 }
8550 p->subs[otherindex].needunhold = 1;
8551 p->owner = p->subs[SUB_REAL].owner;
8552 } else {
8553 ast_verb(3, "Dumping incomplete call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
8556 p->owner = p->subs[SUB_REAL].owner;
8557 if (p->subs[SUB_REAL].owner) {
8559 }
8560 p->subs[SUB_REAL].needunhold = 1;
8561 dahdi_ec_enable(p);
8562 }
8563 }
8564 }
8565winkflashdone:
8567 break;
8568 case SIG_EM:
8569 case SIG_EM_E1:
8570 case SIG_FEATD:
8571 case SIG_SF:
8572 case SIG_SFWINK:
8573 case SIG_SF_FEATD:
8574 case SIG_FXSLS:
8575 case SIG_FXSGS:
8576 if (p->dialing)
8577 ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
8578 else
8579 ast_debug(1, "Got wink in weird state %u on channel %d\n", ast_channel_state(ast), p->channel);
8580 break;
8581 case SIG_FEATDMF_TA:
8582 switch (p->whichwink) {
8583 case 0:
8584 ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
8587 snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
8591 break;
8592 case 1:
8593 ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
8594 break;
8595 case 2:
8596 ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
8597 return NULL;
8598 }
8599 p->whichwink++;
8600 /* Fall through */
8601 case SIG_FEATDMF:
8602 case SIG_E911:
8603 case SIG_FGC_CAMAMF:
8604 case SIG_FGC_CAMA:
8605 case SIG_FEATB:
8606 case SIG_SF_FEATDMF:
8607 case SIG_SF_FEATB:
8608 case SIG_EMWINK:
8609 /* FGD MF and EMWINK *Must* wait for wink */
8610 if (!ast_strlen_zero(p->dop.dialstr)) {
8611 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8612 if (res) {
8613 p->dop.dialstr[0] = '\0';
8614 return NULL;
8615 } else
8616 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8617 }
8618 p->dop.dialstr[0] = '\0';
8619 break;
8620 default:
8621 ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
8622 }
8623 break;
8624 case DAHDI_EVENT_HOOKCOMPLETE:
8625 if (p->inalarm) break;
8626 if ((p->radio || (p->oprmode < 0))) break;
8627 if (p->waitingfordt.tv_sec) break;
8628 switch (mysig) {
8629 case SIG_FXSLS: /* only interesting for FXS */
8630 case SIG_FXSGS:
8631 case SIG_FXSKS:
8632 case SIG_EM:
8633 case SIG_EM_E1:
8634 case SIG_EMWINK:
8635 case SIG_FEATD:
8636 case SIG_SF:
8637 case SIG_SFWINK:
8638 case SIG_SF_FEATD:
8639 if (!ast_strlen_zero(p->dop.dialstr)) {
8640 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
8641 if (res) {
8642 p->dop.dialstr[0] = '\0';
8643 return NULL;
8644 } else
8645 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
8646 }
8647 p->dop.dialstr[0] = '\0';
8648 p->dop.op = DAHDI_DIAL_OP_REPLACE;
8649 break;
8650 case SIG_FEATDMF:
8651 case SIG_FEATDMF_TA:
8652 case SIG_E911:
8653 case SIG_FGC_CAMA:
8654 case SIG_FGC_CAMAMF:
8655 case SIG_FEATB:
8656 case SIG_SF_FEATDMF:
8657 case SIG_SF_FEATB:
8658 ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
8659 break;
8660 default:
8661 break;
8662 }
8663 break;
8664 case DAHDI_EVENT_POLARITY:
8665 /*
8666 * If we get a Polarity Switch event, check to see
8667 * if we should change the polarity state and
8668 * mark the channel as UP or if this is an indication
8669 * of remote end disconnect.
8670 */
8671 if (p->polarity == POLARITY_IDLE) {
8673 if (p->answeronpolarityswitch &&
8676 ast_debug(1, "Answering on polarity switch!\n");
8678 if (p->hanguponpolarityswitch) {
8680 }
8681 } else
8682 ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8683 }
8684 /* Removed else statement from here as it was preventing hangups from ever happening*/
8685 /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
8686 if (p->hanguponpolarityswitch &&
8687 (p->polarityonanswerdelay > 0) &&
8688 (p->polarity == POLARITY_REV) &&
8690 /* Added log_debug information below to provide a better indication of what is going on */
8691 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) );
8692
8694 ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
8697 } else
8698 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));
8699
8700 } else {
8702 ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %u\n", p->channel, ast_channel_state(ast));
8703 }
8704 /* Added more log_debug information below to provide a better indication of what is going on */
8705 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) );
8706 break;
8707 default:
8708 ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
8709 }
8710 return &p->subs[idx].f;
8711}
8712
8713static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
8714{
8715 int res;
8716 int idx;
8717 struct ast_frame *f;
8718 int usedindex = -1;
8719 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8720
8721 if ((idx = dahdi_get_index(ast, p, 0)) < 0) {
8722 idx = SUB_REAL;
8723 }
8724
8725 p->subs[idx].f.frametype = AST_FRAME_NULL;
8726 p->subs[idx].f.datalen = 0;
8727 p->subs[idx].f.samples = 0;
8728 p->subs[idx].f.mallocd = 0;
8729 p->subs[idx].f.offset = 0;
8730 p->subs[idx].f.subclass.integer = 0;
8731 p->subs[idx].f.delivery = ast_tv(0,0);
8732 p->subs[idx].f.src = "dahdi_exception";
8733 p->subs[idx].f.data.ptr = NULL;
8734
8735
8736 if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
8737 /* If nobody owns us, absorb the event appropriately, otherwise
8738 we loop indefinitely. This occurs when, during call waiting, the
8739 other end hangs up our channel so that it no longer exists, but we
8740 have neither FLASH'd nor ONHOOK'd to signify our desire to
8741 change to the other channel. */
8742 if (p->fake_event) {
8743 res = p->fake_event;
8744 p->fake_event = 0;
8745 } else
8746 res = dahdi_get_event(p->subs[SUB_REAL].dfd);
8747 /* Switch to real if there is one and this isn't something really silly... */
8748 if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
8749 (res != DAHDI_EVENT_HOOKCOMPLETE)) {
8750 ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
8751 p->owner = p->subs[SUB_REAL].owner;
8752 if (p->owner) {
8754 }
8755 p->subs[SUB_REAL].needunhold = 1;
8756 }
8757 switch (res) {
8758 case DAHDI_EVENT_ONHOOK:
8760 if (p->owner) {
8761 ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
8763 p->callwaitingrepeat = 0;
8764 p->cidcwexpire = 0;
8765 p->cid_suppress_expire = 0;
8766 } else
8767 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8769 break;
8770 case DAHDI_EVENT_RINGOFFHOOK:
8771 dahdi_ec_enable(p);
8772 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
8773 if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
8774 p->subs[SUB_REAL].needanswer = 1;
8775 p->dialing = 0;
8776 }
8777 break;
8778 case DAHDI_EVENT_HOOKCOMPLETE:
8779 case DAHDI_EVENT_RINGERON:
8780 case DAHDI_EVENT_RINGEROFF:
8781 /* Do nothing */
8782 break;
8783 case DAHDI_EVENT_WINKFLASH:
8784 p->flashtime = ast_tvnow();
8785 if (p->owner) {
8786 ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
8788 /* Answer if necessary */
8789 usedindex = dahdi_get_index(p->owner, p, 0);
8790 if (usedindex > -1) {
8791 p->subs[usedindex].needanswer = 1;
8792 }
8794 }
8795 p->callwaitingrepeat = 0;
8796 p->cidcwexpire = 0;
8797 p->cid_suppress_expire = 0;
8799 p->subs[SUB_REAL].needunhold = 1;
8800 } else
8801 ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
8803 break;
8804 default:
8805 ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
8806 }
8807 f = &p->subs[idx].f;
8808 return f;
8809 }
8810 if (!(p->radio || (p->oprmode < 0)))
8811 ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
8812 /* If it's not us, return NULL immediately */
8813 if (ast != p->owner) {
8814 if (p->owner) {
8815 ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
8816 }
8817 f = &p->subs[idx].f;
8818 return f;
8819 }
8820
8821 f = dahdi_handle_event(ast);
8822 if (!f) {
8823 const char *name = ast_strdupa(ast_channel_name(ast));
8824
8825 /* Tell the CDR this DAHDI device hung up */
8827 ast_channel_unlock(ast);
8828 ast_set_hangupsource(ast, name, 0);
8829 ast_channel_lock(ast);
8830 ast_mutex_lock(&p->lock);
8831 }
8832 return f;
8833}
8834
8835static struct ast_frame *dahdi_exception(struct ast_channel *ast)
8836{
8837 struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
8838 struct ast_frame *f;
8839 ast_mutex_lock(&p->lock);
8840 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
8841 struct analog_pvt *analog_p = p->sig_pvt;
8842 f = analog_exception(analog_p, ast);
8843 } else {
8844 f = __dahdi_exception(ast);
8845 }
8847 return f;
8848}
8849
8850static struct ast_frame *dahdi_read(struct ast_channel *ast)
8851{
8852 struct dahdi_pvt *p;
8853 int res;
8854 int idx;
8855 void *readbuf;
8856 struct ast_frame *f;
8857
8858 /*
8859 * For analog channels, we must do deadlock avoidance because
8860 * analog ports can have more than one Asterisk channel using
8861 * the same private structure.
8862 */
8863 p = ast_channel_tech_pvt(ast);
8864 while (ast_mutex_trylock(&p->lock)) {
8866
8867 /*
8868 * Check to see if the channel is still associated with the same
8869 * private structure. While the Asterisk channel was unlocked
8870 * the following events may have occurred:
8871 *
8872 * 1) A masquerade may have associated the channel with another
8873 * technology or private structure.
8874 *
8875 * 2) For PRI calls, call signaling could change the channel
8876 * association to another B channel (private structure).
8877 */
8878 if (ast_channel_tech_pvt(ast) != p) {
8879 /* The channel is no longer associated. Quit gracefully. */
8880 return &ast_null_frame;
8881 }
8882 }
8883
8884 idx = dahdi_get_index(ast, p, 0);
8885
8886 /* Hang up if we don't really exist */
8887 if (idx < 0) {
8888 ast_log(LOG_WARNING, "We don't exist?\n");
8890 return NULL;
8891 }
8892
8893 if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
8895 return NULL;
8896 }
8897
8898 p->subs[idx].f.frametype = AST_FRAME_NULL;
8899 p->subs[idx].f.datalen = 0;
8900 p->subs[idx].f.samples = 0;
8901 p->subs[idx].f.mallocd = 0;
8902 p->subs[idx].f.offset = 0;
8903 p->subs[idx].f.subclass.integer = 0;
8904 p->subs[idx].f.delivery = ast_tv(0,0);
8905 p->subs[idx].f.src = "dahdi_read";
8906 p->subs[idx].f.data.ptr = NULL;
8907
8908 /* make sure it sends initial key state as first frame */
8909 if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
8910 {
8911 struct dahdi_params ps;
8912
8913 memset(&ps, 0, sizeof(ps));
8914 if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
8916 return NULL;
8917 }
8918 p->firstradio = 1;
8920 if (ps.rxisoffhook)
8921 {
8923 }
8924 else
8925 {
8927 }
8929 return &p->subs[idx].f;
8930 }
8931 if (p->ringt > 0) {
8932 if (!(--p->ringt)) {
8934 return NULL;
8935 }
8936 }
8937
8938#ifdef HAVE_OPENR2
8939 if (p->mfcr2) {
8940 openr2_chan_process_event(p->r2chan);
8941 if (OR2_DIR_FORWARD == openr2_chan_get_direction(p->r2chan)) {
8943 /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
8944 * now enqueue a progress frame to bridge the media up */
8945 if (p->mfcr2_call_accepted &&
8946 !p->mfcr2_progress_sent &&
8948 ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
8949 ast_queue_frame(p->owner, &fr);
8950 p->mfcr2_progress_sent = 1;
8951 }
8952 }
8953 }
8954#endif
8955
8956 if (p->subs[idx].needringing) {
8957 /* Send ringing frame if requested */
8958 p->subs[idx].needringing = 0;
8963 return &p->subs[idx].f;
8964 }
8965
8966 if (p->subs[idx].needbusy) {
8967 /* Send busy frame if requested */
8968 p->subs[idx].needbusy = 0;
8972 return &p->subs[idx].f;
8973 }
8974
8975 if (p->subs[idx].needcongestion) {
8976 /* Send congestion frame if requested */
8977 p->subs[idx].needcongestion = 0;
8981 return &p->subs[idx].f;
8982 }
8983
8984 if (p->subs[idx].needanswer) {
8985 /* Send answer frame if requested */
8986 p->subs[idx].needanswer = 0;
8990 return &p->subs[idx].f;
8991 }
8992#ifdef HAVE_OPENR2
8993 if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
8994 /* openr2 took care of reading and handling any event
8995 (needanswer, needbusy etc), if we continue we will read()
8996 twice, lets just return a null frame. This should only
8997 happen when openr2 is dialing out */
8999 return &ast_null_frame;
9000 }
9001#endif
9002
9003 if (p->subs[idx].needflash) {
9004 /* Send answer frame if requested */
9005 p->subs[idx].needflash = 0;
9009 return &p->subs[idx].f;
9010 }
9011
9012 if (p->subs[idx].needhold) {
9013 /* Send answer frame if requested */
9014 p->subs[idx].needhold = 0;
9018 ast_debug(1, "Sending hold on '%s'\n", ast_channel_name(ast));
9019 return &p->subs[idx].f;
9020 }
9021
9022 if (p->subs[idx].needunhold) {
9023 /* Send answer frame if requested */
9024 p->subs[idx].needunhold = 0;
9028 ast_debug(1, "Sending unhold on '%s'\n", ast_channel_name(ast));
9029 return &p->subs[idx].f;
9030 }
9031
9032 /*
9033 * If we have a fake_event, fake an exception to handle it only
9034 * if this channel owns the private.
9035 */
9036 if (p->fake_event && p->owner == ast) {
9037 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9038 struct analog_pvt *analog_p = p->sig_pvt;
9039
9040 f = analog_exception(analog_p, ast);
9041 } else {
9042 f = __dahdi_exception(ast);
9043 }
9045 return f;
9046 }
9047
9049 if (!p->subs[idx].linear) {
9050 p->subs[idx].linear = 1;
9051 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9052 if (res)
9053 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
9054 }
9055 } else {
9056 if (p->subs[idx].linear) {
9057 p->subs[idx].linear = 0;
9058 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9059 if (res)
9060 ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
9061 }
9062 }
9063 readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
9064 CHECK_BLOCKING(ast);
9065 res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9067 /* Check for hangup */
9068 if (res < 0) {
9069 f = NULL;
9070 if (res == -1) {
9071 if (errno == EAGAIN) {
9072 /* Return "NULL" frame if there is nobody there */
9074 return &p->subs[idx].f;
9075 } else if (errno == ELAST) {
9076 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9077 struct analog_pvt *analog_p = p->sig_pvt;
9078 f = analog_exception(analog_p, ast);
9079 } else {
9080 f = __dahdi_exception(ast);
9081 }
9082 } else
9083 ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
9084 }
9086 return f;
9087 }
9088 if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
9089 ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
9090 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9091 struct analog_pvt *analog_p = p->sig_pvt;
9092 f = analog_exception(analog_p, ast);
9093 } else {
9094 f = __dahdi_exception(ast);
9095 }
9097 return f;
9098 }
9099 if (p->tdd) { /* if in TDD mode, see if we receive that */
9100 int c;
9101
9102 c = tdd_feed(p->tdd,readbuf,READ_SIZE);
9103 if (c < 0) {
9104 ast_debug(1,"tdd_feed failed\n");
9106 return NULL;
9107 }
9108 if (c) { /* if a char to return */
9109 p->subs[idx].f.subclass.integer = 0;
9110 p->subs[idx].f.frametype = AST_FRAME_TEXT;
9111 p->subs[idx].f.mallocd = 0;
9112 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9113 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
9114 p->subs[idx].f.datalen = 1;
9115 *((char *) p->subs[idx].f.data.ptr) = c;
9117 return &p->subs[idx].f;
9118 }
9119 }
9120 if (idx == SUB_REAL) {
9121 /* Ensure the CW timers decrement only on a single subchannel */
9122 if (p->cidcwexpire) {
9123 if (!--p->cidcwexpire) {
9124 /* Expired CID/CW */
9125 ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
9127 }
9128 }
9129 if (p->cid_suppress_expire) {
9131 }
9132 if (p->callwaitingrepeat) {
9133 if (!--p->callwaitingrepeat) {
9134 /* Expired, Repeat callwaiting tone */
9135 ++p->callwaitrings;
9136 dahdi_callwait(ast);
9137 }
9138 }
9139 }
9140 if (p->subs[idx].linear) {
9141 p->subs[idx].f.datalen = READ_SIZE * 2;
9142 } else
9143 p->subs[idx].f.datalen = READ_SIZE;
9144
9145 /* Handle CallerID Transmission */
9146 if ((p->owner == ast) && p->cidspill) {
9147 send_callerid(p);
9148 }
9149
9150 p->subs[idx].f.frametype = AST_FRAME_VOICE;
9152 p->subs[idx].f.samples = READ_SIZE;
9153 p->subs[idx].f.mallocd = 0;
9154 p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
9155 p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
9156#if 0
9157 ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
9158#endif
9159 if ((p->dialing && !p->waitingfordt.tv_sec) || p->radio || /* Transmitting something */
9160 (idx && (ast_channel_state(ast) != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
9161 ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
9162 ) {
9163 /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
9164 don't send anything */
9165 p->subs[idx].f.frametype = AST_FRAME_NULL;
9166 p->subs[idx].f.subclass.integer = 0;
9167 p->subs[idx].f.samples = 0;
9168 p->subs[idx].f.mallocd = 0;
9169 p->subs[idx].f.offset = 0;
9170 p->subs[idx].f.data.ptr = NULL;
9171 p->subs[idx].f.datalen= 0;
9172 }
9173 if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec || p->dialtone_detect) && !idx) {
9174 /* Perform busy detection etc on the dahdi line */
9175 int mute;
9176
9178 && p->faxdetect_timeout
9180 p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
9182 ast_debug(1, "Channel driver fax CNG detection timeout on %s\n",
9183 ast_channel_name(ast));
9184 }
9185
9186 f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
9187
9188 /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
9189 mute = ast_dsp_was_muted(p->dsp);
9190 if (p->muting != mute) {
9191 p->muting = mute;
9192 dahdi_confmute(p, mute);
9193 }
9194
9195 if (f) {
9197 && !p->outgoing && ast_channel_state(ast) == AST_STATE_UP) {
9199 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9201 }
9202 }
9204 if ((ast_channel_state(ast) == AST_STATE_UP) && !p->outgoing) {
9205 /*
9206 * Treat this as a "hangup" instead of a "busy" on the
9207 * assumption that a busy means the incoming call went away.
9208 */
9209 ast_frfree(f);
9210 f = NULL;
9211 }
9212 } else if (p->dialtone_detect && !p->outgoing && f->frametype == AST_FRAME_VOICE) {
9214 /* Dialtone detected on inbound call; hangup the channel */
9215 ast_frfree(f);
9216 f = NULL;
9217 }
9218 } else if (f->frametype == AST_FRAME_DTMF_BEGIN
9219 || f->frametype == AST_FRAME_DTMF_END) {
9220#ifdef HAVE_PRI
9222 && ((struct sig_pri_chan *) p->sig_pvt)->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING
9223 && p->pri
9224 && ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING))
9225 || (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
9226 /* Don't accept in-band DTMF when in overlap dial mode */
9227 ast_debug(1, "Absorbing inband %s DTMF digit: 0x%02X '%c' on %s\n",
9228 f->frametype == AST_FRAME_DTMF_BEGIN ? "begin" : "end",
9229 (unsigned)f->subclass.integer, f->subclass.integer, ast_channel_name(ast));
9230
9232 f->subclass.integer = 0;
9233 }
9234#endif
9235 /* DSP clears us of being pulse */
9236 p->pulsedial = 0;
9237 } else if (p->waitingfordt.tv_sec) {
9239 p->waitingfordt.tv_sec = 0;
9240 ast_log(LOG_NOTICE, "Never saw dialtone on channel %d\n", p->channel);
9241 ast_frfree(f);
9242 f = NULL;
9243 } else if (f->frametype == AST_FRAME_VOICE) {
9245 f->subclass.integer = 0;
9247 p->waitingfordt.tv_sec = 0;
9248 p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
9250 ast_debug(1, "Got 10 samples of dialtone!\n");
9251 if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
9252 res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
9253 if (res) {
9254 p->dop.dialstr[0] = '\0';
9256 ast_frfree(f);
9257 return NULL;
9258 } else {
9259 ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
9260 p->dialing = 1;
9261 p->dop.dialstr[0] = '\0';
9262 p->dop.op = DAHDI_DIAL_OP_REPLACE;
9264 }
9265 }
9266 }
9267 }
9268 }
9269 }
9270 } else
9271 f = &p->subs[idx].f;
9272
9273 if (f) {
9274 struct analog_pvt *analog_p = p->sig_pvt;
9275 switch (f->frametype) {
9277 case AST_FRAME_DTMF_END:
9278 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
9279 analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
9280 } else {
9281 dahdi_handle_dtmf(ast, idx, &f);
9282 }
9283 if (!(analog_p->dialmode == ANALOG_DIALMODE_BOTH || analog_p->dialmode == ANALOG_DIALMODE_DTMF)) {
9284 if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
9285 ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
9286 }
9288 f->subclass.integer = 0;
9289 }
9290 break;
9291 case AST_FRAME_VOICE:
9292 if (p->cidspill || p->cid_suppress_expire) {
9293 /* We are/were sending a caller id spill. Suppress any echo. */
9294 p->subs[idx].f.frametype = AST_FRAME_NULL;
9295 p->subs[idx].f.subclass.integer = 0;
9296 p->subs[idx].f.samples = 0;
9297 p->subs[idx].f.mallocd = 0;
9298 p->subs[idx].f.offset = 0;
9299 p->subs[idx].f.data.ptr = NULL;
9300 p->subs[idx].f.datalen= 0;
9301 }
9302 break;
9303 default:
9304 break;
9305 }
9306 }
9307
9309 return f;
9310}
9311
9312static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
9313{
9314 int sent=0;
9315 int size;
9316 int res;
9317 int fd;
9318 fd = p->subs[idx].dfd;
9319 while (len) {
9320 size = len;
9321 if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
9322 size = (linear ? READ_SIZE * 2 : READ_SIZE);
9323 res = write(fd, buf, size);
9324 if (res != size) {
9325 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
9326 return sent;
9327 }
9328 len -= size;
9329 buf += size;
9330 }
9331 return sent;
9332}
9333
9334static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
9335{
9336 struct dahdi_pvt *p;
9337 int res;
9338 int idx;
9339
9340 /* Write a frame of (presumably voice) data */
9341 if (frame->frametype != AST_FRAME_VOICE) {
9342 if (frame->frametype != AST_FRAME_IMAGE) {
9343 ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n",
9344 frame->frametype);
9345 }
9346 return 0;
9347 }
9348
9349 /* Return if it's not valid data */
9350 if (!frame->data.ptr || !frame->datalen) {
9351 return 0;
9352 }
9353
9354 p = ast_channel_tech_pvt(ast);
9355 ast_mutex_lock(&p->lock);
9356
9357 idx = dahdi_get_index(ast, p, 0);
9358 if (idx < 0) {
9360 ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast_channel_name(ast));
9361 return -1;
9362 }
9363
9364 if (IS_FXO_SIG(p)) {
9365 struct analog_pvt *analog_p = p->sig_pvt;
9366 if (analog_p->callwaitingdeluxepending) {
9367 unsigned int mssinceflash = ast_tvdiff_ms(ast_tvnow(), analog_p->flashtime);
9368 if (mssinceflash >= 1000) {
9369 /* Timer expired: the user hasn't yet selected an option. Take the default action and get on with it. */
9370 /* Note: If in the future Advanced Call Waiting Deluxe (*76) is supported, then as part of the
9371 * dialing code, we'll need to automatically invoke the preselected behavior about 2-3 seconds after
9372 * the call waiting begins (this allows for the SAS, CAS, and CWCID spill to be sent first).
9373 */
9374 analog_p->callwaitingdeluxepending = 0;
9375 analog_callwaiting_deluxe(analog_p, 0);
9376 }
9378 /* The user shouldn't hear anything after hook flashing, until a decision is made, by the user or when the timer expires. */
9379 ast_debug(5, "Dropping frame since Call Waiting Deluxe pending on %s\n", ast_channel_name(ast));
9380 return 0;
9381 }
9382 }
9383
9384 if (p->dialing) {
9386 ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",
9387 ast_channel_name(ast));
9388 return 0;
9389 }
9390 if (!p->owner) {
9392 ast_debug(5, "Dropping frame since there is no active owner on %s...\n",
9393 ast_channel_name(ast));
9394 return 0;
9395 }
9396 if (p->cidspill) {
9398 ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
9399 ast_channel_name(ast));
9400 return 0;
9401 }
9402
9404 if (!p->subs[idx].linear) {
9405 p->subs[idx].linear = 1;
9406 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9407 if (res)
9408 ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
9409 }
9410 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
9413 /* x-law already */
9414 if (p->subs[idx].linear) {
9415 p->subs[idx].linear = 0;
9416 res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
9417 if (res)
9418 ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
9419 }
9420 res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
9421 } else {
9423 ast_log(LOG_WARNING, "Cannot handle frames in %s format\n",
9425 return -1;
9426 }
9428 if (res < 0) {
9429 ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
9430 return -1;
9431 }
9432 return 0;
9433}
9434
9435static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
9436{
9437 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9438 int res=-1;
9439 int idx;
9440 int func = DAHDI_FLASH;
9441
9442 ast_mutex_lock(&p->lock);
9443 ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
9444 switch (p->sig) {
9445#if defined(HAVE_PRI)
9447 res = sig_pri_indicate(p->sig_pvt, chan, condition, data, datalen);
9449 return res;
9450#endif /* defined(HAVE_PRI) */
9451#if defined(HAVE_SS7)
9452 case SIG_SS7:
9453 res = sig_ss7_indicate(p->sig_pvt, chan, condition, data, datalen);
9455 return res;
9456#endif /* defined(HAVE_SS7) */
9457 default:
9458 break;
9459 }
9460#ifdef HAVE_OPENR2
9461 if (p->mfcr2 && !p->mfcr2_call_accepted) {
9463 /* if this is an R2 call and the call is not yet accepted, we don't want the
9464 tone indications to mess up with the MF tones */
9465 return 0;
9466 }
9467#endif
9468 idx = dahdi_get_index(chan, p, 0);
9469 if (idx == SUB_REAL) {
9470 switch (condition) {
9471 case AST_CONTROL_BUSY:
9472 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
9473 break;
9475 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
9476
9477 if (ast_channel_state(chan) != AST_STATE_UP) {
9478 if ((ast_channel_state(chan) != AST_STATE_RING) ||
9479 ((p->sig != SIG_FXSKS) &&
9480 (p->sig != SIG_FXSLS) &&
9481 (p->sig != SIG_FXSGS))) {
9482 /* We're playing audible ringback tone on the channel,
9483 * so set state to AST_STATE_RING, not AST_STATE_RINGING. */
9485 }
9486 }
9487 break;
9489 ast_debug(1, "Received AST_CONTROL_INCOMPLETE on %s\n", ast_channel_name(chan));
9490 /* act as a progress or proceeding, allowing the caller to enter additional numbers */
9491 res = 0;
9492 break;
9494 ast_debug(1, "Received AST_CONTROL_PROCEEDING on %s\n", ast_channel_name(chan));
9495 /* don't continue in ast_indicate */
9496 res = 0;
9497 break;
9499 ast_debug(1, "Received AST_CONTROL_PROGRESS on %s\n", ast_channel_name(chan));
9500 /* don't continue in ast_indicate */
9501 res = 0;
9502 break;
9504 /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
9505 switch (ast_channel_hangupcause(chan)) {
9508 case 0:/* Cause has not been set. */
9509 /* Supply a more appropriate cause. */
9511 break;
9512 default:
9513 break;
9514 }
9515 break;
9516 case AST_CONTROL_HOLD:
9517 ast_moh_start(chan, data, p->mohinterpret);
9518 break;
9519 case AST_CONTROL_UNHOLD:
9520 ast_moh_stop(chan);
9521 break;
9523 if (p->radio)
9524 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
9525 res = 0;
9526 break;
9528 if (p->radio)
9529 res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
9530 res = 0;
9531 break;
9532 case AST_CONTROL_FLASH:
9533 /* flash hookswitch */
9534 if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
9535 /* Clear out the dial buffer */
9536 p->dop.dialstr[0] = '\0';
9537 if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
9538 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
9539 ast_channel_name(chan), strerror(errno));
9540 } else
9541 res = 0;
9542 } else
9543 res = 0;
9544 break;
9546 res = 0;
9547 break;
9548 case -1:
9549 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
9550 break;
9551 }
9552 } else {
9553 res = 0;
9554 }
9556 return res;
9557}
9558
9559#if defined(HAVE_PRI)
9560static struct ast_str *create_channel_name(struct dahdi_pvt *i, int is_outgoing, char *address)
9561#else
9562static struct ast_str *create_channel_name(struct dahdi_pvt *i)
9563#endif /* defined(HAVE_PRI) */
9564{
9565 struct ast_str *chan_name;
9566 int x, y;
9567
9568 /* Create the new channel name tail. */
9569 if (!(chan_name = ast_str_create(32))) {
9570 return NULL;
9571 }
9572 if (i->channel == CHAN_PSEUDO) {
9573 ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
9574#if defined(HAVE_PRI)
9575 } else if (i->pri) {
9576 ast_mutex_lock(&i->pri->lock);
9577 y = ++i->pri->new_chan_seq;
9578 if (is_outgoing) {
9579 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, address, (unsigned)y);
9580 address[0] = '\0';
9581 } else if (ast_strlen_zero(i->cid_subaddr)) {
9582 /* Put in caller-id number only since there is no subaddress. */
9583 ast_str_set(&chan_name, 0, "i%d/%s-%x", i->pri->span, i->cid_num, (unsigned)y);
9584 } else {
9585 /* Put in caller-id number and subaddress. */
9586 ast_str_set(&chan_name, 0, "i%d/%s:%s-%x", i->pri->span, i->cid_num,
9587 i->cid_subaddr, (unsigned)y);
9588 }
9589 ast_mutex_unlock(&i->pri->lock);
9590#endif /* defined(HAVE_PRI) */
9591 } else {
9592 y = 1;
9593 do {
9594 ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
9595 for (x = 0; x < 3; ++x) {
9596 if (i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name),
9597 ast_channel_name(i->subs[x].owner) + 6)) {
9598 break;
9599 }
9600 }
9601 ++y;
9602 } while (x < 3);
9603 }
9604 return chan_name;
9605}
9606
9607static 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)
9608{
9609 struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, assignedids, requestor, callid);
9610
9612
9613 return new_channel;
9614}
9615
9616static 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)
9617{
9618 struct ast_channel *tmp;
9619 struct ast_format_cap *caps;
9620 struct ast_format *deflaw;
9621 int x;
9622 int features;
9623 struct ast_str *chan_name;
9624 struct ast_variable *v;
9625 char *dashptr;
9626 char device_name[AST_CHANNEL_NAME];
9627
9628 if (i->subs[idx].owner) {
9629 ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
9630 return NULL;
9631 }
9632
9633#if defined(HAVE_PRI)
9634 /*
9635 * The dnid has been stuffed with the called-number[:subaddress]
9636 * by dahdi_request() for outgoing calls.
9637 */
9638 chan_name = create_channel_name(i, i->outgoing, i->dnid);
9639#else
9640 chan_name = create_channel_name(i);
9641#endif /* defined(HAVE_PRI) */
9642 if (!chan_name) {
9643 return NULL;
9644 }
9645
9647 if (!caps) {
9648 ast_free(chan_name);
9649 return NULL;
9650 }
9651
9652 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));
9653 ast_free(chan_name);
9654 if (!tmp) {
9655 ao2_ref(caps, -1);
9656 return NULL;
9657 }
9658
9660
9661 if (callid) {
9662 ast_channel_callid_set(tmp, callid);
9663 }
9664
9666#if defined(HAVE_PRI)
9667 if (i->pri) {
9669 }
9670#endif /* defined(HAVE_PRI) */
9672 if (law) {
9673 i->law = law;
9674 if (law == DAHDI_LAW_ALAW) {
9675 deflaw = ast_format_alaw;
9676 } else {
9677 deflaw = ast_format_ulaw;
9678 }
9679 } else {
9680 switch (i->sig) {
9682 /* Make sure companding law is known. */
9683 i->law = (i->law_default == DAHDI_LAW_ALAW)
9684 ? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
9685 break;
9686 default:
9687 i->law = i->law_default;
9688 break;
9689 }
9690 if (i->law_default == DAHDI_LAW_ALAW) {
9691 deflaw = ast_format_alaw;
9692 } else {
9693 deflaw = ast_format_ulaw;
9694 }
9695 }
9696 ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
9697 ast_format_cap_append(caps, deflaw, 0);
9699 ao2_ref(caps, -1);
9700 /* Start out assuming ulaw since it's smaller :) */
9701 ast_channel_set_rawreadformat(tmp, deflaw);
9702 ast_channel_set_readformat(tmp, deflaw);
9703 ast_channel_set_rawwriteformat(tmp, deflaw);
9704 ast_channel_set_writeformat(tmp, deflaw);
9705 i->subs[idx].linear = 0;
9706 dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
9707 features = 0;
9708 if (idx == SUB_REAL) {
9709 if (i->busydetect && CANBUSYDETECT(i))
9710 features |= DSP_FEATURE_BUSY_DETECT;
9712 features |= DSP_FEATURE_CALL_PROGRESS;
9714 features |= DSP_FEATURE_WAITDIALTONE;
9715 if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
9717 features |= DSP_FEATURE_FAX_DETECT;
9718 }
9719 x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
9720 if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
9721 i->hardwaredtmf = 0;
9722 features |= DSP_FEATURE_DIGIT_DETECT;
9723 } else if (NEED_MFDETECT(i)) {
9724 i->hardwaredtmf = 1;
9725 features |= DSP_FEATURE_DIGIT_DETECT;
9726 }
9727 }
9728 if (features) {
9729 if (i->dsp) {
9730 ast_debug(1, "Already have a dsp on %s?\n", ast_channel_name(tmp));
9731 } else {
9732 if (i->channel != CHAN_PSEUDO)
9733 i->dsp = ast_dsp_new();
9734 else
9735 i->dsp = NULL;
9736 if (i->dsp) {
9737 i->dsp_features = features;
9738#if defined(HAVE_PRI) || defined(HAVE_SS7)
9739 /* We cannot do progress detection until receive PROGRESS message */
9740 if (i->outgoing && (dahdi_sig_pri_lib_handles(i->sig) || (i->sig == SIG_SS7))) {
9741 /* Remember requested DSP features, don't treat
9742 talking as ANSWER */
9743 i->dsp_features = features & ~DSP_PROGRESS_TALK;
9744 features = 0;
9745 }
9746#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9747 ast_dsp_set_features(i->dsp, features);
9751 if (i->busydetect && CANBUSYDETECT(i)) {
9754 }
9755 }
9756 }
9757 }
9758
9760
9761 if (state == AST_STATE_RING)
9762 ast_channel_rings_set(tmp, 1);
9764 if (IS_FXO_SIG(i)) {
9765 /* Only FXO signalled stuff can be picked up */
9770 }
9771 if (!ast_strlen_zero(i->parkinglot))
9772 ast_channel_parkinglot_set(tmp, i->parkinglot);
9773 if (!ast_strlen_zero(i->language))
9774 ast_channel_language_set(tmp, i->language);
9775 if (!i->owner)
9776 i->owner = tmp;
9778 ast_channel_accountcode_set(tmp, i->accountcode);
9779 if (i->amaflags)
9781 i->subs[idx].owner = tmp;
9783 if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
9784 ast_channel_call_forward_set(tmp, i->call_forward);
9785 }
9786 /* If we've been told "no ADSI" then enforce it */
9787 if (!i->adsi)
9789 if (!ast_strlen_zero(i->exten))
9791 if (!ast_strlen_zero(i->rdnis)) {
9794 }
9795 if (!ast_strlen_zero(i->dnid)) {
9797 }
9798
9799 /* Don't use ast_set_callerid() here because it will
9800 * generate a needless NewCallerID event */
9801#if defined(HAVE_PRI) || defined(HAVE_SS7)
9802 if (!ast_strlen_zero(i->cid_ani)) {
9804 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
9805 } else if (!ast_strlen_zero(i->cid_num)) {
9808 }
9809#else
9810 if (!ast_strlen_zero(i->cid_num)) {
9813 }
9814#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
9818 ast_channel_caller(tmp)->ani2 = i->cid_ani2;
9820 /* clear the fake event in case we posted one before we had ast_channel */
9821 i->fake_event = 0;
9822 /* Assure there is no confmute on this channel */
9823 dahdi_confmute(i, 0);
9824 i->muting = 0;
9825 /* Configure the new channel jb */
9827
9828 /* Set initial device state */
9829 if (IS_FXO_SIG(i) && idx == SUB_REAL && state == AST_STATE_RESERVED && !startpbx && requestor) {
9830 /* In the case that an analog line is receiving a call, temporarily suppress device state updates.
9831 * If we updated the device state right now, the calculated device state would be "INUSE",
9832 * even though almost instantly, it will become "RINGING". This is problematic,
9833 * because many IP phones ignore INUSE -> RINGING transitions since that's not technically possible.
9834 * To prevent such a bogus transition, if this line is about to ring and is not already in use, skip the update.
9835 * The next update will correctly start device state at RINGING so everything works as devices expect. */
9836 ast_debug(3, "Suppressing immediate device state update to prevent INUSE -> RINGING transition\n");
9837 } else {
9838 ast_copy_string(device_name, ast_channel_name(tmp), sizeof(device_name));
9839 dashptr = strrchr(device_name, '-');
9840 if (dashptr) {
9841 *dashptr = '\0';
9842 }
9844 }
9845
9846 for (v = i->vars ; v ; v = v->next)
9848
9850
9851 ast_channel_unlock(tmp);
9852
9854
9856 if (startpbx) {
9857#ifdef HAVE_OPENR2
9858 if (i->mfcr2call) {
9859 pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
9860 }
9861#endif
9862 if (ast_pbx_start(tmp)) {
9863 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
9864 ast_hangup(tmp);
9865 return NULL;
9866 }
9867 }
9868 return tmp;
9869}
9870
9871
9872static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
9873{
9874 char c;
9875
9876 *str = 0; /* start with empty output buffer */
9877 for (;;)
9878 {
9879 /* Wait for the first digit (up to specified ms). */
9880 c = ast_waitfordigit(chan, ms);
9881 /* if timeout, hangup or error, return as such */
9882 if (c < 1)
9883 return c;
9884 *str++ = c;
9885 *str = 0;
9886 if (strchr(term, c))
9887 return 1;
9888 }
9889}
9890
9891static int dahdi_wink(struct dahdi_pvt *p, int idx)
9892{
9893 int j;
9894 dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
9895 for (;;)
9896 {
9897 /* set bits of interest */
9898 j = DAHDI_IOMUX_SIGEVENT;
9899 /* wait for some happening */
9900 if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
9901 /* exit loop if we have it */
9902 if (j & DAHDI_IOMUX_SIGEVENT) break;
9903 }
9904 /* get the event info */
9905 if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
9906 return 0;
9907}
9908
9909static void publish_dnd_state(int channel, const char *status)
9910{
9911 RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
9912 RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
9913 if (!dahdichan) {
9914 return;
9915 }
9916
9917 ast_str_set(&dahdichan, 0, "%d", channel);
9918
9919 body = ast_json_pack("{s: s, s: s}",
9920 "DAHDIChannel", ast_str_buffer(dahdichan),
9921 "Status", status);
9922 if (!body) {
9923 return;
9924 }
9925
9927}
9928
9929/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
9930 * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
9931 * \param flag on 1 to enable, 0 to disable, -1 return dnd value
9932 *
9933 * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical
9934 * DAHDI channel). Use this to enable or disable it.
9935 *
9936 * \bug the use of the word "channel" for those dahdichans is really confusing.
9937 */
9938static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
9939{
9940 if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
9941 return analog_dnd(dahdichan->sig_pvt, flag);
9942 }
9943
9944 if (flag == -1) {
9945 return dahdichan->dnd;
9946 }
9947
9948 /* Do not disturb */
9949 dahdichan->dnd = flag;
9950 ast_verb(3, "%s DND on channel %d\n",
9951 flag? "Enabled" : "Disabled",
9952 dahdichan->channel);
9953 publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
9954 return 0;
9955}
9956
9957static int canmatch_featurecode(const char *pickupexten, const char *exten)
9958{
9959 int extlen = strlen(exten);
9960
9961 if (!extlen) {
9962 return 1;
9963 }
9964
9965 if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
9966 return 1;
9967 }
9968 /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
9969 if (exten[0] == '*' && extlen < 3) {
9970 if (extlen == 1) {
9971 return 1;
9972 }
9973 /* "*0" should be processed before it gets here */
9974 switch (exten[1]) {
9975 case '6':
9976 case '7':
9977 case '8':
9978 return 1;
9979 }
9980 }
9981 return 0;
9982}
9983
9984static void *analog_ss_thread(void *data)
9985{
9986 struct ast_channel *chan = data;
9987 struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
9988 char exten[AST_MAX_EXTENSION] = "";
9989 char exten2[AST_MAX_EXTENSION] = "";
9990 unsigned char buf[256];
9991 char dtmfcid[300];
9992 char dtmfbuf[300];
9993 struct callerid_state *cs = NULL;
9994 char *name = NULL, *number = NULL;
9995 int distMatches;
9996 int curRingData[3];
9997 int receivedRingT;
9998 int counter1;
9999 int counter;
10000 int samples = 0;
10001 struct ast_smdi_md_message *smdi_msg = NULL;
10002 int flags = 0;
10003 int i;
10004 int timeout;
10005 int getforward = 0;
10006 char *s1, *s2;
10007 int len = 0;
10008 int res;
10009 int idx;
10010 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
10011 const char *pickupexten;
10012
10016 /* in the bizarre case where the channel has become a zombie before we
10017 even get started here, abort safely
10018 */
10019 if (!p) {
10020 ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
10021 ast_hangup(chan);
10022 goto quit;
10023 }
10024 ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
10025 idx = dahdi_get_index(chan, p, 1);
10026 if (idx < 0) {
10027 ast_log(LOG_WARNING, "Huh?\n");
10028 ast_hangup(chan);
10029 goto quit;
10030 }
10031
10032 ast_channel_lock(chan);
10033 pickup_cfg = ast_get_chan_features_pickup_config(chan);
10034 if (!pickup_cfg) {
10035 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
10036 pickupexten = "";
10037 } else {
10038 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
10039 }
10040 ast_channel_unlock(chan);
10041
10042 if (p->dsp)
10044 switch (p->sig) {
10045 case SIG_FEATD:
10046 case SIG_FEATDMF:
10047 case SIG_FEATDMF_TA:
10048 case SIG_E911:
10049 case SIG_FGC_CAMAMF:
10050 case SIG_FEATB:
10051 case SIG_EMWINK:
10052 case SIG_SF_FEATD:
10053 case SIG_SF_FEATDMF:
10054 case SIG_SF_FEATB:
10055 case SIG_SFWINK:
10056 if (dahdi_wink(p, idx))
10057 goto quit;
10058 /* Fall through */
10059 case SIG_EM:
10060 case SIG_EM_E1:
10061 case SIG_SF:
10062 case SIG_FGC_CAMA:
10063 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10064 if (p->dsp)
10066 /* set digit mode appropriately */
10067 if (p->dsp) {
10068 if (NEED_MFDETECT(p))
10070 else
10072 }
10073 memset(dtmfbuf, 0, sizeof(dtmfbuf));
10074 /* Wait for the first digit only if immediate=no */
10075 if (!p->immediate)
10076 /* Wait for the first digit (up to 5 seconds). */
10077 res = ast_waitfordigit(chan, 5000);
10078 else
10079 res = 0;
10080 if (res > 0) {
10081 /* save first char */
10082 dtmfbuf[0] = res;
10083 switch (p->sig) {
10084 case SIG_FEATD:
10085 case SIG_SF_FEATD:
10086 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10087 if (res > 0)
10088 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10089 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10090 break;
10091 case SIG_FEATDMF_TA:
10092 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10093 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10094 if (dahdi_wink(p, idx)) goto quit;
10095 dtmfbuf[0] = 0;
10096 /* Wait for the first digit (up to 5 seconds). */
10097 res = ast_waitfordigit(chan, 5000);
10098 if (res <= 0) break;
10099 dtmfbuf[0] = res;
10100 /* fall through intentionally */
10101 case SIG_FEATDMF:
10102 case SIG_E911:
10103 case SIG_FGC_CAMAMF:
10104 case SIG_SF_FEATDMF:
10105 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10106 /* if international caca, do it again to get real ANO */
10107 if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
10108 {
10109 if (dahdi_wink(p, idx)) goto quit;
10110 dtmfbuf[0] = 0;
10111 /* Wait for the first digit (up to 5 seconds). */
10112 res = ast_waitfordigit(chan, 5000);
10113 if (res <= 0) break;
10114 dtmfbuf[0] = res;
10115 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10116 }
10117 if (res > 0) {
10118 /* if E911, take off hook */
10119 if (p->sig == SIG_E911)
10120 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10121 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
10122 }
10123 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10124 break;
10125 case SIG_FEATB:
10126 case SIG_SF_FEATB:
10127 res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
10128 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10129 break;
10130 case SIG_EMWINK:
10131 /* if we received a '*', we are actually receiving Feature Group D
10132 dial syntax, so use that mode; otherwise, fall through to normal
10133 mode
10134 */
10135 if (res == '*') {
10136 res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
10137 if (res > 0)
10138 res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
10139 if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
10140 break;
10141 }
10142 default:
10143 /* If we got the first digit, get the rest */
10144 len = 1;
10145 dtmfbuf[len] = '\0';
10146 while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10147 if (ast_exists_extension(chan, ast_channel_context(chan), dtmfbuf, 1, p->cid_num)) {
10148 timeout = p->matchdigit_timeout;
10149 } else {
10150 timeout = p->interdigit_timeout;
10151 }
10152 res = ast_waitfordigit(chan, timeout);
10153 if (res < 0) {
10154 ast_debug(1, "waitfordigit returned < 0...\n");
10155 ast_hangup(chan);
10156 goto quit;
10157 } else if (res) {
10158 dtmfbuf[len++] = res;
10159 dtmfbuf[len] = '\0';
10160 } else {
10161 break;
10162 }
10163 }
10164 break;
10165 }
10166 }
10167 if (res == -1) {
10168 ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
10169 ast_hangup(chan);
10170 goto quit;
10171 } else if (res < 0) {
10172 ast_debug(1, "Got hung up before digits finished\n");
10173 ast_hangup(chan);
10174 goto quit;
10175 }
10176
10177 if (p->sig == SIG_FGC_CAMA) {
10178 char anibuf[100];
10179
10180 if (ast_safe_sleep(chan,1000) == -1) {
10181 ast_hangup(chan);
10182 goto quit;
10183 }
10184 dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10186 res = my_getsigstr(chan, anibuf, "#", 10000);
10187 if ((res > 0) && (strlen(anibuf) > 2)) {
10188 if (anibuf[strlen(anibuf) - 1] == '#')
10189 anibuf[strlen(anibuf) - 1] = 0;
10190 ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
10191 }
10193 }
10194
10195 ast_copy_string(exten, dtmfbuf, sizeof(exten));
10196 if (ast_strlen_zero(exten))
10197 ast_copy_string(exten, "s", sizeof(exten));
10198 if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
10199 /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
10200 if (exten[0] == '*') {
10201 char *stringp=NULL;
10202 ast_copy_string(exten2, exten, sizeof(exten2));
10203 /* Parse out extension and callerid */
10204 stringp=exten2 +1;
10205 s1 = strsep(&stringp, "*");
10206 s2 = strsep(&stringp, "*");
10207 if (s2) {
10208 if (!ast_strlen_zero(p->cid_num))
10209 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10210 else
10211 ast_set_callerid(chan, s1, NULL, s1);
10212 ast_copy_string(exten, s2, sizeof(exten));
10213 } else
10214 ast_copy_string(exten, s1, sizeof(exten));
10215 } else if (p->sig == SIG_FEATD)
10216 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10217 }
10218 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10219 if (exten[0] == '*') {
10220 char *stringp=NULL;
10221 ast_copy_string(exten2, exten, sizeof(exten2));
10222 /* Parse out extension and callerid */
10223 stringp=exten2 +1;
10224 s1 = strsep(&stringp, "#");
10225 s2 = strsep(&stringp, "#");
10226 if (s2) {
10227 if (!ast_strlen_zero(p->cid_num))
10228 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10229 else
10230 if (*(s1 + 2))
10231 ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
10232 ast_copy_string(exten, s2 + 1, sizeof(exten));
10233 } else
10234 ast_copy_string(exten, s1 + 2, sizeof(exten));
10235 } else
10236 ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
10237 }
10238 if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
10239 if (exten[0] == '*') {
10240 char *stringp=NULL;
10241 ast_copy_string(exten2, exten, sizeof(exten2));
10242 /* Parse out extension and callerid */
10243 stringp=exten2 +1;
10244 s1 = strsep(&stringp, "#");
10245 s2 = strsep(&stringp, "#");
10246 if (s2 && (*(s2 + 1) == '0')) {
10247 if (*(s2 + 2))
10248 ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
10249 }
10250 if (s1) ast_copy_string(exten, s1, sizeof(exten));
10251 else ast_copy_string(exten, "911", sizeof(exten));
10252 } else
10253 ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
10254 }
10255 if (p->sig == SIG_FEATB) {
10256 if (exten[0] == '*') {
10257 char *stringp=NULL;
10258 ast_copy_string(exten2, exten, sizeof(exten2));
10259 /* Parse out extension and callerid */
10260 stringp=exten2 +1;
10261 s1 = strsep(&stringp, "#");
10262 ast_copy_string(exten, exten2 + 1, sizeof(exten));
10263 } else
10264 ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
10265 }
10266 if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
10267 dahdi_wink(p, idx);
10268 /* some switches require a minimum guard time between
10269 the last FGD wink and something that answers
10270 immediately. This ensures it */
10271 if (ast_safe_sleep(chan, 100)) {
10272 ast_hangup(chan);
10273 goto quit;
10274 }
10275 }
10276 dahdi_ec_enable(p);
10277 if (NEED_MFDETECT(p)) {
10278 if (p->dsp) {
10279 if (!p->hardwaredtmf)
10281 else {
10282 ast_dsp_free(p->dsp);
10283 p->dsp = NULL;
10284 }
10285 }
10286 }
10287
10288 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
10289 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10290 ast_channel_exten_set(chan, exten);
10291 if (p->dsp) ast_dsp_digitreset(p->dsp);
10292 res = ast_pbx_run(chan);
10293 if (res) {
10294 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10295 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10296 }
10297 goto quit;
10298 } else {
10299 ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, ast_channel_context(chan));
10300 sleep(2);
10301 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
10302 if (res < 0)
10303 ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
10304 else
10305 sleep(1);
10306 res = ast_streamfile(chan, "ss-noservice", ast_channel_language(chan));
10307 if (res >= 0)
10308 ast_waitstream(chan, "");
10309 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10310 ast_hangup(chan);
10311 goto quit;
10312 }
10313 break;
10314 case SIG_FXOLS:
10315 case SIG_FXOGS:
10316 case SIG_FXOKS:
10317 /* Read the first digit */
10318 timeout = p->firstdigit_timeout;
10319 /* If starting a threeway call, never timeout on the first digit so someone
10320 can use flash-hook as a "hold" feature */
10321 if (p->subs[SUB_THREEWAY].owner)
10322 timeout = INT_MAX;
10323 while (len < AST_MAX_EXTENSION-1) {
10324 int is_exten_parking = 0;
10325
10326 /* Read digit unless it's supposed to be immediate, in which case the
10327 only answer is 's' */
10328 if (p->immediate)
10329 res = 's';
10330 else
10331 res = ast_waitfordigit(chan, timeout);
10332 timeout = 0;
10333 if (res < 0) {
10334 ast_debug(1, "waitfordigit returned < 0...\n");
10335 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10336 ast_hangup(chan);
10337 goto quit;
10338 } else if (res) {
10339 ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
10340 exten[len++]=res;
10341 exten[len] = '\0';
10342 }
10343 if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
10344 tone_zone_play_tone(p->subs[idx].dfd, -1);
10345 } else {
10346 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10347 }
10349 is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
10350 }
10351 if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
10352 if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
10353 if (getforward) {
10354 /* Record this as the forwarding extension */
10355 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
10356 ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
10357 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10358 if (res)
10359 break;
10360 usleep(500000);
10361 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10362 sleep(1);
10363 memset(exten, 0, sizeof(exten));
10364 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
10365 len = 0;
10366 getforward = 0;
10367 } else {
10368 res = tone_zone_play_tone(p->subs[idx].dfd, -1);
10369 ast_channel_lock(chan);
10370 ast_channel_exten_set(chan, exten);
10371 if (!ast_strlen_zero(p->cid_num)) {
10372 if (!p->hidecallerid)
10373 ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
10374 else
10375 ast_set_callerid(chan, NULL, NULL, p->cid_num);
10376 }
10377 if (!ast_strlen_zero(p->cid_name)) {
10378 if (!p->hidecallerid)
10379 ast_set_callerid(chan, NULL, p->cid_name, NULL);
10380 }
10382 ast_channel_unlock(chan);
10383 dahdi_ec_enable(p);
10384 res = ast_pbx_run(chan);
10385 if (res) {
10386 ast_log(LOG_WARNING, "PBX exited non-zero\n");
10387 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10388 }
10389 goto quit;
10390 }
10391 } else {
10392 /* It's a match, but they just typed a digit, and there is an ambiguous match,
10393 so just set the timeout to matchdigit_timeout and wait some more */
10394 timeout = p->matchdigit_timeout;
10395 }
10396 } else if (res == 0) {
10397 ast_debug(1, "not enough digits (and no ambiguous match)...\n");
10398 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10399 dahdi_wait_event(p->subs[idx].dfd);
10400 ast_hangup(chan);
10401 goto quit;
10402 } else if (p->callwaiting && !strcmp(exten, "*70")) {
10403 ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
10404 /* Disable call waiting if enabled */
10405 p->callwaiting = 0;
10406 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10407 if (res) {
10408 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10409 ast_channel_name(chan), strerror(errno));
10410 }
10411 len = 0;
10412 ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
10413 memset(exten, 0, sizeof(exten));
10414 timeout = p->firstdigit_timeout;
10415
10416 } else if (!strcmp(exten, pickupexten)) {
10417 /* Scan all channels and see if there are any
10418 * ringing channels that have call groups
10419 * that equal this channels pickup group
10420 */
10421 if (idx == SUB_REAL) {
10422 /* Switch us from Third call to Call Wait */
10423 if (p->subs[SUB_THREEWAY].owner) {
10424 /* If you make a threeway call and the *8# a call, it should actually
10425 look like a callwait */
10429 }
10430 dahdi_ec_enable(p);
10431 if (ast_pickup_call(chan)) {
10432 ast_debug(1, "No call pickup possible...\n");
10433 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10434 dahdi_wait_event(p->subs[idx].dfd);
10435 }
10436 ast_hangup(chan);
10437 goto quit;
10438 } else {
10439 ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
10440 ast_hangup(chan);
10441 goto quit;
10442 }
10443
10444 } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
10445 ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
10446 /* Disable Caller*ID if enabled */
10447 p->hidecallerid = 1;
10452 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10453 if (res) {
10454 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10455 ast_channel_name(chan), strerror(errno));
10456 }
10457 len = 0;
10458 memset(exten, 0, sizeof(exten));
10459 timeout = p->firstdigit_timeout;
10460 } else if (p->callreturn && !strcmp(exten, "*69")) {
10461 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10462 break;
10463 } else if (!strcmp(exten, "*78")) {
10464 dahdi_dnd(p, 1);
10465 /* Do not disturb */
10466 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10467 getforward = 0;
10468 memset(exten, 0, sizeof(exten));
10469 len = 0;
10470 } else if (!strcmp(exten, "*79")) {
10471 dahdi_dnd(p, 0);
10472 /* Do not disturb */
10473 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10474 getforward = 0;
10475 memset(exten, 0, sizeof(exten));
10476 len = 0;
10477 } else if (p->cancallforward && !strcmp(exten, "*72")) {
10478 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10479 getforward = 1;
10480 memset(exten, 0, sizeof(exten));
10481 len = 0;
10482 } else if (p->cancallforward && !strcmp(exten, "*73")) {
10483 ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
10484 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10485 memset(p->call_forward, 0, sizeof(p->call_forward));
10486 getforward = 0;
10487 memset(exten, 0, sizeof(exten));
10488 len = 0;
10489 } else if ((p->transfer || p->canpark) && is_exten_parking
10490 && p->subs[SUB_THREEWAY].owner) {
10491 struct ast_bridge_channel *bridge_channel;
10492
10493 /*
10494 * This is a three way call, the main call being a real channel,
10495 * and we're parking the first call.
10496 */
10500 if (bridge_channel) {
10501 if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
10502 /*
10503 * Swap things around between the three-way and real call so we
10504 * can hear where the channel got parked.
10505 */
10506 ast_mutex_lock(&p->lock);
10507 p->owner = p->subs[SUB_THREEWAY].owner;
10510
10511 ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
10513 ao2_ref(bridge_channel, -1);
10514 goto quit;
10515 }
10516 ao2_ref(bridge_channel, -1);
10517 }
10518 break;
10519 } else if (p->hidecallerid && !strcmp(exten, "*82")) {
10520 ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
10521 /* Enable Caller*ID if enabled */
10522 p->hidecallerid = 0;
10524 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
10525 if (res) {
10526 ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
10527 ast_channel_name(chan), strerror(errno));
10528 }
10529 len = 0;
10530 memset(exten, 0, sizeof(exten));
10531 timeout = p->firstdigit_timeout;
10532 } else if (!strcmp(exten, "*0")) {
10533 struct ast_channel *nbridge =
10535 struct dahdi_pvt *pbridge = NULL;
10536 RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
10537
10538 /* set up the private struct of the bridged one, if any */
10539 if (nbridge && bridged) {
10540 pbridge = ast_channel_tech_pvt(bridged);
10541 }
10542 if (nbridge && pbridge &&
10543 (ast_channel_tech(nbridge) == &dahdi_tech) &&
10544 (ast_channel_tech(bridged) == &dahdi_tech) &&
10545 ISTRUNK(pbridge)) {
10546 int func = DAHDI_FLASH;
10547 /* Clear out the dial buffer */
10548 p->dop.dialstr[0] = '\0';
10549 /* flash hookswitch */
10550 if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
10551 ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
10552 ast_channel_name(nbridge), strerror(errno));
10553 }
10556 p->owner = p->subs[SUB_REAL].owner;
10558 ast_hangup(chan);
10559 goto quit;
10560 } else {
10561 tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
10562 dahdi_wait_event(p->subs[idx].dfd);
10563 tone_zone_play_tone(p->subs[idx].dfd, -1);
10566 p->owner = p->subs[SUB_REAL].owner;
10567 ast_hangup(chan);
10568 goto quit;
10569 }
10570 } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
10571 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
10572 && !canmatch_featurecode(pickupexten, exten)) {
10573 ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
10574 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
10575 ast_channel_context(chan));
10576 break;
10577 }
10578 if (!timeout)
10579 timeout = p->interdigit_timeout;
10581 tone_zone_play_tone(p->subs[idx].dfd, -1);
10582 }
10583 break;
10584 case SIG_FXSLS:
10585 case SIG_FXSGS:
10586 case SIG_FXSKS:
10587 /* check for SMDI messages */
10588 if (p->use_smdi && p->smdi_iface) {
10590
10591 if (smdi_msg != NULL) {
10592 ast_channel_exten_set(chan, smdi_msg->fwd_st);
10593
10594 if (smdi_msg->type == 'B')
10595 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
10596 else if (smdi_msg->type == 'N')
10597 pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
10598
10599 ast_debug(1, "Received SMDI message on %s\n", ast_channel_name(chan));
10600 } else {
10601 ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
10602 }
10603 }
10604
10605 if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
10606 number = smdi_msg->calling_st;
10607
10608 /* If we want caller id, we're in a prering state due to a polarity reversal
10609 * and we're set to use a polarity reversal to trigger the start of caller id,
10610 * grab the caller id and wait for ringing to start... */
10611 } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
10613 /* If set to use DTMF CID signalling, listen for DTMF */
10614 if (p->cid_signalling == CID_SIG_DTMF) {
10615 int k = 0;
10616 int off_ms;
10617 struct timeval start = ast_tvnow();
10618 int ms;
10619 cs = NULL;
10620 ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
10621 dahdi_setlinear(p->subs[idx].dfd, 0);
10622 /*
10623 * We are the only party interested in the Rx stream since
10624 * we have not answered yet. We don't need or even want DTMF
10625 * emulation. The DTMF digits can come so fast that emulation
10626 * can drop some of them.
10627 */
10628 ast_channel_lock(chan);
10630 ast_channel_unlock(chan);
10631 off_ms = 4000;/* This is a typical OFF time between rings. */
10632 for (;;) {
10633 struct ast_frame *f;
10634
10635 ms = ast_remaining_ms(start, off_ms);
10636 res = ast_waitfor(chan, ms);
10637 if (res <= 0) {
10638 /*
10639 * We do not need to restore the dahdi_setlinear()
10640 * or AST_FLAG_END_DTMF_ONLY flag settings since we
10641 * are hanging up the channel.
10642 */
10643 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10644 "Exiting simple switch\n");
10645 ast_hangup(chan);
10646 goto quit;
10647 }
10648 f = ast_read(chan);
10649 if (!f)
10650 break;
10651 if (f->frametype == AST_FRAME_DTMF) {
10652 if (k < ARRAY_LEN(dtmfbuf) - 1) {
10653 dtmfbuf[k++] = f->subclass.integer;
10654 }
10655 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10656 start = ast_tvnow();
10657 }
10658 ast_frfree(f);
10659 if (ast_channel_state(chan) == AST_STATE_RING ||
10661 break; /* Got ring */
10662 }
10663 ast_channel_lock(chan);
10665 ast_channel_unlock(chan);
10666 dtmfbuf[k] = '\0';
10667 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10668 /* Got cid and ring. */
10669 ast_debug(1, "CID got string '%s'\n", dtmfbuf);
10670 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10671 ast_debug(1, "CID is '%s', flags %d\n", dtmfcid, flags);
10672 /* If first byte is NULL, we have no cid */
10673 if (!ast_strlen_zero(dtmfcid))
10674 number = dtmfcid;
10675 else
10676 number = NULL;
10677 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10678 } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
10680 if (cs) {
10681 int off_ms;
10682 struct timeval start;
10683 int ms;
10684 samples = 0;
10685#if 1
10686 bump_gains(p);
10687#endif
10688 /* Take out of linear mode for Caller*ID processing */
10689 dahdi_setlinear(p->subs[idx].dfd, 0);
10690
10691 /* First we wait and listen for the Caller*ID */
10692 for (;;) {
10693 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10694 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10695 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10696 callerid_free(cs);
10697 ast_hangup(chan);
10698 goto quit;
10699 }
10700 if (i & DAHDI_IOMUX_SIGEVENT) {
10701 res = dahdi_get_event(p->subs[idx].dfd);
10702 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10703 if (res == DAHDI_EVENT_NOALARM) {
10704 p->inalarm = 0;
10705 }
10706
10707 if (p->cid_signalling == CID_SIG_V23_JP) {
10708 if (res == DAHDI_EVENT_RINGBEGIN) {
10709 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
10710 usleep(1);
10711 }
10712 } else {
10713 res = 0;
10714 break;
10715 }
10716 } else if (i & DAHDI_IOMUX_READ) {
10717 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10718 if (res < 0) {
10719 if (errno != ELAST) {
10720 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10721 callerid_free(cs);
10722 ast_hangup(chan);
10723 goto quit;
10724 }
10725 break;
10726 }
10727 samples += res;
10728
10729 if (p->cid_signalling == CID_SIG_V23_JP) {
10730 res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
10731 } else {
10732 res = callerid_feed(cs, buf, res, AST_LAW(p));
10733 }
10734 if (res < 0) {
10735 /*
10736 * The previous diagnostic message output likely
10737 * explains why it failed.
10738 */
10740 "Failed to decode CallerID on channel '%s'\n",
10741 ast_channel_name(chan));
10742 break;
10743 } else if (res)
10744 break;
10745 else if (samples > (8000 * 10))
10746 break;
10747 }
10748 }
10749 if (res == 1) {
10750 callerid_get(cs, &name, &number, &flags);
10751 ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
10752 }
10753
10754 if (p->cid_signalling == CID_SIG_V23_JP) {
10755 res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
10756 usleep(1);
10757 }
10758
10759 /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
10760 start = ast_tvnow();
10761 off_ms = 4000;/* This is a typical OFF time between rings. */
10762 for (;;) {
10763 struct ast_frame *f;
10764
10765 ms = ast_remaining_ms(start, off_ms);
10766 res = ast_waitfor(chan, ms);
10767 if (res <= 0) {
10768 ast_log(LOG_WARNING, "CID timed out waiting for ring. "
10769 "Exiting simple switch\n");
10770 ast_hangup(chan);
10771 goto quit;
10772 }
10773 if (!(f = ast_read(chan))) {
10774 ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
10775 ast_hangup(chan);
10776 goto quit;
10777 }
10778 ast_frfree(f);
10779 if (ast_channel_state(chan) == AST_STATE_RING ||
10781 break; /* Got ring */
10782 }
10783
10784 /* We must have a ring by now, so, if configured, lets try to listen for
10785 * distinctive ringing */
10787 len = 0;
10788 distMatches = 0;
10789 /* Clear the current ring data array so we don't have old data in it. */
10790 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10791 curRingData[receivedRingT] = 0;
10792 receivedRingT = 0;
10793 counter = 0;
10794 counter1 = 0;
10795 /* Check to see if context is what it should be, if not set to be. */
10796 if (strcmp(p->context,p->defcontext) != 0) {
10797 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10799 }
10800
10801 for (;;) {
10802 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10803 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10804 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10805 callerid_free(cs);
10806 ast_hangup(chan);
10807 goto quit;
10808 }
10809 if (i & DAHDI_IOMUX_SIGEVENT) {
10810 res = dahdi_get_event(p->subs[idx].dfd);
10811 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10812 if (res == DAHDI_EVENT_NOALARM) {
10813 p->inalarm = 0;
10814 }
10815 res = 0;
10816 /* Let us detect distinctive ring */
10817
10818 curRingData[receivedRingT] = p->ringt;
10819
10820 if (p->ringt < p->ringt_base/2)
10821 break;
10822 /* Increment the ringT counter so we can match it against
10823 values in chan_dahdi.conf for distinctive ring */
10824 if (++receivedRingT == ARRAY_LEN(curRingData))
10825 break;
10826 } else if (i & DAHDI_IOMUX_READ) {
10827 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10828 if (res < 0) {
10829 if (errno != ELAST) {
10830 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
10831 callerid_free(cs);
10832 ast_hangup(chan);
10833 goto quit;
10834 }
10835 break;
10836 }
10837 if (p->ringt > 0) {
10838 if (!(--p->ringt)) {
10839 res = -1;
10840 break;
10841 }
10842 }
10843 }
10844 }
10845 /* this only shows up if you have n of the dring patterns filled in */
10846 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
10847 for (counter = 0; counter < 3; counter++) {
10848 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
10849 channel */
10850 distMatches = 0;
10851 for (counter1 = 0; counter1 < 3; counter1++) {
10852 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
10853 if (p->drings.ringnum[counter].ring[counter1] == -1) {
10854 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
10855 curRingData[counter1]);
10856 distMatches++;
10857 } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
10858 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
10859 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
10860 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
10861 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
10862 distMatches++;
10863 }
10864 }
10865
10866 if (distMatches == 3) {
10867 /* The ring matches, set the context to whatever is for distinctive ring.. */
10868 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
10870 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
10871 break;
10872 }
10873 }
10874 }
10875 /* Restore linear mode (if appropriate) for Caller*ID processing */
10876 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10877#if 1
10878 restore_gains(p);
10879#endif
10880 } else
10881 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
10882 } else {
10883 ast_log(LOG_WARNING, "Channel %s in prering "
10884 "state, but I have nothing to do. "
10885 "Terminating simple switch, should be "
10886 "restarted by the actual ring.\n",
10887 ast_channel_name(chan));
10888 ast_hangup(chan);
10889 goto quit;
10890 }
10891 } else if (p->use_callerid && p->cid_start == CID_START_RING) {
10892 if (p->cid_signalling == CID_SIG_DTMF) {
10893 int k = 0;
10894 int off_ms;
10895 struct timeval start;
10896 int ms;
10897 cs = NULL;
10898 dahdi_setlinear(p->subs[idx].dfd, 0);
10899 off_ms = 2000;
10900 start = ast_tvnow();
10901 for (;;) {
10902 struct ast_frame *f;
10903
10904 ms = ast_remaining_ms(start, off_ms);
10905 res = ast_waitfor(chan, ms);
10906 if (res <= 0) {
10907 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
10908 "Exiting simple switch\n");
10909 ast_hangup(chan);
10910 goto quit;
10911 }
10912 f = ast_read(chan);
10913 if (!f) {
10914 /* Hangup received waiting for DTMFCID. Exiting simple switch. */
10915 ast_hangup(chan);
10916 goto quit;
10917 }
10918 if (f->frametype == AST_FRAME_DTMF) {
10919 dtmfbuf[k++] = f->subclass.integer;
10920 ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
10921 start = ast_tvnow();
10922 }
10923 ast_frfree(f);
10924
10925 if (p->ringt_base == p->ringt)
10926 break;
10927 }
10928 dtmfbuf[k] = '\0';
10929 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
10930 /* Got cid and ring. */
10931 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
10932 ast_debug(1, "CID is '%s', flags %d\n",
10933 dtmfcid, flags);
10934 /* If first byte is NULL, we have no cid */
10935 if (!ast_strlen_zero(dtmfcid))
10936 number = dtmfcid;
10937 else
10938 number = NULL;
10939 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
10940 } else {
10941 /* FSK Bell202 callerID */
10943 if (cs) {
10944#if 1
10945 bump_gains(p);
10946#endif
10947 samples = 0;
10948 len = 0;
10949 distMatches = 0;
10950 /* Clear the current ring data array so we don't have old data in it. */
10951 for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
10952 curRingData[receivedRingT] = 0;
10953 receivedRingT = 0;
10954 counter = 0;
10955 counter1 = 0;
10956 /* Check to see if context is what it should be, if not set to be. */
10957 if (strcmp(p->context,p->defcontext) != 0) {
10958 ast_copy_string(p->context, p->defcontext, sizeof(p->context));
10960 }
10961
10962 /* Take out of linear mode for Caller*ID processing */
10963 dahdi_setlinear(p->subs[idx].dfd, 0);
10964 for (;;) {
10965 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
10966 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
10967 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
10968 callerid_free(cs);
10969 ast_hangup(chan);
10970 goto quit;
10971 }
10972 if (i & DAHDI_IOMUX_SIGEVENT) {
10973 res = dahdi_get_event(p->subs[idx].dfd);
10974 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
10975 if (res == DAHDI_EVENT_NOALARM) {
10976 p->inalarm = 0;
10977 }
10978 /* If we get a PR event, they hung up while processing calerid */
10979 if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
10980 ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
10982 callerid_free(cs);
10983 ast_hangup(chan);
10984 goto quit;
10985 }
10986 res = 0;
10987 /* Let us detect callerid when the telco uses distinctive ring */
10988
10989 curRingData[receivedRingT] = p->ringt;
10990
10991 if (p->ringt < p->ringt_base/2)
10992 break;
10993 /* Increment the ringT counter so we can match it against
10994 values in chan_dahdi.conf for distinctive ring */
10995 if (++receivedRingT == ARRAY_LEN(curRingData))
10996 break;
10997 } else if (i & DAHDI_IOMUX_READ) {
10998 res = read(p->subs[idx].dfd, buf, sizeof(buf));
10999 if (res < 0) {
11000 if (errno != ELAST) {
11001 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11002 callerid_free(cs);
11003 ast_hangup(chan);
11004 goto quit;
11005 }
11006 break;
11007 }
11008 if (p->ringt > 0) {
11009 if (!(--p->ringt)) {
11010 res = -1;
11011 break;
11012 }
11013 }
11014 samples += res;
11015 res = callerid_feed(cs, buf, res, AST_LAW(p));
11016 if (res < 0) {
11017 /*
11018 * The previous diagnostic message output likely
11019 * explains why it failed.
11020 */
11022 "Failed to decode CallerID on channel '%s'\n",
11023 ast_channel_name(chan));
11024 break;
11025 } else if (res)
11026 break;
11027 else if (samples > (8000 * 10))
11028 break;
11029 }
11030 }
11031 if (res == 1) {
11032 callerid_get(cs, &name, &number, &flags);
11033 ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
11034 }
11035 if (distinctiveringaftercid == 1) {
11036 /* Clear the current ring data array so we don't have old data in it. */
11037 for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
11038 curRingData[receivedRingT] = 0;
11039 }
11040 receivedRingT = 0;
11041 ast_verb(3, "Detecting post-CID distinctive ring\n");
11042 for (;;) {
11043 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11044 if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
11045 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11046 callerid_free(cs);
11047 ast_hangup(chan);
11048 goto quit;
11049 }
11050 if (i & DAHDI_IOMUX_SIGEVENT) {
11051 res = dahdi_get_event(p->subs[idx].dfd);
11052 ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
11053 if (res == DAHDI_EVENT_NOALARM) {
11054 p->inalarm = 0;
11055 }
11056 res = 0;
11057 /* Let us detect callerid when the telco uses distinctive ring */
11058
11059 curRingData[receivedRingT] = p->ringt;
11060
11061 if (p->ringt < p->ringt_base/2)
11062 break;
11063 /* Increment the ringT counter so we can match it against
11064 values in chan_dahdi.conf for distinctive ring */
11065 if (++receivedRingT == ARRAY_LEN(curRingData))
11066 break;
11067 } else if (i & DAHDI_IOMUX_READ) {
11068 res = read(p->subs[idx].dfd, buf, sizeof(buf));
11069 if (res < 0) {
11070 if (errno != ELAST) {
11071 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11072 callerid_free(cs);
11073 ast_hangup(chan);
11074 goto quit;
11075 }
11076 break;
11077 }
11078 if (p->ringt > 0) {
11079 if (!(--p->ringt)) {
11080 res = -1;
11081 break;
11082 }
11083 }
11084 }
11085 }
11086 }
11088 /* this only shows up if you have n of the dring patterns filled in */
11089 ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
11090
11091 for (counter = 0; counter < 3; counter++) {
11092 /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
11093 channel */
11094 /* this only shows up if you have n of the dring patterns filled in */
11095 ast_verb(3, "Checking %d,%d,%d\n",
11096 p->drings.ringnum[counter].ring[0],
11097 p->drings.ringnum[counter].ring[1],
11098 p->drings.ringnum[counter].ring[2]);
11099 distMatches = 0;
11100 for (counter1 = 0; counter1 < 3; counter1++) {
11101 ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
11102 if (p->drings.ringnum[counter].ring[counter1] == -1) {
11103 ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
11104 curRingData[counter1]);
11105 distMatches++;
11106 }
11107 else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
11108 curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
11109 ast_verb(3, "Ring pattern matched in range: %d to %d\n",
11110 (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
11111 (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
11112 distMatches++;
11113 }
11114 }
11115 if (distMatches == 3) {
11116 /* The ring matches, set the context to whatever is for distinctive ring.. */
11117 ast_copy_string(p->context, S_OR(p->drings.ringContext[counter].contextData, p->defcontext), sizeof(p->context));
11119 ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
11120 break;
11121 }
11122 }
11123 }
11124 /* Restore linear mode (if appropriate) for Caller*ID processing */
11125 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
11126#if 1
11127 restore_gains(p);
11128#endif
11129 if (res < 0) {
11130 ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", ast_channel_name(chan));
11131 }
11132 } else
11133 ast_log(LOG_WARNING, "Unable to get caller ID space\n");
11134 }
11135 } else
11136 cs = NULL;
11137
11138 if (number)
11141
11142 ao2_cleanup(smdi_msg);
11143
11144 if (cs)
11145 callerid_free(cs);
11146
11147 my_handle_notify_message(chan, p, flags, -1);
11148
11149 ast_channel_lock(chan);
11151 ast_channel_rings_set(chan, 1);
11152 ast_channel_unlock(chan);
11153 p->ringt = p->ringt_base;
11154 res = ast_pbx_run(chan);
11155 if (res) {
11156 ast_hangup(chan);
11157 ast_log(LOG_WARNING, "PBX exited non-zero\n");
11158 }
11159 goto quit;
11160 default:
11161 ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
11162 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11163 if (res < 0)
11164 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11165 }
11166 res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
11167 if (res < 0)
11168 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
11169 ast_hangup(chan);
11170quit:
11175 return NULL;
11176}
11177
11180 unsigned char buf[READ_SIZE];
11181 size_t len;
11182};
11183
11184static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
11185{
11186 int x;
11187 int sum = 0;
11188
11189 if (!len)
11190 return 0;
11191
11192 for (x = 0; x < len; x++)
11193 sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
11194
11195 return sum / len;
11196}
11197
11198static void *mwi_thread(void *data)
11199{
11200 struct mwi_thread_data *mtd = data;
11201 struct callerid_state *cs;
11202 pthread_t threadid;
11203 int samples = 0;
11204 char *name, *number;
11205 int flags;
11206 int i, res;
11207 unsigned int spill_done = 0;
11208 int spill_result = -1;
11209
11210 if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
11211 goto quit_no_clean;
11212 }
11213
11214 callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
11215
11216 bump_gains(mtd->pvt);
11217
11218 for (;;) {
11219 i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
11220 if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
11221 ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
11222 goto quit;
11223 }
11224
11225 if (i & DAHDI_IOMUX_SIGEVENT) {
11226 struct ast_channel *chan;
11227 ast_callid callid = 0;
11228 int callid_created;
11229
11230 /* If we get an event, screen out events that we do not act on.
11231 * Otherwise, cancel and go to the simple switch to let it deal with it.
11232 */
11233 res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
11234
11235 switch (res) {
11236 case DAHDI_EVENT_NEONMWI_ACTIVE:
11237 case DAHDI_EVENT_NEONMWI_INACTIVE:
11238 case DAHDI_EVENT_NONE:
11239 case DAHDI_EVENT_BITSCHANGED:
11240 break;
11241 case DAHDI_EVENT_NOALARM:
11242 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11243 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11244
11245 analog_p->inalarm = 0;
11246 }
11247 mtd->pvt->inalarm = 0;
11249 break;
11250 case DAHDI_EVENT_ALARM:
11251 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11252 struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
11253
11254 analog_p->inalarm = 1;
11255 }
11256 mtd->pvt->inalarm = 1;
11257 res = get_alarms(mtd->pvt);
11258 handle_alarms(mtd->pvt, res);
11259 break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
11260 default:
11261 callid_created = ast_callid_threadstorage_auto(&callid);
11262 ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
11263 callerid_free(cs);
11264
11265 restore_gains(mtd->pvt);
11266 mtd->pvt->ringt = mtd->pvt->ringt_base;
11267
11268 if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid))) {
11269 int result;
11270
11271 if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
11273 } else {
11275 }
11276 if (result) {
11277 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
11278 res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11279 if (res < 0)
11280 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
11281 ast_hangup(chan);
11282 }
11283 } else {
11284 ast_log(LOG_WARNING, "Could not create channel to handle call\n");
11285 }
11286
11287 ast_callid_threadstorage_auto_clean(callid, callid_created);
11288 goto quit_no_clean;
11289 }
11290 } else if (i & DAHDI_IOMUX_READ) {
11291 if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
11292 if (errno != ELAST) {
11293 ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
11294 goto quit;
11295 }
11296 break;
11297 }
11298 samples += res;
11299 if (!spill_done) {
11300 if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
11301 /*
11302 * The previous diagnostic message output likely
11303 * explains why it failed.
11304 */
11305 ast_log(LOG_WARNING, "Failed to decode CallerID\n");
11306 break;
11307 } else if (spill_result) {
11308 spill_done = 1;
11309 }
11310 } else {
11311 /* keep reading data until the energy level drops below the threshold
11312 so we don't get another 'trigger' on the remaining carrier signal
11313 */
11314 if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
11315 break;
11316 }
11317 if (samples > (8000 * 4)) /*Termination case - time to give up*/
11318 break;
11319 }
11320 }
11321
11322 if (spill_result == 1) {
11323 callerid_get(cs, &name, &number, &flags);
11324 if (flags & CID_MSGWAITING) {
11325 ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
11326 notify_message(mtd->pvt->mailbox, 1);
11327 } else if (flags & CID_NOMSGWAITING) {
11328 ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
11329 notify_message(mtd->pvt->mailbox, 0);
11330 } else {
11331 ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
11332 }
11333 }
11334
11335
11336quit:
11337 callerid_free(cs);
11338
11339 restore_gains(mtd->pvt);
11340
11341quit_no_clean:
11342 mtd->pvt->mwimonitoractive = 0;
11343 ast_free(mtd);
11344
11345 return NULL;
11346}
11347
11348/*
11349* The following three functions (mwi_send_init, mwi_send_process_buffer,
11350* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
11351* that are sent out via FXS port on voicemail state change. The execution of
11352* the mwi send is state driven and can either generate a ring pulse prior to
11353* sending the fsk spill or simply send an fsk spill.
11354*/
11355static int mwi_send_init(struct dahdi_pvt * pvt)
11356{
11357 int x;
11358
11359#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11360 /* Determine how this spill is to be sent */
11361 if (pvt->mwisend_rpas) {
11363 pvt->mwisendactive = 1;
11364 } else if (pvt->mwisend_fsk) {
11366 pvt->mwisendactive = 1;
11367 } else {
11368 pvt->mwisendactive = 0;
11369 return 0;
11370 }
11371#else
11372 if (mwisend_rpas) {
11374 } else {
11376 }
11377 pvt->mwisendactive = 1;
11378#endif
11379
11380 if (pvt->cidspill) {
11381 ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n");
11382 ast_free(pvt->cidspill);
11383 pvt->cidspill = NULL;
11384 pvt->cidpos = 0;
11385 pvt->cidlen = 0;
11386 }
11388 if (!pvt->cidspill) {
11389 pvt->mwisendactive = 0;
11390 return -1;
11391 }
11392 x = DAHDI_FLUSH_BOTH;
11393 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
11394 x = 3000;
11395 ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
11396#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11397 if (pvt->mwisend_fsk) {
11398#endif
11400 CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
11401 pvt->cidpos = 0;
11402#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11403 }
11404#endif
11405 return 0;
11406}
11407
11408static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
11409{
11410 struct timeval now;
11411 int res;
11412
11413 /* sanity check to catch if this had been interrupted previously
11414 * i.e. state says there is more to do but there is no spill allocated
11415 */
11416 if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
11418 } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
11419 /* Normal processing -- Perform mwi send action */
11420 switch ( pvt->mwisend_data.mwisend_current) {
11421 case MWI_SEND_SA:
11422 /* Send the Ring Pulse Signal Alert */
11423 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
11424 if (res) {
11425 ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
11426 goto quit;
11427 }
11428 res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
11430 break;
11431 case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */
11432 break;
11433 case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/
11434#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11435 if (pvt->mwisend_fsk) {
11436#endif
11437 gettimeofday(&now, NULL);
11438 if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
11440 }
11441#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
11442 } else { /* support for mwisendtype=nofsk */
11444 }
11445#endif
11446 break;
11447 case MWI_SEND_SPILL:
11448 /* We read some number of bytes. Write an equal amount of data */
11449 if (0 < num_read) {
11450 if (num_read > pvt->cidlen - pvt->cidpos) {
11451 num_read = pvt->cidlen - pvt->cidpos;
11452 }
11453 res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
11454 if (res > 0) {
11455 pvt->cidpos += res;
11456 if (pvt->cidpos >= pvt->cidlen) {
11458 }
11459 } else {
11460 ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno));
11461 goto quit;
11462 }
11463 }
11464 break;
11465 case MWI_SEND_CLEANUP:
11466 /* For now, do nothing */
11468 break;
11469 default:
11470 /* Should not get here, punt*/
11471 goto quit;
11472 }
11473 }
11474
11476 if (pvt->cidspill) {
11477 ast_free(pvt->cidspill);
11478 pvt->cidspill = NULL;
11479 pvt->cidpos = 0;
11480 pvt->cidlen = 0;
11481 }
11482 pvt->mwisendactive = 0;
11483 }
11484 return 0;
11485quit:
11486 if (pvt->cidspill) {
11487 ast_free(pvt->cidspill);
11488 pvt->cidspill = NULL;
11489 pvt->cidpos = 0;
11490 pvt->cidlen = 0;
11491 }
11492 pvt->mwisendactive = 0;
11493 return -1;
11494}
11495
11496static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
11497{
11498 int handled = 0;
11499
11501 switch (event) {
11502 case DAHDI_EVENT_RINGEROFF:
11504 handled = 1;
11505
11506 if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
11507 ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
11508 ast_free(pvt->cidspill);
11509 pvt->cidspill = NULL;
11511 pvt->mwisendactive = 0;
11512 } else {
11514 gettimeofday(&pvt->mwisend_data.pause, NULL);
11515 }
11516 }
11517 break;
11518 /* Going off hook, I need to punt this spill */
11519 case DAHDI_EVENT_RINGOFFHOOK:
11520 if (pvt->cidspill) {
11521 ast_free(pvt->cidspill);
11522 pvt->cidspill = NULL;
11523 pvt->cidpos = 0;
11524 pvt->cidlen = 0;
11525 }
11527 pvt->mwisendactive = 0;
11528 break;
11529 case DAHDI_EVENT_RINGERON:
11530 case DAHDI_EVENT_HOOKCOMPLETE:
11531 break;
11532 default:
11533 break;
11534 }
11535 }
11536 return handled;
11537}
11538
11539/* destroy a range DAHDI channels, identified by their number */
11540static void dahdi_destroy_channel_range(int start, int end)
11541{
11542 struct dahdi_pvt *cur;
11543 struct dahdi_pvt *next;
11544 int destroyed_first = 0;
11545 int destroyed_last = 0;
11546
11548 ast_debug(1, "range: %d-%d\n", start, end);
11549 for (cur = iflist; cur; cur = next) {
11550 next = cur->next;
11551 if (cur->channel >= start && cur->channel <= end) {
11552 int x = DAHDI_FLASH;
11553
11554 if (cur->channel > destroyed_last) {
11555 destroyed_last = cur->channel;
11556 }
11557 if (destroyed_first < 1 || cur->channel < destroyed_first) {
11558 destroyed_first = cur->channel;
11559 }
11560 ast_debug(3, "Destroying %d\n", cur->channel);
11561 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
11562 ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11563
11564 destroy_channel(cur, 1);
11566 }
11567 }
11569 if (destroyed_first > start || destroyed_last < end) {
11570 ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
11571 start, end, destroyed_first, destroyed_last);
11572 }
11573}
11574
11575#ifdef HAVE_OPENR2
11576static void dahdi_r2_destroy_nodev(void)
11577{
11578 struct r2link_entry *cur;
11579 AST_LIST_LOCK(&nodev_r2links);
11580 AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
11581 int i;
11582 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
11583 ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
11584 for (i = 0; i < r2->numchans; i++) {
11585 int channel;
11586 struct dahdi_pvt *pvt = r2->pvts[i];
11587 if (!pvt) {
11588 continue;
11589 }
11590 channel = pvt->channel;
11591 ast_debug(3, "About to destroy B-channel %d.\n", channel);
11593 }
11594 ast_debug(3, "Destroying R2 link\n");
11595 AST_LIST_REMOVE(&nodev_r2links, cur, list);
11596 if (r2->r2master != AST_PTHREADT_NULL) {
11597 pthread_cancel(r2->r2master);
11598 pthread_join(r2->r2master, NULL);
11599 r2->r2master = AST_PTHREADT_NULL;
11600 openr2_context_delete(r2->protocol_context);
11601 }
11602 ast_free(cur);
11603 }
11605 AST_LIST_UNLOCK(&nodev_r2links);
11606}
11607#endif
11608
11609static int setup_dahdi(int reload);
11610static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
11611
11612/*!
11613 * \internal
11614 * \brief create a range of new DAHDI channels
11615 *
11616 * \param start first channel in the range
11617 * \param end last channel in the range
11618 *
11619 * \retval RESULT_SUCCESS on success.
11620 * \retval RESULT_FAILURE on error.
11621 */
11622static int dahdi_create_channel_range(int start, int end)
11623{
11624 struct dahdi_pvt *cur;
11625 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
11626 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
11628 int ret = RESULT_FAILURE; /* be pessimistic */
11629
11630 ast_debug(1, "channel range caps: %d - %d\n", start, end);
11632 for (cur = iflist; cur; cur = cur->next) {
11633 if (cur->channel >= start && cur->channel <= end) {
11635 "channel range %d-%d is occupied\n",
11636 start, end);
11637 goto out;
11638 }
11639 }
11640#ifdef HAVE_PRI
11641 {
11642 int i, x;
11643 for (x = 0; x < NUM_SPANS; x++) {
11644 struct dahdi_pri *pri = pris + x;
11645
11646 if (!pris[x].pri.pvts[0]) {
11647 break;
11648 }
11649 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
11650 int channo = pri->dchannels[i];
11651
11652 if (!channo) {
11653 break;
11654 }
11655 if (!pri->pri.fds[i]) {
11656 break;
11657 }
11658 if (channo >= start && channo <= end) {
11660 "channel range %d-%d is occupied by span %d\n",
11661 start, end, x + 1);
11662 goto out;
11663 }
11664 }
11665 }
11666 }
11667#endif
11668 if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
11669 !conf.chan.cc_params) {
11670 goto out;
11671 }
11672 default_conf.wanted_channels_start = start;
11673 base_conf.wanted_channels_start = start;
11674 conf.wanted_channels_start = start;
11675 default_conf.wanted_channels_end = end;
11676 base_conf.wanted_channels_end = end;
11677 conf.wanted_channels_end = end;
11678 if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
11679 ret = RESULT_SUCCESS;
11680 }
11681out:
11684 ast_cc_config_params_destroy(conf.chan.cc_params);
11686 return ret;
11687}
11688
11689
11690static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
11691{
11692 int res;
11693 pthread_t threadid;
11694 struct ast_channel *chan;
11695 ast_callid callid = 0;
11696 int callid_created;
11697
11698 /* Handle an event on a given channel for the monitor thread. */
11699
11700 switch (event) {
11701 case DAHDI_EVENT_NONE:
11702 case DAHDI_EVENT_BITSCHANGED:
11703 break;
11704 case DAHDI_EVENT_WINKFLASH:
11705 case DAHDI_EVENT_RINGOFFHOOK:
11706 if (i->inalarm) break;
11707 if (i->radio) break;
11708 /* Got a ring/answer. What kind of channel are we? */
11709 switch (i->sig) {
11710 case SIG_FXOLS:
11711 case SIG_FXOGS:
11712 case SIG_FXOKS:
11713 res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11714 if (res && (errno == EBUSY)) {
11715 break;
11716 }
11717
11718 callid_created = ast_callid_threadstorage_auto(&callid);
11719
11720 /* Cancel VMWI spill */
11721 ast_free(i->cidspill);
11722 i->cidspill = NULL;
11724
11725 if (i->immediate) {
11726 dahdi_ec_enable(i);
11727 /* The channel is immediately up. Start right away */
11728 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
11729 chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, NULL, callid);
11730 if (!chan) {
11731 ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
11732 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11733 if (res < 0)
11734 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11735 }
11736 } else {
11737 /* Check for callerid, digits, etc */
11738 chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, NULL, callid);
11739 if (chan) {
11740 if (has_voicemail(i))
11741 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
11742 else
11743 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
11744 if (res < 0)
11745 ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
11746 if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11747 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11748 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11749 if (res < 0)
11750 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11751 ast_hangup(chan);
11752 }
11753 } else
11754 ast_log(LOG_WARNING, "Unable to create channel\n");
11755 }
11756
11758 break;
11759 case SIG_FXSLS:
11760 case SIG_FXSGS:
11761 case SIG_FXSKS:
11762 i->ringt = i->ringt_base;
11763 /* Fall through */
11764 case SIG_EMWINK:
11765 case SIG_FEATD:
11766 case SIG_FEATDMF:
11767 case SIG_FEATDMF_TA:
11768 case SIG_E911:
11769 case SIG_FGC_CAMA:
11770 case SIG_FGC_CAMAMF:
11771 case SIG_FEATB:
11772 case SIG_EM:
11773 case SIG_EM_E1:
11774 case SIG_SFWINK:
11775 case SIG_SF_FEATD:
11776 case SIG_SF_FEATDMF:
11777 case SIG_SF_FEATB:
11778 case SIG_SF:
11779 /* Check for callerid, digits, etc */
11780 callid_created = ast_callid_threadstorage_auto(&callid);
11781 if (i->cid_start == CID_START_POLARITY_IN) {
11782 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11783 } else {
11784 chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, callid);
11785 }
11786
11787 if (!chan) {
11788 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11789 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11790 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11791 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11792 if (res < 0) {
11793 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11794 }
11795 ast_hangup(chan);
11796 }
11797
11799 break;
11800 default:
11801 ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11802 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
11803 if (res < 0)
11804 ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
11805 return NULL;
11806 }
11807 break;
11808 case DAHDI_EVENT_NOALARM:
11809 switch (i->sig) {
11810#if defined(HAVE_PRI)
11812 ast_mutex_lock(&i->lock);
11815 break;
11816#endif /* defined(HAVE_PRI) */
11817#if defined(HAVE_SS7)
11818 case SIG_SS7:
11820 break;
11821#endif /* defined(HAVE_SS7) */
11822 default:
11823 i->inalarm = 0;
11824 break;
11825 }
11827 break;
11828 case DAHDI_EVENT_ALARM:
11829 switch (i->sig) {
11830#if defined(HAVE_PRI)
11832 ast_mutex_lock(&i->lock);
11835 break;
11836#endif /* defined(HAVE_PRI) */
11837#if defined(HAVE_SS7)
11838 case SIG_SS7:
11840 break;
11841#endif /* defined(HAVE_SS7) */
11842 default:
11843 i->inalarm = 1;
11844 break;
11845 }
11846 res = get_alarms(i);
11847 handle_alarms(i, res);
11848 /* fall thru intentionally */
11849 case DAHDI_EVENT_ONHOOK:
11850 if (i->radio)
11851 break;
11852 /* Back on hook. Hang up. */
11853 switch (i->sig) {
11854 case SIG_FXOLS:
11855 case SIG_FXOGS:
11856 case SIG_FEATD:
11857 case SIG_FEATDMF:
11858 case SIG_FEATDMF_TA:
11859 case SIG_E911:
11860 case SIG_FGC_CAMA:
11861 case SIG_FGC_CAMAMF:
11862 case SIG_FEATB:
11863 case SIG_EM:
11864 case SIG_EM_E1:
11865 case SIG_EMWINK:
11866 case SIG_SF_FEATD:
11867 case SIG_SF_FEATDMF:
11868 case SIG_SF_FEATB:
11869 case SIG_SF:
11870 case SIG_SFWINK:
11871 case SIG_FXSLS:
11872 case SIG_FXSGS:
11873 case SIG_FXSKS:
11874 case SIG_FXOKS:
11876 /* Diddle the battery for the zhone */
11877#ifdef ZHONE_HACK
11878 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
11879 usleep(1);
11880#endif
11881 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11882 dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
11883 break;
11884 case SIG_SS7:
11887 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11888 break;
11889 default:
11890 ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
11891 res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
11892 return NULL;
11893 }
11894 break;
11895 case DAHDI_EVENT_POLARITY:
11896 switch (i->sig) {
11897 case SIG_FXSLS:
11898 case SIG_FXSKS:
11899 case SIG_FXSGS:
11900 /* We have already got a PR before the channel was
11901 created, but it wasn't handled. We need polarity
11902 to be REV for remote hangup detection to work.
11903 At least in Spain */
11904 callid_created = ast_callid_threadstorage_auto(&callid);
11909 ast_verb(2, "Starting post polarity "
11910 "CID detection on channel %d\n",
11911 i->channel);
11912 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
11913 if (!chan) {
11914 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
11915 } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
11916 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
11917 ast_hangup(chan);
11918 }
11919 }
11921 break;
11922 default:
11923 ast_log(LOG_WARNING, "handle_init_event detected "
11924 "polarity reversal on non-FXO (SIG_FXS) "
11925 "interface %d\n", i->channel);
11926 }
11927 break;
11928 case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
11930 "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
11931 i->channel);
11932 return i;
11933 case DAHDI_EVENT_NEONMWI_ACTIVE:
11934 if (i->mwimonitor_neon) {
11935 notify_message(i->mailbox, 1);
11936 ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
11937 }
11938 break;
11939 case DAHDI_EVENT_NEONMWI_INACTIVE:
11940 if (i->mwimonitor_neon) {
11941 notify_message(i->mailbox, 0);
11942 ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
11943 }
11944 break;
11945 }
11946 return NULL;
11947}
11948
11949static void monitor_pfds_clean(void *arg) {
11950 struct pollfd **pfds = arg;
11951 ast_free(*pfds);
11952}
11953
11954static void *do_monitor(void *data)
11955{
11956 int count, res, res2, spoint, pollres=0;
11957 struct dahdi_pvt *i;
11958 struct dahdi_pvt *last = NULL;
11959 struct dahdi_pvt *doomed;
11960 time_t thispass = 0, lastpass = 0;
11961 int found;
11962 char buf[1024];
11963 struct pollfd *pfds=NULL;
11964 int lastalloc = -1;
11965 /* This thread monitors all the frame relay interfaces which are not yet in use
11966 (and thus do not have a separate thread) indefinitely */
11967 /* From here on out, we die whenever asked */
11968#if 0
11969 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
11970 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
11971 return NULL;
11972 }
11973 ast_debug(1, "Monitor starting...\n");
11974#endif
11975 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11976
11977 pthread_cleanup_push(monitor_pfds_clean, &pfds);
11978 for (;;) {
11979 /* Lock the interface list */
11981 if (!pfds || (lastalloc != ifcount)) {
11982 if (pfds) {
11983 ast_free(pfds);
11984 pfds = NULL;
11985 }
11986 if (ifcount) {
11987 if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
11989 return NULL;
11990 }
11991 }
11992 lastalloc = ifcount;
11993 }
11994 /* Build the stuff we're going to poll on, that is the socket of every
11995 dahdi_pvt that does not have an associated owner channel */
11996 count = 0;
11997 for (i = iflist; i; i = i->next) {
11998 ast_mutex_lock(&i->lock);
11999 if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
12000 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12001 struct analog_pvt *p = i->sig_pvt;
12002
12003 if (!p) {
12004 ast_log(LOG_ERROR, "No sig_pvt?\n");
12005 } else if (!p->owner && !p->subs[SUB_REAL].owner) {
12006 /* This needs to be watched, as it lacks an owner */
12007 pfds[count].fd = i->subs[SUB_REAL].dfd;
12008 pfds[count].events = POLLPRI;
12009 pfds[count].revents = 0;
12010 /* Message waiting or r2 channels also get watched for reading */
12011 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12012 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12013 pfds[count].events |= POLLIN;
12014 }
12015 count++;
12016 }
12017 } else {
12018 if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
12019 /* This needs to be watched, as it lacks an owner */
12020 pfds[count].fd = i->subs[SUB_REAL].dfd;
12021 pfds[count].events = POLLPRI;
12022 pfds[count].revents = 0;
12023 /* If we are monitoring for VMWI or sending CID, we need to
12024 read from the channel as well */
12025 if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
12026 (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
12027 pfds[count].events |= POLLIN;
12028 }
12029 count++;
12030 }
12031 }
12032 }
12034 }
12035 /* Okay, now that we know what to do, release the interface lock */
12037
12038 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
12039 pthread_testcancel();
12040 /* Wait at least a second for something to happen */
12041 res = poll(pfds, count, 1000);
12042 pthread_testcancel();
12043 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
12044
12045 /* Okay, poll has finished. Let's see what happened. */
12046 if (res < 0) {
12047 if ((errno != EAGAIN) && (errno != EINTR))
12048 ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
12049 continue;
12050 }
12051 /* Alright, lock the interface list again, and let's look and see what has
12052 happened */
12054 found = 0;
12055 spoint = 0;
12056 lastpass = thispass;
12057 thispass = time(NULL);
12058 doomed = NULL;
12059 for (i = iflist;; i = i->next) {
12060 if (doomed) {
12062 doomed = NULL;
12063 }
12064 if (!i) {
12065 break;
12066 }
12067
12068 if (thispass != lastpass) {
12069 if (!found && ((i == last) || ((i == iflist) && !last))) {
12070 last = i;
12071 if (last) {
12072 struct analog_pvt *analog_p = last->sig_pvt;
12073 /* Only allow MWI to be initiated on a quiescent fxs port */
12074 if (analog_p
12075 && !last->mwisendactive
12076 && (last->sig & __DAHDI_SIG_FXO)
12077 && !analog_p->fxsoffhookstate
12078 && !last->owner
12079 && (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
12080 && !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
12081 && (thispass - analog_p->onhooktime > 3)
12082 /* In some cases, all of the above checks will pass even if the line is really off-hook.
12083 * This last check will give the right answer 100% of the time, but is relatively
12084 * "expensive" (it requires an ioctl), so it is last to avoid unnecessary system calls. */
12085 && !my_is_off_hook(last)) {
12086 res = has_voicemail(last);
12087 if (analog_p->msgstate != res) {
12088 /* Set driver resources for signalling VMWI */
12089 res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
12090 if (res2) {
12091 /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
12092 ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
12093 }
12094 /* If enabled for FSK spill then initiate it */
12095 ast_debug(5, "Initiating MWI FSK spill on channel %d\n", last->channel);
12096 if (mwi_send_init(last)) {
12097 ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
12098 }
12099 analog_p->msgstate = res;
12100 found ++;
12101 }
12102 }
12103 last = last->next;
12104 }
12105 }
12106 }
12107 if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
12108 if (i->radio && !i->owner)
12109 {
12110 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12111 if (res)
12112 {
12113 ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
12114 /* Don't hold iflock while handling init events */
12116 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12118 else
12119 doomed = handle_init_event(i, res);
12121 }
12122 continue;
12123 }
12124 pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
12125 if (pollres & POLLIN) {
12126 if (i->owner || i->subs[SUB_REAL].owner) {
12127#ifdef HAVE_PRI
12128 if (!i->pri)
12129#endif
12130 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
12131 continue;
12132 }
12134 ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
12135 continue;
12136 }
12137 res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
12138 if (res > 0) {
12139 if (i->mwimonitor_fsk) {
12140 if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
12141 pthread_attr_t attr;
12142 pthread_t threadid;
12143 struct mwi_thread_data *mtd;
12144
12145 pthread_attr_init(&attr);
12146 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
12147
12148 ast_debug(1, "Maybe some MWI on port %d!\n", i->channel);
12149 if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
12150 mtd->pvt = i;
12151 memcpy(mtd->buf, buf, res);
12152 mtd->len = res;
12153 i->mwimonitoractive = 1;
12154 if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
12155 ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
12156 i->mwimonitoractive = 0;
12157 ast_free(mtd);
12158 }
12159 }
12160 }
12161 /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
12162 } else if (i->cid_start == CID_START_DTMF_NOALERT) {
12163 int energy;
12164 struct timeval now;
12165 /* State machine dtmfcid_holdoff_state allows for the line to settle
12166 * before checking again for dtmf energy. Presently waits for 500 mS before checking again
12167 */
12168 if (1 == i->dtmfcid_holdoff_state) {
12169 gettimeofday(&i->dtmfcid_delay, NULL);
12170 i->dtmfcid_holdoff_state = 2;
12171 } else if (2 == i->dtmfcid_holdoff_state) {
12172 gettimeofday(&now, NULL);
12173 if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
12174 i->dtmfcid_holdoff_state = 0;
12175 }
12176 } else {
12177 energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
12178 if (!i->mwisendactive && energy > dtmfcid_level) {
12179 pthread_t threadid;
12180 struct ast_channel *chan;
12182 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12183 /* just in case this event changes or somehow destroys a channel, set doomed here too */
12185 i->dtmfcid_holdoff_state = 1;
12186 } else {
12187 ast_callid callid = 0;
12188 int callid_created = ast_callid_threadstorage_auto(&callid);
12189 chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, NULL, callid);
12190 if (!chan) {
12191 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
12192 } else {
12193 res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
12194 if (res) {
12195 ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
12196 ast_hangup(chan);
12197 } else {
12198 i->dtmfcid_holdoff_state = 1;
12199 }
12200 }
12202 }
12204 }
12205 }
12206 }
12207 if (i->mwisendactive) {
12209 }
12210 } else {
12211 ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
12212 }
12213 }
12214 if (pollres & POLLPRI) {
12215 if (i->owner || i->subs[SUB_REAL].owner) {
12216#ifdef HAVE_PRI
12217 if (!i->pri)
12218#endif
12219 ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
12220 continue;
12221 }
12222 res = dahdi_get_event(i->subs[SUB_REAL].dfd);
12223 ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
12224 /* Don't hold iflock while handling init events */
12226 if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
12227 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
12229 else
12230 doomed = handle_init_event(i, res);
12231 }
12232 if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
12233 /* Actually automatically reoriginate this FXS line, if directed to.
12234 * We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
12235 * doing its thing (one reason why this is for FXOKS only: FXOLS
12236 * hangups don't give us any DAHDI events to piggyback off of)*/
12237 i->doreoriginate = 0;
12238 /* Double check the channel is still off-hook. There's only about a millisecond
12239 * between when doreoriginate is set high and we see that here, but just to be safe. */
12240 if (!my_is_off_hook(i)) {
12241 ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
12242 } else {
12243 ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
12244 res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
12245 if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
12247 } else {
12248 doomed = handle_init_event(i, res);
12249 }
12250 }
12251 }
12253 }
12254 }
12255 }
12258#ifdef HAVE_OPENR2
12259 dahdi_r2_destroy_nodev();
12260#endif
12261 }
12262 /* Never reached */
12263 pthread_cleanup_pop(1);
12264 return NULL;
12265
12266}
12267
12268static int restart_monitor(void)
12269{
12270 /* If we're supposed to be stopped -- stay stopped */
12272 return 0;
12274 if (monitor_thread == pthread_self()) {
12276 ast_log(LOG_WARNING, "Cannot kill myself\n");
12277 return -1;
12278 }
12280 /* Wake up the thread */
12281 pthread_kill(monitor_thread, SIGURG);
12282 } else {
12283 /* Start a new monitor */
12286 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
12287 return -1;
12288 }
12289 }
12291 return 0;
12292}
12293
12294#if defined(HAVE_PRI)
12295static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
12296{
12297 int x;
12298 int trunkgroup;
12299 /* Get appropriate trunk group if there is one */
12300 trunkgroup = pris[*span].mastertrunkgroup;
12301 if (trunkgroup) {
12302 /* Select a specific trunk group */
12303 for (x = 0; x < NUM_SPANS; x++) {
12304 if (pris[x].pri.trunkgroup == trunkgroup) {
12305 *span = x;
12306 return 0;
12307 }
12308 }
12309 ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
12310 *span = -1;
12311 } else {
12312 if (pris[*span].pri.trunkgroup) {
12313 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);
12314 *span = -1;
12315 } else if (pris[*span].mastertrunkgroup) {
12316 ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
12317 *span = -1;
12318 } else {
12319 if (si->totalchans == 31) {
12320 /* E1 */
12321 pris[*span].dchannels[0] = 16 + offset;
12322 } else if (si->totalchans == 24) {
12323 /* T1 or J1 */
12324 pris[*span].dchannels[0] = 24 + offset;
12325 } else if (si->totalchans == 3) {
12326 /* BRI */
12327 pris[*span].dchannels[0] = 3 + offset;
12328 } else {
12329 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);
12330 *span = -1;
12331 return 0;
12332 }
12333 pris[*span].pri.span = *span + 1;
12334 }
12335 }
12336 return 0;
12337}
12338#endif /* defined(HAVE_PRI) */
12339
12340#if defined(HAVE_PRI)
12341static int pri_create_trunkgroup(int trunkgroup, int *channels)
12342{
12343 struct dahdi_spaninfo si;
12344 struct dahdi_params p;
12345 int fd;
12346 int span;
12347 int ospan=0;
12348 int x,y;
12349 for (x = 0; x < NUM_SPANS; x++) {
12350 if (pris[x].pri.trunkgroup == trunkgroup) {
12351 ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
12352 return -1;
12353 }
12354 }
12355 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12356 if (!channels[y])
12357 break;
12358 memset(&si, 0, sizeof(si));
12359 memset(&p, 0, sizeof(p));
12360 fd = open("/dev/dahdi/channel", O_RDWR);
12361 if (fd < 0) {
12362 ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
12363 return -1;
12364 }
12365 x = channels[y];
12366 if (ioctl(fd, DAHDI_SPECIFY, &x)) {
12367 ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
12368 close(fd);
12369 return -1;
12370 }
12371 if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
12372 ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
12373 close(fd);
12374 return -1;
12375 }
12376 if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
12377 ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
12378 close(fd);
12379 return -1;
12380 }
12381 span = p.spanno - 1;
12382 if (pris[span].pri.trunkgroup) {
12383 ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].pri.trunkgroup);
12384 close(fd);
12385 return -1;
12386 }
12387 if (pris[span].pri.pvts[0]) {
12388 ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
12389 close(fd);
12390 return -1;
12391 }
12392 if (!y) {
12393 pris[span].pri.trunkgroup = trunkgroup;
12394 ospan = span;
12395 }
12396 pris[ospan].dchannels[y] = channels[y];
12397 pris[span].pri.span = span + 1;
12398 close(fd);
12399 }
12400 return 0;
12401}
12402#endif /* defined(HAVE_PRI) */
12403
12404#if defined(HAVE_PRI)
12405static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
12406{
12407 if (pris[span].mastertrunkgroup) {
12408 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);
12409 return -1;
12410 }
12411 pris[span].mastertrunkgroup = trunkgroup;
12412 pris[span].prilogicalspan = logicalspan;
12413 return 0;
12414}
12415#endif /* defined(HAVE_PRI) */
12416
12417#if defined(HAVE_SS7)
12418static unsigned int parse_pointcode(const char *pcstring)
12419{
12420 unsigned int code1, code2, code3;
12421 int numvals;
12422
12423 numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
12424 if (numvals == 1)
12425 return code1;
12426 if (numvals == 3)
12427 return (code1 << 16) | (code2 << 8) | code3;
12428
12429 return 0;
12430}
12431#endif /* defined(HAVE_SS7) */
12432
12433#if defined(HAVE_SS7)
12434static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
12435{
12436 if ((linkset < 0) || (linkset >= NUM_SPANS))
12437 return NULL;
12438 else
12439 return &linksets[linkset - 1];
12440}
12441#endif /* defined(HAVE_SS7) */
12442
12443#ifdef HAVE_OPENR2
12444static void dahdi_r2_destroy_links(void)
12445{
12446 struct r2link_entry *cur;
12447
12448 /* Queue everything for removal */
12449 AST_LIST_LOCK(&r2links);
12450 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
12451 ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
12452 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
12453 }
12455 AST_LIST_UNLOCK(&r2links);
12456 /* Now destroy properly */
12457 dahdi_r2_destroy_nodev();
12458}
12459
12460/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
12461#define R2_LINK_CAPACITY 30
12462static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
12463{
12464 struct r2link_entry *cur = NULL;
12465 /* Only create a new R2 link if
12466 1. This is the first link requested
12467 2. Configuration changed
12468 3. We got more channels than supported per link */
12469 AST_LIST_LOCK(&r2links);
12470 if (! AST_LIST_EMPTY(&r2links)) {
12471 cur = AST_LIST_LAST(&r2links);
12472 if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
12473 ast_debug(3, "Need new R2 link because of: Configuration change\n");
12474 cur = NULL;
12475 } else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
12476 ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
12477 cur = NULL;
12478 }
12479 }
12480 if (!cur) {
12481 struct r2link_entry *tmp = NULL;
12482 int new_idx = r2links_count + 1;
12483 int i;
12484 for (i = 1; i <= r2links_count; i++) {
12485 int i_unused = 1;
12486 AST_LIST_TRAVERSE(&r2links, tmp, list) {
12487 if (i == tmp->mfcr2.index) {
12488 i_unused = 0;
12489 break;
12490 }
12491 }
12492 if (i_unused) {
12493 new_idx = i;
12494 break;
12495 }
12496 }
12497 cur = ast_calloc(1, sizeof(*cur));
12498 if (!cur) {
12499 ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
12500 return NULL;
12501 }
12502 cur->mfcr2.index = new_idx;
12503 cur->mfcr2.r2master = AST_PTHREADT_NULL;
12504 r2links_count++;
12505 ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
12506 AST_LIST_INSERT_TAIL(&r2links, cur, list);
12507 }
12508 AST_LIST_UNLOCK(&r2links);
12509 return cur;
12510}
12511
12512static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
12513{
12514 char tmplogdir[] = "/tmp";
12515 char logdir[OR2_MAX_PATH];
12516 int threshold = 0;
12517 int snres = 0;
12518 r2_link->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
12519 &dahdi_r2_transcode_iface, conf->mfcr2.variant, conf->mfcr2.max_ani,
12520 conf->mfcr2.max_dnis);
12521 if (!r2_link->protocol_context) {
12522 return -1;
12523 }
12524 openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
12525 openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
12526#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
12527 openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
12528#endif
12529 openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
12530 openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
12531 openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
12532 openr2_context_set_double_answer(r2_link->protocol_context, conf->mfcr2.double_answer);
12533 openr2_context_set_immediate_accept(r2_link->protocol_context, conf->mfcr2.immediate_accept);
12534#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
12535 openr2_context_set_dtmf_dialing(r2_link->protocol_context, conf->mfcr2.dtmf_dialing, conf->mfcr2.dtmf_time_on, conf->mfcr2.dtmf_time_off);
12536 openr2_context_set_dtmf_detection(r2_link->protocol_context, conf->mfcr2.dtmf_detection);
12537#endif
12538#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
12539 openr2_context_set_dtmf_detection_end_timeout(r2_link->protocol_context, conf->mfcr2.dtmf_end_timeout);
12540#endif
12541 if (ast_strlen_zero(conf->mfcr2.logdir)) {
12542 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12543 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12544 }
12545 } else {
12546 snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", conf->mfcr2.logdir);
12547 if (snres >= sizeof(logdir)) {
12548 ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
12549 if (openr2_context_set_log_directory(r2_link->protocol_context, tmplogdir)) {
12550 ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
12551 }
12552 } else {
12553 if (openr2_context_set_log_directory(r2_link->protocol_context, logdir)) {
12554 ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
12555 }
12556 }
12557 }
12558 if (!ast_strlen_zero(conf->mfcr2.r2proto_file)) {
12559 if (openr2_context_configure_from_advanced_file(r2_link->protocol_context, conf->mfcr2.r2proto_file)) {
12560 ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
12561 }
12562 }
12563 /* Save the configuration used to setup this link */
12564 memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
12565 return 0;
12566}
12567#endif
12568
12569/* converts a DAHDI sigtype to signalling as can be configured from
12570 * chan_dahdi.conf.
12571 * While both have basically the same values, this will later be the
12572 * place to add filters and sanity checks
12573 */
12575{
12576 return sigtype;
12577}
12578
12579/*!
12580 * \internal
12581 * \brief Initialize/create a channel interface.
12582 *
12583 * \param channel Channel interface number to initialize/create.
12584 * \param conf Configuration parameters to initialize interface with.
12585 * \param reloading What we are doing now:
12586 * 0 - initial module load,
12587 * 1 - module reload,
12588 * 2 - module restart
12589 *
12590 * \retval Interface-pointer initialized/created
12591 * \retval NULL if error
12592 */
12593static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
12594{
12595 /* Make a dahdi_pvt structure for this interface */
12596 struct dahdi_pvt *tmp;/*!< Current channel structure initializing */
12597 char fn[80];
12598 struct dahdi_bufferinfo bi;
12599
12600 int res;
12601#if defined(HAVE_PRI)
12602 int span = 0;
12603#endif /* defined(HAVE_PRI) */
12604 int here = 0;/*!< TRUE if the channel interface already exists. */
12605 int x;
12606 struct analog_pvt *analog_p = NULL;
12607 struct dahdi_params p;
12608#if defined(HAVE_PRI)
12609 struct dahdi_spaninfo si;
12610 struct sig_pri_chan *pri_chan = NULL;
12611#endif /* defined(HAVE_PRI) */
12612#if defined(HAVE_SS7)
12613 struct sig_ss7_chan *ss7_chan = NULL;
12614#endif /* defined(HAVE_SS7) */
12615
12616 /* Search channel interface list to see if it already exists. */
12617 for (tmp = iflist; tmp; tmp = tmp->next) {
12618 if (!tmp->destroy) {
12619 if (tmp->channel == channel) {
12620 /* The channel interface already exists. */
12621 here = 1;
12622 break;
12623 }
12624 if (tmp->channel > channel) {
12625 /* No way it can be in the sorted list. */
12626 tmp = NULL;
12627 break;
12628 }
12629 }
12630 }
12631
12632 if (!here && reloading != 1) {
12633 tmp = ast_calloc(1, sizeof(*tmp));
12634 if (!tmp) {
12635 return NULL;
12636 }
12638 if (!tmp->cc_params) {
12639 ast_free(tmp);
12640 return NULL;
12641 }
12642 ast_mutex_init(&tmp->lock);
12643 ifcount++;
12644 for (x = 0; x < 3; x++)
12645 tmp->subs[x].dfd = -1;
12646 tmp->channel = channel;
12647 tmp->priindication_oob = conf->chan.priindication_oob;
12648 }
12649
12650 if (tmp) {
12651 int chan_sig = conf->chan.sig;
12652
12653 /* If there are variables in tmp before it is updated to match the new config, clear them */
12654 if (reloading && tmp->vars) {
12656 tmp->vars = NULL;
12657 }
12658
12659 if (!here) {
12660 /* Can only get here if this is a new channel interface being created. */
12661 if ((channel != CHAN_PSEUDO)) {
12662 int count = 0;
12663
12664 snprintf(fn, sizeof(fn), "%d", channel);
12665 /* Open non-blocking */
12666 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12667 /* Retry open on restarts, but don't keep retrying if the channel doesn't exist (e.g. not configured) */
12668 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 */
12669 usleep(1);
12670 tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
12671 count++;
12672 }
12673 /* Allocate a DAHDI structure */
12674 if (tmp->subs[SUB_REAL].dfd < 0) {
12675 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);
12676 destroy_dahdi_pvt(tmp);
12677 return NULL;
12678 }
12679 memset(&p, 0, sizeof(p));
12680 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
12681 if (res < 0) {
12682 ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
12683 destroy_dahdi_pvt(tmp);
12684 return NULL;
12685 }
12686 if (conf->is_sig_auto)
12687 chan_sig = sigtype_to_signalling(p.sigtype);
12688 if (p.sigtype != (chan_sig & 0x3ffff)) {
12689 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));
12690 destroy_dahdi_pvt(tmp);
12691 return NULL;
12692 }
12693 tmp->law_default = p.curlaw;
12694 tmp->law = p.curlaw;
12695 tmp->span = p.spanno;
12696#if defined(HAVE_PRI)
12697 span = p.spanno - 1;
12698#endif /* defined(HAVE_PRI) */
12699 } else {
12700 chan_sig = 0;
12701 }
12702 tmp->sig = chan_sig;
12703 tmp->outsigmod = conf->chan.outsigmod;
12704
12705 if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
12706 analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
12707 if (!analog_p) {
12708 destroy_dahdi_pvt(tmp);
12709 return NULL;
12710 }
12711 tmp->sig_pvt = analog_p;
12712 }
12713#if defined(HAVE_SS7)
12714 if (chan_sig == SIG_SS7) {
12715 struct dahdi_ss7 *ss7;
12716 int clear = 0;
12717
12718 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
12719 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12720 destroy_dahdi_pvt(tmp);
12721 return NULL;
12722 }
12723
12724 ss7 = ss7_resolve_linkset(cur_linkset);
12725 if (!ss7) {
12726 ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
12727 destroy_dahdi_pvt(tmp);
12728 return NULL;
12729 }
12730 ss7->ss7.span = cur_linkset;
12731 if (cur_cicbeginswith < 0) {
12732 ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
12733 destroy_dahdi_pvt(tmp);
12734 return NULL;
12735 }
12736 ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
12737 if (!ss7_chan) {
12738 destroy_dahdi_pvt(tmp);
12739 return NULL;
12740 }
12741 tmp->sig_pvt = ss7_chan;
12742 tmp->ss7 = &ss7->ss7;
12743
12744 ss7_chan->channel = tmp->channel;
12745 ss7_chan->cic = cur_cicbeginswith++;
12746
12747 /* DB: Add CIC's DPC information */
12748 ss7_chan->dpc = cur_defaultdpc;
12749
12750 ss7->ss7.pvts[ss7->ss7.numchans++] = ss7_chan;
12751
12752 ast_copy_string(ss7->ss7.internationalprefix, conf->ss7.ss7.internationalprefix, sizeof(ss7->ss7.internationalprefix));
12753 ast_copy_string(ss7->ss7.nationalprefix, conf->ss7.ss7.nationalprefix, sizeof(ss7->ss7.nationalprefix));
12754 ast_copy_string(ss7->ss7.subscriberprefix, conf->ss7.ss7.subscriberprefix, sizeof(ss7->ss7.subscriberprefix));
12755 ast_copy_string(ss7->ss7.unknownprefix, conf->ss7.ss7.unknownprefix, sizeof(ss7->ss7.unknownprefix));
12756 ast_copy_string(ss7->ss7.networkroutedprefix, conf->ss7.ss7.networkroutedprefix, sizeof(ss7->ss7.networkroutedprefix));
12757
12758 ss7->ss7.called_nai = conf->ss7.ss7.called_nai;
12759 ss7->ss7.calling_nai = conf->ss7.ss7.calling_nai;
12760 }
12761#endif /* defined(HAVE_SS7) */
12762#ifdef HAVE_OPENR2
12763 if (chan_sig == SIG_MFCR2) {
12764 struct dahdi_mfcr2 *r2_link;
12765 struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
12766 r2_link = &r2_le->mfcr2;
12767 if (!r2_link) {
12768 ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
12769 destroy_dahdi_pvt(tmp);
12770 return NULL;
12771 }
12772 if (!r2_link->protocol_context && dahdi_r2_set_context(r2_link, conf)) {
12773 ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
12774 destroy_dahdi_pvt(tmp);
12775 return NULL;
12776 }
12777 if (r2_link->numchans == ARRAY_LEN(r2_link->pvts)) {
12778 ast_log(LOG_ERROR, "Cannot add more channels to this link!\n");
12779 destroy_dahdi_pvt(tmp);
12780 return NULL;
12781 }
12782 r2_link->pvts[r2_link->numchans++] = tmp;
12783 tmp->r2chan = openr2_chan_new_from_fd(r2_link->protocol_context,
12784 tmp->subs[SUB_REAL].dfd,
12785 NULL, NULL);
12786 if (!tmp->r2chan) {
12787 openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
12788 ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
12789 destroy_dahdi_pvt(tmp);
12790 return NULL;
12791 }
12792 r2_link->live_chans++;
12793 tmp->mfcr2 = r2_link;
12794 if (conf->mfcr2.call_files) {
12795 openr2_chan_enable_call_files(tmp->r2chan);
12796 }
12797 openr2_chan_set_client_data(tmp->r2chan, tmp);
12798 /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
12799 openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
12800 openr2_chan_set_log_level(tmp->r2chan, conf->mfcr2.loglevel);
12801 tmp->mfcr2_category = conf->mfcr2.category;
12802 tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
12803 tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
12804 tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
12805 tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
12806 tmp->mfcr2call = 0;
12807 tmp->mfcr2_dnis_index = 0;
12808 tmp->mfcr2_ani_index = 0;
12809 }
12810#endif
12811#ifdef HAVE_PRI
12812 if (dahdi_sig_pri_lib_handles(chan_sig)) {
12813 int offset;
12814 int matchesdchan;
12815 int x,y;
12816 int myswitchtype = 0;
12817
12818 offset = 0;
12819 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
12820 ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
12821 destroy_dahdi_pvt(tmp);
12822 return NULL;
12823 }
12824 if (span >= NUM_SPANS) {
12825 ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
12826 destroy_dahdi_pvt(tmp);
12827 return NULL;
12828 } else {
12829 si.spanno = 0;
12830 if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
12831 ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
12832 destroy_dahdi_pvt(tmp);
12833 return NULL;
12834 }
12835 /* Store the logical span first based upon the real span */
12836 tmp->logicalspan = pris[span].prilogicalspan;
12837 pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
12838 if (span < 0) {
12839 ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
12840 destroy_dahdi_pvt(tmp);
12841 return NULL;
12842 }
12843 myswitchtype = conf->pri.pri.switchtype;
12844 /* Make sure this isn't a d-channel */
12845 matchesdchan=0;
12846 for (x = 0; x < NUM_SPANS; x++) {
12847 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
12848 if (pris[x].dchannels[y] == tmp->channel) {
12849 matchesdchan = 1;
12850 break;
12851 }
12852 }
12853 }
12854 if (!matchesdchan) {
12855 if (pris[span].pri.nodetype && (pris[span].pri.nodetype != conf->pri.pri.nodetype)) {
12856 ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].pri.nodetype));
12857 destroy_dahdi_pvt(tmp);
12858 return NULL;
12859 }
12860 if (pris[span].pri.switchtype && (pris[span].pri.switchtype != myswitchtype)) {
12861 ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].pri.switchtype));
12862 destroy_dahdi_pvt(tmp);
12863 return NULL;
12864 }
12865 if ((pris[span].pri.dialplan) && (pris[span].pri.dialplan != conf->pri.pri.dialplan)) {
12866 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));
12867 destroy_dahdi_pvt(tmp);
12868 return NULL;
12869 }
12870 if (!ast_strlen_zero(pris[span].pri.idledial) && strcmp(pris[span].pri.idledial, conf->pri.pri.idledial)) {
12871 ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.pri.idledial);
12872 destroy_dahdi_pvt(tmp);
12873 return NULL;
12874 }
12875 if (!ast_strlen_zero(pris[span].pri.idleext) && strcmp(pris[span].pri.idleext, conf->pri.pri.idleext)) {
12876 ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.pri.idleext);
12877 destroy_dahdi_pvt(tmp);
12878 return NULL;
12879 }
12880 if (pris[span].pri.minunused && (pris[span].pri.minunused != conf->pri.pri.minunused)) {
12881 ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.pri.minunused);
12882 destroy_dahdi_pvt(tmp);
12883 return NULL;
12884 }
12885 if (pris[span].pri.minidle && (pris[span].pri.minidle != conf->pri.pri.minidle)) {
12886 ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.pri.minidle);
12887 destroy_dahdi_pvt(tmp);
12888 return NULL;
12889 }
12890 if (pris[span].pri.numchans >= ARRAY_LEN(pris[span].pri.pvts)) {
12891 ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
12892 pris[span].pri.trunkgroup);
12893 destroy_dahdi_pvt(tmp);
12894 return NULL;
12895 }
12896
12897 pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
12898 if (!pri_chan) {
12899 destroy_dahdi_pvt(tmp);
12900 return NULL;
12901 }
12902 tmp->sig_pvt = pri_chan;
12903 tmp->pri = &pris[span].pri;
12904
12905 tmp->priexclusive = conf->chan.priexclusive;
12906
12907 if (!tmp->pri->cc_params) {
12909 if (!tmp->pri->cc_params) {
12910 destroy_dahdi_pvt(tmp);
12911 return NULL;
12912 }
12913 }
12915 conf->chan.cc_params);
12916
12917 pris[span].pri.sig = chan_sig;
12918 pris[span].pri.nodetype = conf->pri.pri.nodetype;
12919 pris[span].pri.switchtype = myswitchtype;
12920 pris[span].pri.nsf = conf->pri.pri.nsf;
12921 pris[span].pri.dialplan = conf->pri.pri.dialplan;
12922 pris[span].pri.localdialplan = conf->pri.pri.localdialplan;
12923 pris[span].pri.cpndialplan = conf->pri.pri.cpndialplan;
12924 pris[span].pri.pvts[pris[span].pri.numchans++] = tmp->sig_pvt;
12925 pris[span].pri.minunused = conf->pri.pri.minunused;
12926 pris[span].pri.minidle = conf->pri.pri.minidle;
12927 pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
12928 pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
12929 pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
12930#if defined(HAVE_PRI_SERVICE_MESSAGES)
12931 pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
12932#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
12933#ifdef HAVE_PRI_INBANDDISCONNECT
12934 pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
12935#endif
12936#if defined(HAVE_PRI_CALL_HOLD)
12937 pris[span].pri.hold_disconnect_transfer =
12938 conf->pri.pri.hold_disconnect_transfer;
12939#endif /* defined(HAVE_PRI_CALL_HOLD) */
12940#if defined(HAVE_PRI_CCSS)
12941 pris[span].pri.cc_ptmp_recall_mode =
12942 conf->pri.pri.cc_ptmp_recall_mode;
12943 pris[span].pri.cc_qsig_signaling_link_req =
12944 conf->pri.pri.cc_qsig_signaling_link_req;
12945 pris[span].pri.cc_qsig_signaling_link_rsp =
12946 conf->pri.pri.cc_qsig_signaling_link_rsp;
12947#endif /* defined(HAVE_PRI_CCSS) */
12948#if defined(HAVE_PRI_CALL_WAITING)
12949 pris[span].pri.max_call_waiting_calls =
12950 conf->pri.pri.max_call_waiting_calls;
12951 pris[span].pri.allow_call_waiting_calls =
12952 conf->pri.pri.allow_call_waiting_calls;
12953#endif /* defined(HAVE_PRI_CALL_WAITING) */
12954 pris[span].pri.transfer = conf->chan.transfer;
12955 pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
12956#if defined(HAVE_PRI_L2_PERSISTENCE)
12957 pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
12958#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
12959 pris[span].pri.colp_send = conf->pri.pri.colp_send;
12960#if defined(HAVE_PRI_AOC_EVENTS)
12961 pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
12962 pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
12963#endif /* defined(HAVE_PRI_AOC_EVENTS) */
12964 if (chan_sig == SIG_BRI_PTMP) {
12965 pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
12966 } else {
12967 /* Option does not apply to this line type. */
12968 pris[span].pri.layer1_ignored = 0;
12969 }
12970 pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
12971 pris[span].pri.inband_on_setup_ack = conf->pri.pri.inband_on_setup_ack;
12972 pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
12973 ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
12974 ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
12975#if defined(HAVE_PRI_MWI)
12976 ast_copy_string(pris[span].pri.mwi_mailboxes,
12977 conf->pri.pri.mwi_mailboxes,
12978 sizeof(pris[span].pri.mwi_mailboxes));
12979 ast_copy_string(pris[span].pri.mwi_vm_boxes,
12980 conf->pri.pri.mwi_vm_boxes,
12981 sizeof(pris[span].pri.mwi_vm_boxes));
12982 ast_copy_string(pris[span].pri.mwi_vm_numbers,
12983 conf->pri.pri.mwi_vm_numbers,
12984 sizeof(pris[span].pri.mwi_vm_numbers));
12985#endif /* defined(HAVE_PRI_MWI) */
12986 ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
12987 ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
12988 ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix));
12989 ast_copy_string(pris[span].pri.nationalprefix, conf->pri.pri.nationalprefix, sizeof(pris[span].pri.nationalprefix));
12990 ast_copy_string(pris[span].pri.localprefix, conf->pri.pri.localprefix, sizeof(pris[span].pri.localprefix));
12991 ast_copy_string(pris[span].pri.privateprefix, conf->pri.pri.privateprefix, sizeof(pris[span].pri.privateprefix));
12992 ast_copy_string(pris[span].pri.unknownprefix, conf->pri.pri.unknownprefix, sizeof(pris[span].pri.unknownprefix));
12993 pris[span].pri.moh_signaling = conf->pri.pri.moh_signaling;
12994 pris[span].pri.resetinterval = conf->pri.pri.resetinterval;
12995#if defined(HAVE_PRI_DISPLAY_TEXT)
12996 pris[span].pri.display_flags_send = conf->pri.pri.display_flags_send;
12997 pris[span].pri.display_flags_receive = conf->pri.pri.display_flags_receive;
12998#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
12999#if defined(HAVE_PRI_MCID)
13000 pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
13001#endif /* defined(HAVE_PRI_MCID) */
13002 pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
13003#if defined(HAVE_PRI_DATETIME_SEND)
13004 pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
13005#endif /* defined(HAVE_PRI_DATETIME_SEND) */
13006
13007 for (x = 0; x < PRI_MAX_TIMERS; x++) {
13008 pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
13009 }
13010
13011#if defined(HAVE_PRI_CALL_WAITING)
13012 /* Channel initial config parameters. */
13013 pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
13014 pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
13015 pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
13016 pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
13017 pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
13018 pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
13019 pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
13020 pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
13021 ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
13022 ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
13023#endif /* defined(HAVE_PRI_CALL_WAITING) */
13024 } else {
13025 ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
13026 destroy_dahdi_pvt(tmp);
13027 return NULL;
13028 }
13029 }
13030 }
13031#endif
13032 } else {
13033 /* already exists in interface list */
13034 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));
13035 chan_sig = tmp->sig;
13036 if (tmp->subs[SUB_REAL].dfd > -1) {
13037 memset(&p, 0, sizeof(p));
13038 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13039 }
13040 }
13041 /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
13042 switch (chan_sig) {
13043 case SIG_FXSKS:
13044 case SIG_FXSLS:
13045 case SIG_EM:
13046 case SIG_EM_E1:
13047 case SIG_EMWINK:
13048 case SIG_FEATD:
13049 case SIG_FEATDMF:
13050 case SIG_FEATDMF_TA:
13051 case SIG_FEATB:
13052 case SIG_E911:
13053 case SIG_SF:
13054 case SIG_SFWINK:
13055 case SIG_FGC_CAMA:
13056 case SIG_FGC_CAMAMF:
13057 case SIG_SF_FEATD:
13058 case SIG_SF_FEATDMF:
13059 case SIG_SF_FEATB:
13060 p.starttime = 250;
13061 break;
13062 }
13063
13064 if (tmp->radio) {
13065 /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
13066 p.channo = channel;
13067 p.rxwinktime = 1;
13068 p.rxflashtime = 1;
13069 p.starttime = 1;
13070 p.debouncetime = 5;
13071 } else {
13072 p.channo = channel;
13073 /* Override timing settings based on config file */
13074 if (conf->timing.prewinktime >= 0)
13075 p.prewinktime = conf->timing.prewinktime;
13076 if (conf->timing.preflashtime >= 0)
13077 p.preflashtime = conf->timing.preflashtime;
13078 if (conf->timing.winktime >= 0)
13079 p.winktime = conf->timing.winktime;
13080 if (conf->timing.flashtime >= 0)
13081 p.flashtime = conf->timing.flashtime;
13082 if (conf->timing.starttime >= 0)
13083 p.starttime = conf->timing.starttime;
13084 if (conf->timing.rxwinktime >= 0)
13085 p.rxwinktime = conf->timing.rxwinktime;
13086 if (conf->timing.rxflashtime >= 0)
13087 p.rxflashtime = conf->timing.rxflashtime;
13088 if (conf->timing.debouncetime >= 0)
13089 p.debouncetime = conf->timing.debouncetime;
13090 }
13091
13092 /* don't set parms on a pseudo-channel */
13093 if (tmp->subs[SUB_REAL].dfd >= 0)
13094 {
13095 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
13096 if (res < 0) {
13097 ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
13098 destroy_dahdi_pvt(tmp);
13099 return NULL;
13100 }
13101 }
13102#if 1
13103 if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
13104 memset(&bi, 0, sizeof(bi));
13105 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13106 if (!res) {
13107 bi.txbufpolicy = conf->chan.buf_policy;
13108 bi.rxbufpolicy = conf->chan.buf_policy;
13109 bi.numbufs = conf->chan.buf_no;
13110 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13111 if (res < 0) {
13112 ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
13113 }
13114 } else {
13115 ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
13116 }
13117 tmp->buf_policy = conf->chan.buf_policy;
13118 tmp->buf_no = conf->chan.buf_no;
13119 tmp->usefaxbuffers = conf->chan.usefaxbuffers;
13120 tmp->faxbuf_policy = conf->chan.faxbuf_policy;
13121 tmp->faxbuf_no = conf->chan.faxbuf_no;
13122 /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting
13123 * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail.
13124 * The reason the ioctl call above failed should to be determined before worrying about the
13125 * faxbuffer-related ioctl calls */
13126 tmp->bufsize = bi.bufsize;
13127 }
13128#endif
13129 tmp->immediate = conf->chan.immediate;
13130 tmp->immediatering = conf->chan.immediatering;
13131 tmp->transfertobusy = conf->chan.transfertobusy;
13132 tmp->permdialmode = conf->chan.permdialmode;
13133 if (chan_sig & __DAHDI_SIG_FXS) {
13134 tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
13135 tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
13136 tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
13137 }
13138 tmp->ringt_base = ringt_base;
13139 tmp->firstradio = 0;
13140 if (CHAN_IS_FXO_SIG(chan_sig))
13141 tmp->permcallwaiting = conf->chan.callwaiting;
13142 else
13143 tmp->permcallwaiting = 0;
13144 /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
13145 tmp->destroy = 0;
13146 tmp->drings = conf->chan.drings;
13147
13148 /* 10 is a nice default. */
13149 if (tmp->drings.ringnum[0].range == 0)
13150 tmp->drings.ringnum[0].range = 10;
13151 if (tmp->drings.ringnum[1].range == 0)
13152 tmp->drings.ringnum[1].range = 10;
13153 if (tmp->drings.ringnum[2].range == 0)
13154 tmp->drings.ringnum[2].range = 10;
13155
13157 tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
13158 tmp->callwaitingdeluxe = conf->chan.callwaitingdeluxe; /* Not used in DAHDI pvt, only analog pvt */
13159 tmp->threewaycalling = conf->chan.threewaycalling;
13160 tmp->threewaysilenthold = conf->chan.threewaysilenthold;
13161 tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
13162 tmp->adsi = conf->chan.adsi;
13163 tmp->use_smdi = conf->chan.use_smdi;
13164 tmp->permhidecallerid = conf->chan.hidecallerid;
13165 tmp->hidecalleridname = conf->chan.hidecalleridname;
13166 tmp->callreturn = conf->chan.callreturn;
13167 tmp->lastnumredial = conf->chan.lastnumredial; /* Not used in DAHDI pvt, only analog pvt */
13168 tmp->echocancel = conf->chan.echocancel;
13169 tmp->echotraining = conf->chan.echotraining;
13170 tmp->pulse = conf->chan.pulse;
13171 if (tmp->echocancel.head.tap_length) {
13172 tmp->echocanbridged = conf->chan.echocanbridged;
13173 } else {
13174 if (conf->chan.echocanbridged)
13175 ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
13176 tmp->echocanbridged = 0;
13177 }
13178 tmp->busydetect = conf->chan.busydetect;
13179 tmp->busycount = conf->chan.busycount;
13180 tmp->busy_cadence = conf->chan.busy_cadence;
13181 tmp->callprogress = conf->chan.callprogress;
13182 tmp->waitfordialtone = conf->chan.waitfordialtone;
13183 tmp->dialtone_detect = conf->chan.dialtone_detect;
13184 tmp->faxdetect_timeout = conf->chan.faxdetect_timeout;
13185 tmp->firstdigit_timeout = conf->chan.firstdigit_timeout;
13186 tmp->interdigit_timeout = conf->chan.interdigit_timeout;
13187 tmp->matchdigit_timeout = conf->chan.matchdigit_timeout;
13188 tmp->cancallforward = conf->chan.cancallforward;
13189 tmp->dtmfrelax = conf->chan.dtmfrelax;
13190 tmp->callwaiting = tmp->permcallwaiting;
13191 tmp->hidecallerid = tmp->permhidecallerid;
13192 tmp->channel = channel;
13193 tmp->stripmsd = conf->chan.stripmsd;
13194 tmp->use_callerid = conf->chan.use_callerid;
13195 tmp->cid_signalling = conf->chan.cid_signalling;
13196 tmp->cid_start = conf->chan.cid_start;
13197 tmp->dahditrcallerid = conf->chan.dahditrcallerid;
13198 tmp->restrictcid = conf->chan.restrictcid;
13199 tmp->use_callingpres = conf->chan.use_callingpres;
13200 if (tmp->usedistinctiveringdetection) {
13201 if (!tmp->use_callerid) {
13202 ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
13203 tmp->use_callerid = 1;
13204 }
13205 }
13206
13207 if (tmp->cid_signalling == CID_SIG_SMDI) {
13208 if (!tmp->use_smdi) {
13209 ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
13210 tmp->use_smdi = 1;
13211 }
13212 }
13213 if (tmp->use_smdi) {
13214 tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
13215 if (!(tmp->smdi_iface)) {
13216 ast_log(LOG_ERROR, "Invalid SMDI port specified, disabling SMDI support\n");
13217 tmp->use_smdi = 0;
13218 }
13219 }
13220
13221 ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
13222 tmp->amaflags = conf->chan.amaflags;
13223 if (!here) {
13224 tmp->confno = -1;
13225 tmp->propconfno = -1;
13226 }
13227 tmp->canpark = conf->chan.canpark;
13228 tmp->transfer = conf->chan.transfer;
13229 ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
13230 ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
13231 ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
13232 ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
13233 ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
13234 ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
13235 ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
13236 tmp->cid_ton = 0;
13237 if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
13238 ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
13239 ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
13240 } else {
13241 tmp->cid_num[0] = '\0';
13242 tmp->cid_name[0] = '\0';
13243 }
13244#if defined(HAVE_PRI)
13245 if (dahdi_sig_pri_lib_handles(tmp->sig)) {
13246 tmp->cid_tag[0] = '\0';
13247 } else
13248#endif /* defined(HAVE_PRI) */
13249 {
13250 ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
13251 }
13252 tmp->cid_subaddr[0] = '\0';
13253 ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
13254 if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
13255 /* This module does not handle MWI in an event-based manner. However, it
13256 * subscribes to MWI for each mailbox that is configured so that the core
13257 * knows that we care about it. Then, chan_dahdi will get the MWI from the
13258 * event cache instead of checking the mailbox directly. */
13260 }
13261#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13262 tmp->mwisend_setting = conf->chan.mwisend_setting;
13263 tmp->mwisend_fsk = conf->chan.mwisend_fsk;
13264 tmp->mwisend_rpas = conf->chan.mwisend_rpas;
13265#endif
13266
13267 tmp->group = conf->chan.group;
13268 tmp->callgroup = conf->chan.callgroup;
13269 tmp->pickupgroup= conf->chan.pickupgroup;
13271 tmp->named_callgroups = ast_ref_namedgroups(conf->chan.named_callgroups);
13273 tmp->named_pickupgroups = ast_ref_namedgroups(conf->chan.named_pickupgroups);
13274 if (conf->chan.vars) {
13275 struct ast_variable *v, *tmpvar;
13276 for (v = conf->chan.vars ; v ; v = v->next) {
13277 if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
13278 if (ast_variable_list_replace(&tmp->vars, tmpvar)) {
13279 tmpvar->next = tmp->vars;
13280 tmp->vars = tmpvar;
13281 }
13282 }
13283 }
13284 }
13285 tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
13286 tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
13287 tmp->hwrxgain = conf->chan.hwrxgain;
13288 tmp->hwtxgain = conf->chan.hwtxgain;
13289 tmp->cid_rxgain = conf->chan.cid_rxgain;
13290 tmp->rxgain = conf->chan.rxgain;
13291 tmp->txgain = conf->chan.txgain;
13292 tmp->txdrc = conf->chan.txdrc;
13293 tmp->rxdrc = conf->chan.rxdrc;
13294 tmp->tonezone = conf->chan.tonezone;
13295 if (tmp->subs[SUB_REAL].dfd > -1) {
13296 if (tmp->hwrxgain_enabled) {
13297 tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
13298 }
13299 if (tmp->hwtxgain_enabled) {
13300 tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
13301 }
13302 set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
13303 if (tmp->dsp)
13305 dahdi_conf_update(tmp);
13306 if (!here) {
13307 switch (chan_sig) {
13309 case SIG_SS7:
13310 case SIG_MFCR2:
13311 break;
13312 default:
13313 /* Hang it up to be sure it's good */
13314 dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
13315 break;
13316 }
13317 }
13318 ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
13319 if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
13320 /* the dchannel is down so put the channel in alarm */
13321 switch (tmp->sig) {
13322#ifdef HAVE_PRI
13324 sig_pri_set_alarm(tmp->sig_pvt, 1);
13325 break;
13326#endif
13327#if defined(HAVE_SS7)
13328 case SIG_SS7:
13329 sig_ss7_set_alarm(tmp->sig_pvt, 1);
13330 break;
13331#endif /* defined(HAVE_SS7) */
13332 default:
13333 /* The only sig submodule left should be sig_analog. */
13334 analog_p = tmp->sig_pvt;
13335 if (analog_p) {
13336 analog_p->inalarm = 1;
13337 }
13338 tmp->inalarm = 1;
13339 break;
13340 }
13341 handle_alarms(tmp, res);
13342 }
13343 }
13344
13345 tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13346 tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13347 tmp->ani_info_digits = conf->chan.ani_info_digits;
13348 tmp->ani_wink_time = conf->chan.ani_wink_time;
13349 tmp->ani_timeout = conf->chan.ani_timeout;
13350 tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13351 tmp->reoriginate = conf->chan.reoriginate;
13352 tmp->sendcalleridafter = conf->chan.sendcalleridafter;
13353 ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
13354
13355 if (!here) {
13356 tmp->locallyblocked = 0;
13357 tmp->remotelyblocked = 0;
13358 switch (tmp->sig) {
13359#if defined(HAVE_PRI)
13361 tmp->inservice = 1;/* Inservice until actually implemented. */
13362#if defined(HAVE_PRI_SERVICE_MESSAGES)
13363 ((struct sig_pri_chan *) tmp->sig_pvt)->service_status = 0;
13364 if (chan_sig == SIG_PRI) {
13365 char db_chan_name[20];
13366 char db_answer[5];
13367
13368 /*
13369 * Initialize the active out-of-service status
13370 * and delete any record if the feature is not enabled.
13371 */
13372 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
13373 if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
13374 unsigned *why;
13375
13376 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
13377 if (tmp->pri->enable_service_message_support) {
13378 char state;
13379
13380 sscanf(db_answer, "%1c:%30u", &state, why);
13381
13382 /* Ensure that only the implemented bits could be set.*/
13383 *why &= (SRVST_NEAREND | SRVST_FAREND);
13384 }
13385 if (!*why) {
13386 ast_db_del(db_chan_name, SRVST_DBKEY);
13387 }
13388 }
13389 }
13390#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
13391 break;
13392#endif /* defined(HAVE_PRI) */
13393#if defined(HAVE_SS7)
13394 case SIG_SS7:
13395 tmp->inservice = 0;
13396 if (tmp->ss7->flags & LINKSET_FLAG_INITIALHWBLO) {
13398 }
13399 break;
13400#endif /* defined(HAVE_SS7) */
13401 default:
13402 /* We default to in service on protocols that don't have a reset */
13403 tmp->inservice = 1;
13404 break;
13405 }
13406 }
13407
13408 switch (tmp->sig) {
13409#if defined(HAVE_PRI)
13411 if (pri_chan) {
13412 pri_chan->channel = tmp->channel;
13413 pri_chan->hidecallerid = tmp->hidecallerid;
13414 pri_chan->hidecalleridname = tmp->hidecalleridname;
13415 pri_chan->immediate = tmp->immediate;
13416 pri_chan->inalarm = tmp->inalarm;
13417 pri_chan->priexclusive = tmp->priexclusive;
13418 pri_chan->priindication_oob = tmp->priindication_oob;
13419 pri_chan->use_callerid = tmp->use_callerid;
13420 pri_chan->use_callingpres = tmp->use_callingpres;
13421 ast_copy_string(pri_chan->context, tmp->context,
13422 sizeof(pri_chan->context));
13424 sizeof(pri_chan->mohinterpret));
13425 pri_chan->stripmsd = tmp->stripmsd;
13426 }
13427 break;
13428#endif /* defined(HAVE_PRI) */
13429#if defined(HAVE_SS7)
13430 case SIG_SS7:
13431 if (ss7_chan) {
13432 ss7_chan->inalarm = tmp->inalarm;
13433 ss7_chan->inservice = tmp->inservice;
13434
13435 ss7_chan->stripmsd = tmp->stripmsd;
13436 ss7_chan->hidecallerid = tmp->hidecallerid;
13437 ss7_chan->use_callerid = tmp->use_callerid;
13438 ss7_chan->use_callingpres = tmp->use_callingpres;
13439 ss7_chan->immediate = tmp->immediate;
13440 ss7_chan->locallyblocked = tmp->locallyblocked;
13441 ss7_chan->remotelyblocked = tmp->remotelyblocked;
13442 ast_copy_string(ss7_chan->context, tmp->context,
13443 sizeof(ss7_chan->context));
13445 sizeof(ss7_chan->mohinterpret));
13446 }
13447 break;
13448#endif /* defined(HAVE_SS7) */
13449 default:
13450 /* The only sig submodule left should be sig_analog. */
13451 analog_p = tmp->sig_pvt;
13452 if (analog_p) {
13453 analog_p->channel = tmp->channel;
13454 analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
13455 analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
13456 analog_p->ani_info_digits = conf->chan.ani_info_digits;
13457 analog_p->ani_timeout = conf->chan.ani_timeout;
13458 analog_p->ani_wink_time = conf->chan.ani_wink_time;
13459 analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
13460 analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13461 analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
13462 analog_p->callreturn = conf->chan.callreturn;
13463 analog_p->lastnumredial = conf->chan.lastnumredial; /* Only actually used in analog pvt, not DAHDI pvt */
13464 analog_p->cancallforward = conf->chan.cancallforward;
13465 analog_p->canpark = conf->chan.canpark;
13466 analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
13467 analog_p->immediate = conf->chan.immediate;
13468 analog_p->immediatering = conf->chan.immediatering;
13469 analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
13470 /* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
13471 analog_p->pulse = conf->chan.pulse;
13472 analog_p->threewaycalling = conf->chan.threewaycalling;
13473 analog_p->transfer = conf->chan.transfer;
13474 analog_p->transfertobusy = conf->chan.transfertobusy;
13475 analog_p->permdialmode = conf->chan.permdialmode;
13476 analog_p->use_callerid = tmp->use_callerid;
13478 analog_p->use_smdi = tmp->use_smdi;
13479 analog_p->smdi_iface = tmp->smdi_iface;
13480 analog_p->outsigmod = ANALOG_SIG_NONE;
13481 analog_p->echotraining = conf->chan.echotraining;
13482 analog_p->cid_signalling = conf->chan.cid_signalling;
13483 analog_p->stripmsd = conf->chan.stripmsd;
13484 switch (conf->chan.cid_start) {
13485 case CID_START_POLARITY:
13487 break;
13490 break;
13493 break;
13494 default:
13495 analog_p->cid_start = ANALOG_CID_START_RING;
13496 break;
13497 }
13498 analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
13499 analog_p->callwaitingdeluxe = conf->chan.callwaitingdeluxe;
13500 analog_p->ringt = conf->chan.ringt;
13501 analog_p->ringt_base = ringt_base;
13502 analog_p->onhooktime = time(NULL);
13503 if (chan_sig & __DAHDI_SIG_FXO) {
13504 memset(&p, 0, sizeof(p));
13505 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
13506 if (!res) {
13507 analog_p->fxsoffhookstate = p.rxisoffhook;
13508 }
13509#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
13510 res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
13511#endif
13512 }
13513 analog_p->msgstate = -1;
13514
13515 ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
13516 ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
13517 ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
13518
13519 analog_config_complete(analog_p);
13520 }
13521 break;
13522 }
13523#if defined(HAVE_PRI)
13524 if (tmp->channel == CHAN_PSEUDO) {
13525 /*
13526 * Save off pseudo channel buffer policy values for dynamic creation of
13527 * no B channel interfaces.
13528 */
13529 dahdi_pseudo_parms.buf_no = tmp->buf_no;
13530 dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
13531 dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
13532 dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
13533 }
13534#endif /* defined(HAVE_PRI) */
13535 }
13536 if (tmp && !here) {
13537 /* Add the new channel interface to the sorted channel interface list. */
13539 }
13540 return tmp;
13541}
13542
13543static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
13544{
13545#if defined(HAVE_PRI)
13546 if (0 < span) {
13547 /* The channel must be on the specified PRI span. */
13548 if (!p->pri || p->pri->span != span) {
13549 return 0;
13550 }
13551 if (!groupmatch && channelmatch == -1) {
13552 /* Match any group since it only needs to be on the PRI span. */
13553 *groupmatched = 1;
13554 return 1;
13555 }
13556 }
13557#endif /* defined(HAVE_PRI) */
13558 /* check group matching */
13559 if (groupmatch) {
13560 if ((p->group & groupmatch) != groupmatch)
13561 /* Doesn't match the specified group, try the next one */
13562 return 0;
13563 *groupmatched = 1;
13564 }
13565 /* Check to see if we have a channel match */
13566 if (channelmatch != -1) {
13567 if (p->channel != channelmatch)
13568 /* Doesn't match the specified channel, try the next one */
13569 return 0;
13570 *channelmatched = 1;
13571 }
13572
13573 return 1;
13574}
13575
13576static int available(struct dahdi_pvt **pvt, int is_specific_channel)
13577{
13578 struct dahdi_pvt *p = *pvt;
13579
13580 if (p->inalarm)
13581 return 0;
13582
13583 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
13584 return analog_available(p->sig_pvt);
13585
13586 switch (p->sig) {
13587#if defined(HAVE_PRI)
13589 {
13590 struct sig_pri_chan *pvt_chan;
13591 int res;
13592
13593 pvt_chan = p->sig_pvt;
13594 res = sig_pri_available(&pvt_chan, is_specific_channel);
13595 *pvt = pvt_chan->chan_pvt;
13596 return res;
13597 }
13598#endif /* defined(HAVE_PRI) */
13599#if defined(HAVE_SS7)
13600 case SIG_SS7:
13601 return sig_ss7_available(p->sig_pvt);
13602#endif /* defined(HAVE_SS7) */
13603 default:
13604 break;
13605 }
13606
13607 if (p->locallyblocked || p->remotelyblocked) {
13608 return 0;
13609 }
13610
13611 /* If no owner definitely available */
13612 if (!p->owner) {
13613#ifdef HAVE_OPENR2
13614 /* Trust MFC/R2 */
13615 if (p->mfcr2) {
13616 if (p->mfcr2call) {
13617 return 0;
13618 } else {
13619 return 1;
13620 }
13621 }
13622#endif
13623 return 1;
13624 }
13625
13626 return 0;
13627}
13628
13629#if defined(HAVE_PRI)
13630#if defined(HAVE_PRI_CALL_WAITING)
13631/*!
13632 * \internal
13633 * \brief Init the private channel configuration using the span controller.
13634 * \since 1.8
13635 *
13636 * \param priv Channel to init the configuration.
13637 * \param pri sig_pri PRI control structure.
13638 *
13639 * \note Assumes the pri->lock is already obtained.
13640 */
13641static void my_pri_init_config(void *priv, struct sig_pri_span *pri)
13642{
13643 struct dahdi_pvt *pvt = priv;
13644
13645 pvt->stripmsd = pri->ch_cfg.stripmsd;
13646 pvt->hidecallerid = pri->ch_cfg.hidecallerid;
13647 pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
13648 pvt->immediate = pri->ch_cfg.immediate;
13649 pvt->priexclusive = pri->ch_cfg.priexclusive;
13650 pvt->priindication_oob = pri->ch_cfg.priindication_oob;
13651 pvt->use_callerid = pri->ch_cfg.use_callerid;
13652 pvt->use_callingpres = pri->ch_cfg.use_callingpres;
13653 ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
13654 ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
13655}
13656#endif /* defined(HAVE_PRI_CALL_WAITING) */
13657#endif /* defined(HAVE_PRI) */
13658
13659#if defined(HAVE_PRI)
13660/*!
13661 * \internal
13662 * \brief Create a no B channel interface.
13663 * \since 1.8
13664 *
13665 * \param pri sig_pri span controller to add interface.
13666 *
13667 * \note Assumes the pri->lock is already obtained.
13668 *
13669 * \retval array-index into private pointer array on success.
13670 * \retval -1 on error.
13671 */
13672static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri)
13673{
13674 int pvt_idx;
13675 int res;
13676 unsigned idx;
13677 struct dahdi_pvt *pvt;
13678 struct sig_pri_chan *chan;
13679 struct dahdi_bufferinfo bi;
13680
13681 static int nobch_channel = CHAN_PSEUDO;
13682
13683 /* Find spot in the private pointer array for new interface. */
13684 for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
13685 if (!pri->pvts[pvt_idx]) {
13686 break;
13687 }
13688 }
13689 if (pri->numchans == pvt_idx) {
13690 if (ARRAY_LEN(pri->pvts) <= pvt_idx) {
13691 ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
13692 return -1;
13693 }
13694
13695 /* Add new spot to the private pointer array. */
13696 pri->pvts[pvt_idx] = NULL;
13697 ++pri->numchans;
13698 }
13699
13700 pvt = ast_calloc(1, sizeof(*pvt));
13701 if (!pvt) {
13702 return -1;
13703 }
13705 if (!pvt->cc_params) {
13706 ast_free(pvt);
13707 return -1;
13708 }
13709 ast_mutex_init(&pvt->lock);
13710 for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
13711 pvt->subs[idx].dfd = -1;
13712 }
13713 pvt->buf_no = dahdi_pseudo_parms.buf_no;
13714 pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
13715 pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
13716 pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
13717
13718 chan = sig_pri_chan_new(pvt, pri, 0, 0, 0);
13719 if (!chan) {
13720 destroy_dahdi_pvt(pvt);
13721 return -1;
13722 }
13723 chan->no_b_channel = 1;
13724
13725 /*
13726 * Pseudo channel companding law.
13727 * Needed for outgoing call waiting calls.
13728 * XXX May need to make this determined by switchtype or user option.
13729 */
13730 pvt->law_default = DAHDI_LAW_ALAW;
13731
13732 pvt->sig = pri->sig;
13733 pvt->outsigmod = -1;
13734 pvt->pri = pri;
13735 pvt->sig_pvt = chan;
13736 pri->pvts[pvt_idx] = chan;
13737
13738 pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13739 if (pvt->subs[SUB_REAL].dfd < 0) {
13740 ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
13741 strerror(errno));
13742 destroy_dahdi_pvt(pvt);
13743 return -1;
13744 }
13745 memset(&bi, 0, sizeof(bi));
13746 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13747 if (!res) {
13748 pvt->bufsize = bi.bufsize;
13749 bi.txbufpolicy = pvt->buf_policy;
13750 bi.rxbufpolicy = pvt->buf_policy;
13751 bi.numbufs = pvt->buf_no;
13752 res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13753 if (res < 0) {
13755 "Unable to set buffer policy on no B channel interface: %s\n",
13756 strerror(errno));
13757 }
13758 } else
13760 "Unable to check buffer policy on no B channel interface: %s\n",
13761 strerror(errno));
13762
13763 --nobch_channel;
13764 if (CHAN_PSEUDO < nobch_channel) {
13765 nobch_channel = CHAN_PSEUDO - 1;
13766 }
13767 pvt->channel = nobch_channel;
13768 pvt->span = pri->span;
13769 chan->channel = pvt->channel;
13770
13771 dahdi_nobch_insert(pri, pvt);
13772
13773 return pvt_idx;
13774}
13775#endif /* defined(HAVE_PRI) */
13776
13777/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
13778 structures; it makes no attempt to safely copy regular channel private
13779 structures that might contain reference-counted object pointers and other
13780 scary bits
13781*/
13782static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src)
13783{
13784 struct dahdi_pvt *p;
13785 struct dahdi_bufferinfo bi;
13786 int res;
13787
13788 p = ast_malloc(sizeof(*p));
13789 if (!p) {
13790 return NULL;
13791 }
13792 *p = *src;
13793
13794 /* Must deep copy the cc_params. */
13796 if (!p->cc_params) {
13797 ast_free(p);
13798 return NULL;
13799 }
13801
13803 p->next = NULL;
13804 p->prev = NULL;
13805 ast_mutex_init(&p->lock);
13806 p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
13807 if (p->subs[SUB_REAL].dfd < 0) {
13808 ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
13810 return NULL;
13811 }
13812 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
13813 if (!res) {
13814 bi.txbufpolicy = src->buf_policy;
13815 bi.rxbufpolicy = src->buf_policy;
13816 bi.numbufs = src->buf_no;
13817 res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
13818 if (res < 0) {
13819 ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
13820 }
13821 } else
13822 ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
13823 p->destroy = 1;
13825 return p;
13826}
13827
13829 /*! Group matching mask. Zero if not specified. */
13831 /*! DAHDI channel to match with. -1 if not specified. */
13833 /*! Round robin saved search location index. (Valid if roundrobin TRUE) */
13835 /*! ISDN span where channels can be picked (Zero if not specified) */
13836 int span;
13837 /*! Analog channel distinctive ring cadence index. */
13839 /*! Dialing option. c/r/d if present and valid. */
13840 char opt;
13841 /*! TRUE if to search the channel list backwards. */
13843 /*! TRUE if search is done with round robin sequence. */
13845};
13846static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
13847{
13848 char *dest;
13849 char *s;
13850 int x;
13851 int res = 0;
13852 struct dahdi_pvt *p;
13853 char *subdir = NULL;
13855 AST_APP_ARG(group); /* channel/group token */
13856 //AST_APP_ARG(ext); /* extension token */
13857 //AST_APP_ARG(opts); /* options token */
13858 AST_APP_ARG(other); /* Any remaining unused arguments */
13859 );
13860
13861 /*
13862 * data is ---v
13863 * Dial(DAHDI/pseudo[/extension[/options]])
13864 * Dial(DAHDI/<channel#>[c|r<cadence#>|d][/extension[/options]])
13865 * Dial(DAHDI/<subdir>!<channel#>[c|r<cadence#>|d][/extension[/options]])
13866 * Dial(DAHDI/i<span>[/extension[/options]])
13867 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadence#>|d][/extension[/options]])
13868 *
13869 * i - ISDN span channel restriction.
13870 * Used by CC to ensure that the CC recall goes out the same span.
13871 * Also to make ISDN channel names dialable when the sequence number
13872 * is stripped off. (Used by DTMF attended transfer feature.)
13873 *
13874 * g - channel group allocation search forward
13875 * G - channel group allocation search backward
13876 * r - channel group allocation round robin search forward
13877 * R - channel group allocation round robin search backward
13878 *
13879 * c - Wait for DTMF digit to confirm answer
13880 * r<cadence#> - Set distinctive ring cadence number
13881 * d - Force bearer capability for ISDN/SS7 call to digital.
13882 */
13883
13884 if (data) {
13885 dest = ast_strdupa(data);
13886 } else {
13887 ast_log(LOG_WARNING, "Channel requested with no data\n");
13888 return NULL;
13889 }
13890 AST_NONSTANDARD_APP_ARGS(args, dest, '/');
13891 if (!args.argc || ast_strlen_zero(args.group)) {
13892 ast_log(LOG_WARNING, "No channel/group specified\n");
13893 return NULL;
13894 }
13895
13896 /* Initialize the output parameters */
13897 memset(param, 0, sizeof(*param));
13898 param->channelmatch = -1;
13899
13900 if (strchr(args.group, '!') != NULL) {
13901 char *prev = args.group;
13902 while ((s = strchr(prev, '!')) != NULL) {
13903 *s++ = '/';
13904 prev = s;
13905 }
13906 *(prev - 1) = '\0';
13907 subdir = args.group;
13908 args.group = prev;
13909 } else if (args.group[0] == 'i') {
13910 /* Extract the ISDN span channel restriction specifier. */
13911 res = sscanf(args.group + 1, "%30d", &x);
13912 if (res < 1) {
13913 ast_log(LOG_WARNING, "Unable to determine ISDN span for data %s\n", data);
13914 return NULL;
13915 }
13916 param->span = x;
13917
13918 /* Remove the ISDN span channel restriction specifier. */
13919 s = strchr(args.group, '-');
13920 if (!s) {
13921 /* Search all groups since we are ISDN span restricted. */
13922 return iflist;
13923 }
13924 args.group = s + 1;
13925 res = 0;
13926 }
13927 if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
13928 /* Retrieve the group number */
13929 s = args.group + 1;
13930 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13931 if (res < 1) {
13932 ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
13933 return NULL;
13934 }
13935 param->groupmatch = ((ast_group_t) 1 << x);
13936
13937 if (toupper(args.group[0]) == 'G') {
13938 if (args.group[0] == 'G') {
13939 param->backwards = 1;
13940 p = ifend;
13941 } else
13942 p = iflist;
13943 } else {
13944 if (ARRAY_LEN(round_robin) <= x) {
13945 ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
13946 x, data);
13947 return NULL;
13948 }
13949 if (args.group[0] == 'R') {
13950 param->backwards = 1;
13951 p = round_robin[x] ? round_robin[x]->prev : ifend;
13952 if (!p)
13953 p = ifend;
13954 } else {
13955 p = round_robin[x] ? round_robin[x]->next : iflist;
13956 if (!p)
13957 p = iflist;
13958 }
13959 param->roundrobin = 1;
13960 param->rr_starting_point = x;
13961 }
13962 } else {
13963 s = args.group;
13964 if (!strcasecmp(s, "pseudo")) {
13965 /* Special case for pseudo */
13966 x = CHAN_PSEUDO;
13967 param->channelmatch = x;
13968 } else {
13969 res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadence);
13970 if (res < 1) {
13971 ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
13972 return NULL;
13973 } else {
13974 param->channelmatch = x;
13975 }
13976 }
13977 if (subdir) {
13978 char path[PATH_MAX];
13979 struct stat stbuf;
13980
13981 snprintf(path, sizeof(path), "/dev/dahdi/%s/%d",
13982 subdir, param->channelmatch);
13983 if (stat(path, &stbuf) < 0) {
13984 ast_log(LOG_WARNING, "stat(%s) failed: %s\n",
13985 path, strerror(errno));
13986 return NULL;
13987 }
13988 if (!S_ISCHR(stbuf.st_mode)) {
13989 ast_log(LOG_ERROR, "%s: Not a character device file\n",
13990 path);
13991 return NULL;
13992 }
13993 param->channelmatch = minor(stbuf.st_rdev);
13994 }
13995
13996 p = iflist;
13997 }
13998
13999 if (param->opt == 'r' && res < 3) {
14000 ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
14001 param->opt = '\0';
14002 }
14003
14004 return p;
14005}
14006
14007static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap *cap,
14008 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
14009 const char *data, int *cause)
14010{
14011 int callwait = 0;
14012 struct dahdi_pvt *p;
14013 struct ast_channel *tmp = NULL;
14014 struct dahdi_pvt *exitpvt;
14015 int channelmatched = 0;
14016 int foundowner = 0;
14017 int groupmatched = 0;
14018#if defined(HAVE_PRI) || defined(HAVE_SS7)
14019 int transcapdigital = 0;
14020#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14021 struct dahdi_starting_point start;
14022 ast_callid callid = 0;
14023 int callid_created = ast_callid_threadstorage_auto(&callid);
14024
14026 p = determine_starting_point(data, &start);
14027 if (!p) {
14028 /* We couldn't determine a starting point, which likely means badly-formatted channel name. Abort! */
14030 ast_callid_threadstorage_auto_clean(callid, callid_created);
14031 return NULL;
14032 }
14033
14034 /* Search for an unowned channel */
14035 exitpvt = p;
14036 while (p && !tmp) {
14037 if (start.roundrobin)
14038 round_robin[start.rr_starting_point] = p;
14039
14040 if (p->owner) {
14041 foundowner++;
14042 }
14043
14044 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
14045 && available(&p, channelmatched)) {
14046 ast_debug(1, "Using channel %d\n", p->channel);
14047
14048 callwait = (p->owner != NULL);
14049#ifdef HAVE_OPENR2
14050 if (p->mfcr2) {
14051 ast_mutex_lock(&p->lock);
14052 if (p->mfcr2call) {
14054 ast_debug(1, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
14055 goto next;
14056 }
14057 p->mfcr2call = 1;
14059 }
14060#endif
14061 if (p->channel == CHAN_PSEUDO) {
14062 p = duplicate_pseudo(p);
14063 if (!p) {
14064 break;
14065 }
14066 }
14067
14068 p->distinctivering = 0;
14069 /* Make special notes */
14070 switch (start.opt) {
14071 case '\0':
14072 /* No option present. */
14073 break;
14074 case 'c':
14075 /* Confirm answer */
14076 p->confirmanswer = 1;
14077 break;
14078 case 'r':
14079 /* Distinctive ring */
14080 p->distinctivering = start.cadence;
14081 break;
14082 case 'd':
14083#if defined(HAVE_PRI) || defined(HAVE_SS7)
14084 /* If this is an ISDN call, make it digital */
14085 transcapdigital = AST_TRANS_CAP_DIGITAL;
14086#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
14087 break;
14088 default:
14089 ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, data);
14090 break;
14091 }
14092
14093 p->outgoing = 1;
14094 if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
14095 tmp = analog_request(p->sig_pvt, &callwait, requestor);
14096#ifdef HAVE_PRI
14097 } else if (dahdi_sig_pri_lib_handles(p->sig)) {
14098 /*
14099 * We already have the B channel reserved for this call. We
14100 * just need to make sure that dahdi_hangup() has completed
14101 * cleaning up before continuing.
14102 */
14103 ast_mutex_lock(&p->lock);
14105
14107 sizeof(p->dnid));
14108 tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, assignedids, requestor, transcapdigital);
14109#endif
14110#if defined(HAVE_SS7)
14111 } else if (p->sig == SIG_SS7) {
14112 tmp = sig_ss7_request(p->sig_pvt, SIG_SS7_DEFLAW, assignedids, requestor, transcapdigital);
14113#endif /* defined(HAVE_SS7) */
14114 } else {
14115 tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, assignedids, requestor, callid);
14116 }
14117 if (!tmp) {
14118 p->outgoing = 0;
14119#if defined(HAVE_PRI)
14120 switch (p->sig) {
14122#if defined(HAVE_PRI_CALL_WAITING)
14123 if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
14124 ((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
14125 ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
14126 }
14127#endif /* defined(HAVE_PRI_CALL_WAITING) */
14128 /*
14129 * This should be the last thing to clear when we are done with
14130 * the channel.
14131 */
14132 ((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
14133 break;
14134 default:
14135 break;
14136 }
14137#endif /* defined(HAVE_PRI) */
14138 } else {
14139 snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", data);
14140 }
14141 break;
14142 }
14143#ifdef HAVE_OPENR2
14144next:
14145#endif
14146 if (start.backwards) {
14147 p = p->prev;
14148 if (!p)
14149 p = ifend;
14150 } else {
14151 p = p->next;
14152 if (!p)
14153 p = iflist;
14154 }
14155 /* stop when you roll to the one that we started from */
14156 if (p == exitpvt)
14157 break;
14158 }
14161 if (cause && !tmp) {
14162 if (callwait || (channelmatched && foundowner)) {
14163 *cause = AST_CAUSE_BUSY;
14164 } else if (groupmatched) {
14165 *cause = AST_CAUSE_CONGESTION;
14166 } else {
14167 /*
14168 * We did not match any channel requested.
14169 * Dialplan error requesting non-existant channel?
14170 */
14171 }
14172 }
14173
14174 ast_callid_threadstorage_auto_clean(callid, callid_created);
14175 return tmp;
14176}
14177
14178/*!
14179 * \internal
14180 * \brief Determine the device state for a given DAHDI device if we can.
14181 * \since 1.8
14182 *
14183 * \param data DAHDI device name after "DAHDI/".
14184 *
14185 * \retval device_state enum ast_device_state value.
14186 * \retval AST_DEVICE_UNKNOWN if we could not determine the device's state.
14187 */
14188static int dahdi_devicestate(const char *data)
14189{
14190#if defined(HAVE_PRI)
14191 const char *device;
14192 unsigned span;
14193 int res;
14194
14195 device = data;
14196
14197 if (*device != 'I') {
14198 /* The request is not for an ISDN span device. */
14199 return AST_DEVICE_UNKNOWN;
14200 }
14201 res = sscanf(device, "I%30u", &span);
14202 if (res != 1 || !span || NUM_SPANS < span) {
14203 /* Bad format for ISDN span device name. */
14204 return AST_DEVICE_UNKNOWN;
14205 }
14206 device = strchr(device, '/');
14207 if (!device) {
14208 /* Bad format for ISDN span device name. */
14209 return AST_DEVICE_UNKNOWN;
14210 }
14211
14212 /*
14213 * Since there are currently no other span devstate's defined,
14214 * it must be congestion.
14215 */
14216#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14217 ++device;
14218 if (!strcmp(device, "congestion"))
14219#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14220 {
14221 return pris[span - 1].pri.congestion_devstate;
14222 }
14223#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
14224 else if (!strcmp(device, "threshold")) {
14225 return pris[span - 1].pri.threshold_devstate;
14226 }
14227 return AST_DEVICE_UNKNOWN;
14228#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
14229#else
14230 return AST_DEVICE_UNKNOWN;
14231#endif /* defined(HAVE_PRI) */
14232}
14233
14234/*!
14235 * \brief Callback made when dial failed to get a channel out of dahdi_request().
14236 * \since 1.8
14237 *
14238 * \param inbound Incoming asterisk channel.
14239 * \param dest Same dial string passed to dahdi_request().
14240 * \param callback Callback into CC core to announce a busy channel available for CC.
14241 *
14242 * \details
14243 * This callback acts like a forked dial with all prongs of the fork busy.
14244 * Essentially, for each channel that could have taken the call, indicate that
14245 * it is busy.
14246 *
14247 * \retval 0 on success.
14248 * \retval -1 on error.
14249 */
14250static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
14251{
14252 struct dahdi_pvt *p;
14253 struct dahdi_pvt *exitpvt;
14254 struct dahdi_starting_point start;
14255 int groupmatched = 0;
14256 int channelmatched = 0;
14257
14259 p = determine_starting_point(dest, &start);
14260 if (!p) {
14262 return -1;
14263 }
14264 exitpvt = p;
14265 for (;;) {
14266 if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
14267 /* We found a potential match. call the callback */
14268 struct ast_str *device_name;
14269 char *dash;
14270 const char *monitor_type;
14271 char dialstring[AST_CHANNEL_NAME];
14272 char full_device_name[AST_CHANNEL_NAME];
14273
14276 break;
14280#if defined(HAVE_PRI)
14282 /*
14283 * ISDN is in a trunk busy condition so we need to monitor
14284 * the span congestion device state.
14285 */
14286 snprintf(full_device_name, sizeof(full_device_name),
14287 "DAHDI/I%d/congestion", p->pri->span);
14288 } else
14289#endif /* defined(HAVE_PRI) */
14290 {
14291#if defined(HAVE_PRI)
14292 device_name = create_channel_name(p, 1, "");
14293#else
14294 device_name = create_channel_name(p);
14295#endif /* defined(HAVE_PRI) */
14296 snprintf(full_device_name, sizeof(full_device_name), "DAHDI/%s",
14297 device_name ? ast_str_buffer(device_name) : "");
14298 ast_free(device_name);
14299 /*
14300 * The portion after the '-' in the channel name is either a random
14301 * number, a sequence number, or a subchannel number. None are
14302 * necessary so strip them off.
14303 */
14304 dash = strrchr(full_device_name, '-');
14305 if (dash) {
14306 *dash = '\0';
14307 }
14308 }
14309 snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
14310
14311 /*
14312 * Analog can only do generic monitoring.
14313 * ISDN is in a trunk busy condition and any "device" is going
14314 * to be busy until a B channel becomes available. The generic
14315 * monitor can do this task.
14316 */
14317 monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
14318 callback(inbound,
14319#if defined(HAVE_PRI)
14320 p->pri ? p->pri->cc_params : p->cc_params,
14321#else
14322 p->cc_params,
14323#endif /* defined(HAVE_PRI) */
14324 monitor_type, full_device_name, dialstring, NULL);
14325 break;
14326 }
14327 }
14328 p = start.backwards ? p->prev : p->next;
14329 if (!p) {
14330 p = start.backwards ? ifend : iflist;
14331 }
14332 if (p == exitpvt) {
14333 break;
14334 }
14335 }
14337 return 0;
14338}
14339
14340#if defined(HAVE_SS7)
14341static void dahdi_ss7_message(struct ss7 *ss7, char *s)
14342{
14343 int i;
14344
14345 if (ss7) {
14346 for (i = 0; i < NUM_SPANS; i++) {
14347 if (linksets[i].ss7.ss7 == ss7) {
14348 ast_verbose_callid(0, "[%d] %s", i + 1, s);
14349 return;
14350 }
14351 }
14352 }
14353 ast_verbose_callid(0, "%s", s);
14354}
14355#endif /* defined(HAVE_SS7) */
14356
14357#if defined(HAVE_SS7)
14358static void dahdi_ss7_error(struct ss7 *ss7, char *s)
14359{
14360 int i;
14361
14362 if (ss7) {
14363 for (i = 0; i < NUM_SPANS; i++) {
14364 if (linksets[i].ss7.ss7 == ss7) {
14365 ast_log_callid(LOG_ERROR, 0, "[%d] %s", i + 1, s);
14366 return;
14367 }
14368 }
14369 }
14370 ast_log_callid(LOG_ERROR, 0, "%s", s);
14371}
14372#endif /* defined(HAVE_SS7) */
14373
14374#if defined(HAVE_OPENR2)
14375static void *mfcr2_monitor(void *data)
14376{
14377 struct dahdi_mfcr2 *mfcr2 = data;
14378 struct dahdi_pvt *pvt;
14379
14380 /* we should be using pthread_key_create
14381 and allocate pollers dynamically.
14382 I think do_monitor() could be leaking, since it
14383 could be cancelled at any time and is not
14384 using thread keys, why?, */
14385 struct pollfd pollers[ARRAY_LEN(mfcr2->pvts)];
14386 int res = 0;
14387 int i = 0;
14388 int oldstate = 0;
14389 int quit_loop = 0;
14390 int maxsleep = 20;
14391 int was_idle = 0;
14392 int pollsize = 0;
14393 /* now that we're ready to get calls, unblock our side and
14394 get current line state */
14395 for (i = 0; i < mfcr2->numchans; i++) {
14396 pvt = mfcr2->pvts[i];
14397 if (!pvt) {
14398 continue;
14399 }
14400 openr2_chan_set_idle(pvt->r2chan);
14401 openr2_chan_handle_cas(pvt->r2chan);
14402 }
14403 while (1) {
14404 /* we trust here that the mfcr2 channel list will not ever change once
14405 the module is loaded */
14406 pollsize = 0;
14407 for (i = 0; i < mfcr2->numchans; i++) {
14408 pollers[i].revents = 0;
14409 pollers[i].events = 0;
14410 pvt = mfcr2->pvts[i];
14411 if (!pvt) {
14412 continue;
14413 }
14414 if (pvt->owner) {
14415 continue;
14416 }
14417 if (mfcr2->nodev) {
14418 continue;
14419 }
14420 if (!pvt->r2chan) {
14421 ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
14422 quit_loop = 1;
14423 break;
14424 }
14425 openr2_chan_enable_read(pvt->r2chan);
14426 pollers[i].events = POLLIN | POLLPRI;
14427 pollers[i].fd = pvt->subs[SUB_REAL].dfd;
14428 pollsize++;
14429 }
14430 if (quit_loop) {
14431 break;
14432 }
14433 if (pollsize == 0) {
14434 if (!was_idle) {
14435 ast_debug(1, "Monitor thread going idle since everybody has an owner\n");
14436 was_idle = 1;
14437 }
14438 poll(NULL, 0, maxsleep);
14439 continue;
14440 }
14441 was_idle = 0;
14442 /* probably poll() is a valid cancel point, lets just be on the safe side
14443 by calling pthread_testcancel */
14444 pthread_testcancel();
14445 res = poll(pollers, mfcr2->numchans, maxsleep);
14446 pthread_testcancel();
14447 if ((res < 0) && (errno != EINTR)) {
14448 ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
14449 break;
14450 }
14451 /* do we want to allow to cancel while processing events? */
14452 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
14453 for (i = 0; i < mfcr2->numchans; i++) {
14454 pvt = mfcr2->pvts[i];
14455 if (!pvt) {
14456 continue;
14457 }
14458 if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
14459 openr2_chan_process_event(pvt->r2chan);
14460 }
14461 }
14462 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14463 }
14464 ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
14465 return 0;
14466}
14467#endif /* HAVE_OPENR2 */
14468
14469#if defined(HAVE_PRI)
14470static void dahdi_pri_message(struct pri *pri, char *s)
14471{
14472 int x;
14473 int y;
14474 int dchan = -1;
14475 int span = -1;
14476 int dchancount = 0;
14477
14478 if (pri) {
14479 for (x = 0; x < NUM_SPANS; x++) {
14480 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14481 if (pris[x].pri.dchans[y]) {
14482 dchancount++;
14483 }
14484
14485 if (pris[x].pri.dchans[y] == pri) {
14486 dchan = y;
14487 }
14488 }
14489 if (dchan >= 0) {
14490 span = x;
14491 break;
14492 }
14493 dchancount = 0;
14494 }
14495 if (-1 < span) {
14496 if (1 < dchancount) {
14497 ast_verbose_callid(0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14498 } else {
14499 ast_verbose_callid(0, "PRI Span: %d %s", span + 1, s);
14500 }
14501 } else {
14502 ast_verbose_callid(0, "PRI Span: ? %s", s);
14503 }
14504 } else {
14505 ast_verbose_callid(0, "PRI Span: ? %s", s);
14506 }
14507
14508 ast_mutex_lock(&pridebugfdlock);
14509
14510 if (pridebugfd >= 0) {
14511 if (write(pridebugfd, s, strlen(s)) < 0) {
14512 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14513 }
14514 }
14515
14516 ast_mutex_unlock(&pridebugfdlock);
14517}
14518#endif /* defined(HAVE_PRI) */
14519
14520#if defined(HAVE_PRI)
14521static void dahdi_pri_error(struct pri *pri, char *s)
14522{
14523 int x;
14524 int y;
14525 int dchan = -1;
14526 int span = -1;
14527 int dchancount = 0;
14528
14529 if (pri) {
14530 for (x = 0; x < NUM_SPANS; x++) {
14531 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14532 if (pris[x].pri.dchans[y]) {
14533 dchancount++;
14534 }
14535
14536 if (pris[x].pri.dchans[y] == pri) {
14537 dchan = y;
14538 }
14539 }
14540 if (dchan >= 0) {
14541 span = x;
14542 break;
14543 }
14544 dchancount = 0;
14545 }
14546 if (-1 < span) {
14547 if (1 < dchancount) {
14548 ast_log_callid(LOG_ERROR, 0, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s);
14549 } else {
14550 ast_log_callid(LOG_ERROR, 0, "PRI Span: %d %s", span + 1, s);
14551 }
14552 } else {
14553 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14554 }
14555 } else {
14556 ast_log_callid(LOG_ERROR, 0, "PRI Span: ? %s", s);
14557 }
14558
14559 ast_mutex_lock(&pridebugfdlock);
14560
14561 if (pridebugfd >= 0) {
14562 if (write(pridebugfd, s, strlen(s)) < 0) {
14563 ast_log_callid(LOG_WARNING, 0, "write() failed: %s\n", strerror(errno));
14564 }
14565 }
14566
14567 ast_mutex_unlock(&pridebugfdlock);
14568}
14569#endif /* defined(HAVE_PRI) */
14570
14571#if defined(HAVE_PRI)
14572static int prepare_pri(struct dahdi_pri *pri)
14573{
14574 int i, res, x;
14575 struct dahdi_params p;
14576 struct dahdi_bufferinfo bi;
14577 struct dahdi_spaninfo si;
14578
14579 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
14580 if (!pri->dchannels[i])
14581 break;
14582 if (pri->pri.fds[i] >= 0) {
14583 /* A partial range addition. Not a complete setup. */
14584 break;
14585 }
14586 pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
14587 if ((pri->pri.fds[i] < 0)) {
14588 ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
14589 pri->pri.fds[i], strerror(errno));
14590 return -1;
14591 }
14592 x = pri->dchannels[i];
14593 res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
14594 if (res) {
14595 dahdi_close_pri_fd(pri, i);
14596 ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
14597 return -1;
14598 }
14599 memset(&p, 0, sizeof(p));
14600 res = ioctl(pri->pri.fds[i], DAHDI_GET_PARAMS, &p);
14601 if (res) {
14602 dahdi_close_pri_fd(pri, i);
14603 ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
14604 return -1;
14605 }
14606 if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
14607 dahdi_close_pri_fd(pri, i);
14608 ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
14609 return -1;
14610 }
14611 memset(&si, 0, sizeof(si));
14612 res = ioctl(pri->pri.fds[i], DAHDI_SPANSTAT, &si);
14613 if (res) {
14614 dahdi_close_pri_fd(pri, i);
14615 ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
14616 }
14617 if (!si.alarms) {
14618 pri_event_noalarm(&pri->pri, i, 1);
14619 } else {
14620 pri_event_alarm(&pri->pri, i, 1);
14621 }
14622 memset(&bi, 0, sizeof(bi));
14623 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
14624 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
14625 bi.numbufs = 32;
14626 bi.bufsize = 1024;
14627 if (ioctl(pri->pri.fds[i], DAHDI_SET_BUFINFO, &bi)) {
14628 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
14629 dahdi_close_pri_fd(pri, i);
14630 return -1;
14631 }
14632 pri->pri.dchan_logical_span[i] = pris[p.spanno - 1].prilogicalspan;
14633 }
14634 return 0;
14635}
14636#endif /* defined(HAVE_PRI) */
14637
14638#if defined(HAVE_PRI)
14639static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
14640{
14641 int which, span;
14642 char *ret = NULL;
14643
14644 if (pos != rpos)
14645 return ret;
14646
14647 for (which = span = 0; span < NUM_SPANS; span++) {
14648 if (pris[span].pri.pri && ++which > state) {
14649 if (ast_asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
14650 ret = NULL;
14651 }
14652 break;
14653 }
14654 }
14655 return ret;
14656}
14657#endif /* defined(HAVE_PRI) */
14658
14659#if defined(HAVE_PRI)
14660static char *complete_span_4(const char *line, const char *word, int pos, int state)
14661{
14662 return complete_span_helper(line,word,pos,state,3);
14663}
14664#endif /* defined(HAVE_PRI) */
14665
14666#if defined(HAVE_PRI)
14667static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14668{
14669 int myfd;
14670 switch (cmd) {
14671 case CLI_INIT:
14672 e->command = "pri set debug file";
14673 e->usage = "Usage: pri set debug file [output-file]\n"
14674 " Sends PRI debug output to the specified output file\n";
14675 return NULL;
14676 case CLI_GENERATE:
14677 return NULL;
14678 }
14679 if (a->argc < 5)
14680 return CLI_SHOWUSAGE;
14681
14682 if (ast_strlen_zero(a->argv[4]))
14683 return CLI_SHOWUSAGE;
14684
14685 myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
14686 if (myfd < 0) {
14687 ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
14688 return CLI_SUCCESS;
14689 }
14690
14691 ast_mutex_lock(&pridebugfdlock);
14692
14693 if (pridebugfd >= 0)
14694 close(pridebugfd);
14695
14696 pridebugfd = myfd;
14697 ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
14698 ast_mutex_unlock(&pridebugfdlock);
14699 ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
14700 return CLI_SUCCESS;
14701}
14702#endif /* defined(HAVE_PRI) */
14703
14704#if defined(HAVE_PRI)
14705static int action_pri_debug_file_set(struct mansession *s, const struct message *m)
14706{
14707 const char *output_file = astman_get_header(m, "File");
14708 int myfd;
14709
14710 if (ast_strlen_zero(output_file)) {
14711 astman_send_error(s, m, "Action must define a 'File'");
14712 }
14713
14714 myfd = open(output_file, O_CREAT|O_WRONLY, AST_FILE_MODE);
14715 if (myfd < 0) {
14716 astman_send_error(s, m, "Unable to open requested file for writing");
14717 return 0;
14718 }
14719
14720 ast_mutex_lock(&pridebugfdlock);
14721
14722 if (pridebugfd >= 0) {
14723 close(pridebugfd);
14724 }
14725
14726 pridebugfd = myfd;
14727 ast_copy_string(pridebugfilename, output_file, sizeof(pridebugfilename));
14728 ast_mutex_unlock(&pridebugfdlock);
14729 astman_send_ack(s, m, "PRI debug output will now be sent to requested file.");
14730
14731 return 0;
14732}
14733#endif /* defined(HAVE_PRI) */
14734
14735#if defined(HAVE_PRI)
14736static int action_pri_debug_file_unset(struct mansession *s, const struct message *m)
14737{
14738 ast_mutex_lock(&pridebugfdlock);
14739
14740 if (pridebugfd >= 0) {
14741 close(pridebugfd);
14742 }
14743
14744 pridebugfd = -1;
14745
14746 ast_mutex_unlock(&pridebugfdlock);
14747
14748 astman_send_ack(s, m, "PRI Debug output to file disabled");
14749 return 0;
14750}
14751#endif /* defined(HAVE_PRI) */
14752
14753#if defined(HAVE_PRI)
14754static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14755{
14756 int span;
14757 int x;
14758 int debugmask = 0;
14759 int level = 0;
14760 switch (cmd) {
14761 case CLI_INIT:
14762 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";
14763 e->usage =
14764 "Usage: pri set debug {<level>|on|off|hex|intense} span <span>\n"
14765 " Enables debugging on a given PRI span\n"
14766 " Level is a bitmap of the following values:\n"
14767 " 1 General debugging incl. state changes\n"
14768 " 2 Decoded Q.931 messages\n"
14769 " 4 Decoded Q.921 messages\n"
14770 " 8 Raw hex dumps of Q.921 frames\n"
14771 " on - equivalent to 3\n"
14772 " hex - equivalent to 8\n"
14773 " intense - equivalent to 15\n";
14774 return NULL;
14775 case CLI_GENERATE:
14776 return complete_span_4(a->line, a->word, a->pos, a->n);
14777 }
14778 if (a->argc < 6) {
14779 return CLI_SHOWUSAGE;
14780 }
14781
14782 if (!strcasecmp(a->argv[3], "on")) {
14783 level = 3;
14784 } else if (!strcasecmp(a->argv[3], "off")) {
14785 level = 0;
14786 } else if (!strcasecmp(a->argv[3], "intense")) {
14787 level = 15;
14788 } else if (!strcasecmp(a->argv[3], "hex")) {
14789 level = 8;
14790 } else {
14791 level = atoi(a->argv[3]);
14792 }
14793 span = atoi(a->argv[5]);
14794 if ((span < 1) || (span > NUM_SPANS)) {
14795 ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS);
14796 return CLI_SUCCESS;
14797 }
14798 if (!pris[span-1].pri.pri) {
14799 ast_cli(a->fd, "No PRI running on span %d\n", span);
14800 return CLI_SUCCESS;
14801 }
14802
14803 if (level & 1) debugmask |= SIG_PRI_DEBUG_NORMAL;
14804 if (level & 2) debugmask |= PRI_DEBUG_Q931_DUMP;
14805 if (level & 4) debugmask |= PRI_DEBUG_Q921_DUMP;
14806 if (level & 8) debugmask |= PRI_DEBUG_Q921_RAW;
14807
14808 /* Set debug level in libpri */
14809 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14810 if (pris[span - 1].pri.dchans[x]) {
14811 pri_set_debug(pris[span - 1].pri.dchans[x], debugmask);
14812 }
14813 }
14814 if (level == 0) {
14815 /* Close the debugging file if it's set */
14816 ast_mutex_lock(&pridebugfdlock);
14817 if (0 <= pridebugfd) {
14818 close(pridebugfd);
14819 pridebugfd = -1;
14820 ast_cli(a->fd, "Disabled PRI debug output to file '%s'\n",
14821 pridebugfilename);
14822 }
14823 ast_mutex_unlock(&pridebugfdlock);
14824 }
14825 pris[span - 1].pri.debug = (level) ? 1 : 0;
14826 ast_cli(a->fd, "%s debugging on span %d\n", (level) ? "Enabled" : "Disabled", span);
14827 return CLI_SUCCESS;
14828}
14829#endif /* defined(HAVE_PRI) */
14830
14831#if defined(HAVE_PRI)
14832static int action_pri_debug_set(struct mansession *s, const struct message *m)
14833{
14834 const char *level = astman_get_header(m, "Level");
14835 const char *span = astman_get_header(m, "Span");
14836 int level_val;
14837 int span_val;
14838 int x;
14839 int debugmask = 0;
14840
14841 if (ast_strlen_zero(level)) {
14842 astman_send_error(s, m, "'Level' was not specified");
14843 return 0;
14844 }
14845
14846 if (ast_strlen_zero(span)) {
14847 astman_send_error(s, m, "'Span' was not specified");
14848 return 0;
14849 }
14850
14851 if (!strcasecmp(level, "on")) {
14852 level_val = 3;
14853 } else if (!strcasecmp(level, "off")) {
14854 level_val = 0;
14855 } else if (!strcasecmp(level, "intense")) {
14856 level_val = 15;
14857 } else if (!strcasecmp(level, "hex")) {
14858 level_val = 8;
14859 } else {
14860 if (sscanf(level, "%30d", &level_val) != 1) {
14861 astman_send_error(s, m, "Invalid value for 'Level'");
14862 return 0;
14863 }
14864 }
14865
14866 if (sscanf(span, "%30d", &span_val) != 1) {
14867 astman_send_error(s, m, "Invalid value for 'Span'");
14868 }
14869
14870 if ((span_val < 1) || (span_val > NUM_SPANS)) {
14871 const char *id = astman_get_header(m, "ActionID");
14872 char id_text[256] = "";
14873
14874 if (!ast_strlen_zero(id)) {
14875 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
14876 }
14877
14878 astman_append(s, "Response: Error\r\n"
14879 "%s" /* id_text */
14880 "Message: Invalid span '%s' - Should be a number from 1 to %d\r\n"
14881 "\r\n",
14882 id_text,
14883 span, NUM_SPANS);
14884
14885 return 0;
14886 }
14887
14888 if (!pris[span_val-1].pri.pri) {
14889 astman_send_error(s, m, "No PRI running on requested span");
14890 return 0;
14891 }
14892
14893 if (level_val & 1) {
14894 debugmask |= SIG_PRI_DEBUG_NORMAL;
14895 }
14896 if (level_val & 2) {
14897 debugmask |= PRI_DEBUG_Q931_DUMP;
14898 }
14899 if (level_val & 4) {
14900 debugmask |= PRI_DEBUG_Q921_DUMP;
14901 }
14902 if (level_val & 8) {
14903 debugmask |= PRI_DEBUG_Q921_RAW;
14904 }
14905
14906 /* Set debug level in libpri */
14907 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
14908 if (pris[span_val - 1].pri.dchans[x]) {
14909 pri_set_debug(pris[span_val - 1].pri.dchans[x], debugmask);
14910 }
14911 }
14912
14913 pris[span_val - 1].pri.debug = (level_val) ? 1 : 0;
14914 astman_send_ack(s, m, "Debug level set for requested span");
14915
14916 return 0;
14917}
14918#endif /* defined(HAVE_PRI) */
14919
14920#if defined(HAVE_PRI)
14921#if defined(HAVE_PRI_SERVICE_MESSAGES)
14922static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
14923{
14924 unsigned *why;
14925 int channel;
14926 int trunkgroup;
14927 int x, y, fd = a->fd;
14928 int interfaceid = 0;
14929 char db_chan_name[20], db_answer[15];
14930 struct dahdi_pvt *tmp;
14931 struct dahdi_pri *pri;
14932
14933 if (a->argc < 5 || a->argc > 6)
14934 return CLI_SHOWUSAGE;
14935 if (strchr(a->argv[4], ':')) {
14936 if (sscanf(a->argv[4], "%30d:%30d", &trunkgroup, &channel) != 2)
14937 return CLI_SHOWUSAGE;
14938 if ((trunkgroup < 1) || (channel < 1))
14939 return CLI_SHOWUSAGE;
14940 pri = NULL;
14941 for (x=0;x<NUM_SPANS;x++) {
14942 if (pris[x].pri.trunkgroup == trunkgroup) {
14943 pri = pris + x;
14944 break;
14945 }
14946 }
14947 if (!pri) {
14948 ast_cli(fd, "No such trunk group %d\n", trunkgroup);
14949 return CLI_FAILURE;
14950 }
14951 } else
14952 channel = atoi(a->argv[4]);
14953
14954 if (a->argc == 6)
14955 interfaceid = atoi(a->argv[5]);
14956
14957 /* either servicing a D-Channel */
14958 for (x = 0; x < NUM_SPANS; x++) {
14959 for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) {
14960 if (pris[x].dchannels[y] == channel) {
14961 pri = pris + x;
14962 if (pri->pri.enable_service_message_support) {
14963 ast_mutex_lock(&pri->pri.lock);
14964 pri_maintenance_service(pri->pri.pri, interfaceid, -1, changestatus);
14965 ast_mutex_unlock(&pri->pri.lock);
14966 } else {
14967 ast_cli(fd,
14968 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14969 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14970 }
14971 return CLI_SUCCESS;
14972 }
14973 }
14974 }
14975
14976 /* or servicing a B-Channel */
14978 for (tmp = iflist; tmp; tmp = tmp->next) {
14979 if (tmp->pri && tmp->channel == channel) {
14981 ast_mutex_lock(&tmp->pri->lock);
14982 if (!tmp->pri->enable_service_message_support) {
14983 ast_mutex_unlock(&tmp->pri->lock);
14984 ast_cli(fd,
14985 "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n"
14986 "\tNote only 4ESS, 5ESS, and NI2 switch types are supported.\n\n");
14987 return CLI_SUCCESS;
14988 }
14989 snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
14990 why = &((struct sig_pri_chan *) tmp->sig_pvt)->service_status;
14991 switch(changestatus) {
14992 case 0: /* enable */
14993 /* Near end wants to be in service now. */
14994 ast_db_del(db_chan_name, SRVST_DBKEY);
14995 *why &= ~SRVST_NEAREND;
14996 if (*why) {
14997 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
14998 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
14999 } else {
15000 dahdi_pri_update_span_devstate(tmp->pri);
15001 }
15002 break;
15003 /* case 1: -- loop */
15004 case 2: /* disable */
15005 /* Near end wants to be out-of-service now. */
15006 ast_db_del(db_chan_name, SRVST_DBKEY);
15007 *why |= SRVST_NEAREND;
15008 snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS, *why);
15009 ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
15010 dahdi_pri_update_span_devstate(tmp->pri);
15011 break;
15012 /* case 3: -- continuity */
15013 /* case 4: -- shutdown */
15014 default:
15015 ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
15016 break;
15017 }
15018 pri_maintenance_bservice(tmp->pri->pri, tmp->sig_pvt, changestatus);
15019 ast_mutex_unlock(&tmp->pri->lock);
15020 return CLI_SUCCESS;
15021 }
15022 }
15024
15025 ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
15026 return CLI_FAILURE;
15027}
15028
15029static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15030{
15031 switch (cmd) {
15032 case CLI_INIT:
15033 e->command = "pri service enable channel";
15034 e->usage =
15035 "Usage: pri service enable channel <channel> [<interface id>]\n"
15036 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15037 " to restore a channel to service, with optional interface id\n"
15038 " as agreed upon with remote switch operator\n";
15039 return NULL;
15040 case CLI_GENERATE:
15041 return NULL;
15042 }
15043 return handle_pri_service_generic(e, cmd, a, 0);
15044}
15045
15046static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15047{
15048 switch (cmd) {
15049 case CLI_INIT:
15050 e->command = "pri service disable channel";
15051 e->usage =
15052 "Usage: pri service disable channel <chan num> [<interface id>]\n"
15053 " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
15054 " to remove a channel from service, with optional interface id\n"
15055 " as agreed upon with remote switch operator\n";
15056 return NULL;
15057 case CLI_GENERATE:
15058 return NULL;
15059 }
15060 return handle_pri_service_generic(e, cmd, a, 2);
15061}
15062#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15063#endif /* defined(HAVE_PRI) */
15064
15065#if defined(HAVE_PRI)
15066static char *handle_pri_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15067{
15068 int span;
15069
15070 switch (cmd) {
15071 case CLI_INIT:
15072 e->command = "pri show channels";
15073 e->usage =
15074 "Usage: pri show channels\n"
15075 " Displays PRI channel information such as the current mapping\n"
15076 " of DAHDI B channels to Asterisk channel names and which calls\n"
15077 " are on hold or call-waiting. Calls on hold or call-waiting\n"
15078 " are not associated with any B channel.\n";
15079 return NULL;
15080 case CLI_GENERATE:
15081 return NULL;
15082 }
15083
15084 if (a->argc != 3)
15085 return CLI_SHOWUSAGE;
15086
15088 for (span = 0; span < NUM_SPANS; ++span) {
15089 if (pris[span].pri.pri) {
15090 sig_pri_cli_show_channels(a->fd, &pris[span].pri);
15091 }
15092 }
15093 return CLI_SUCCESS;
15094}
15095#endif /* defined(HAVE_PRI) */
15096
15097#if defined(HAVE_PRI)
15098static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15099{
15100 int span;
15101
15102 switch (cmd) {
15103 case CLI_INIT:
15104 e->command = "pri show spans";
15105 e->usage =
15106 "Usage: pri show spans\n"
15107 " Displays PRI span information\n";
15108 return NULL;
15109 case CLI_GENERATE:
15110 return NULL;
15111 }
15112
15113 if (a->argc != 3)
15114 return CLI_SHOWUSAGE;
15115
15116 for (span = 0; span < NUM_SPANS; span++) {
15117 if (pris[span].pri.pri) {
15118 sig_pri_cli_show_spans(a->fd, span + 1, &pris[span].pri);
15119 }
15120 }
15121 return CLI_SUCCESS;
15122}
15123#endif /* defined(HAVE_PRI) */
15124
15125#if defined(HAVE_PRI)
15126#define container_of(ptr, type, member) \
15127 ((type *)((char *)(ptr) - offsetof(type, member)))
15128/*!
15129 * \internal
15130 * \brief Destroy a D-Channel of a PRI span
15131 * \since 12
15132 *
15133 * \param pri the pri span
15134 *
15135 * Shuts down a span and destroys its D-Channel. Further destruction
15136 * of the B-channels using dahdi_destroy_channel() would probably be required
15137 * for the B-Channels.
15138 */
15139static void pri_destroy_span(struct sig_pri_span *pri)
15140{
15141 int i;
15142 int res;
15143 int cancel_code;
15144 struct dahdi_pri* dahdi_pri;
15145 pthread_t master = pri->master;
15146
15147 if (!master || (master == AST_PTHREADT_NULL)) {
15148 return;
15149 }
15150 ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
15151 for (i = 0; i < pri->numchans; i++) {
15152 int channel;
15153 struct sig_pri_chan *pvt = pri->pvts[i];
15154
15155 if (!pvt) {
15156 continue;
15157 }
15158 channel = pvt->channel;
15159 ast_debug(2, "About to destroy B-channel %d.\n", channel);
15161 }
15162
15163 cancel_code = pthread_cancel(master);
15164 pthread_kill(master, SIGURG);
15165 ast_debug(4,
15166 "Waiting to join thread of span %d "
15167 "with pid=%p cancel_code=%d\n",
15168 pri->span, (void *)master, cancel_code);
15169 res = pthread_join(master, NULL);
15170 if (res != 0) {
15171 ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
15172 }
15174
15175 /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
15176 dahdi_pri = container_of(pri, struct dahdi_pri, pri);
15177 for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
15178 ast_debug(4, "closing pri_fd %d\n", i);
15179 dahdi_close_pri_fd(dahdi_pri, i);
15180 dahdi_pri->dchannels[i] = 0;
15181 }
15183 ast_debug(1, "PRI span %d destroyed\n", pri->span);
15184}
15185
15186static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
15187 struct ast_cli_args *a)
15188{
15189 int span;
15190 int res;
15191 struct sig_pri_span *pri;
15192
15193 switch (cmd) {
15194 case CLI_INIT:
15195 e->command = "pri destroy span";
15196 e->usage =
15197 "Usage: pri destroy span <span>\n"
15198 " Destroys D-channel of span and its B-channels.\n"
15199 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15200 return NULL;
15201 case CLI_GENERATE:
15202 return complete_span_4(a->line, a->word, a->pos, a->n);
15203 }
15204
15205 if (a->argc < 4) {
15206 return CLI_SHOWUSAGE;
15207 }
15208 res = sscanf(a->argv[3], "%30d", &span);
15209 if ((res != 1) || span < 1 || span > NUM_SPANS) {
15210 ast_cli(a->fd,
15211 "Invalid span '%s'. Should be a number from %d to %d\n",
15212 a->argv[3], 1, NUM_SPANS);
15213 return CLI_SUCCESS;
15214 }
15215 pri = &pris[span - 1].pri;
15216 if (!pri->pri) {
15217 ast_cli(a->fd, "No PRI running on span %d\n", span);
15218 return CLI_SUCCESS;
15219 }
15220
15221 pri_destroy_span(pri);
15222 return CLI_SUCCESS;
15223}
15224
15225#endif /* defined(HAVE_PRI) */
15226
15227#if defined(HAVE_PRI)
15228static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15229{
15230 int span;
15231
15232 switch (cmd) {
15233 case CLI_INIT:
15234 e->command = "pri show span";
15235 e->usage =
15236 "Usage: pri show span <span>\n"
15237 " Displays PRI Information on a given PRI span\n";
15238 return NULL;
15239 case CLI_GENERATE:
15240 return complete_span_4(a->line, a->word, a->pos, a->n);
15241 }
15242
15243 if (a->argc < 4)
15244 return CLI_SHOWUSAGE;
15245 span = atoi(a->argv[3]);
15246 if ((span < 1) || (span > NUM_SPANS)) {
15247 ast_cli(a->fd, "Invalid span '%s'. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
15248 return CLI_SUCCESS;
15249 }
15250 if (!pris[span-1].pri.pri) {
15251 ast_cli(a->fd, "No PRI running on span %d\n", span);
15252 return CLI_SUCCESS;
15253 }
15254
15255 sig_pri_cli_show_span(a->fd, pris[span-1].dchannels, &pris[span-1].pri);
15256
15257 return CLI_SUCCESS;
15258}
15259#endif /* defined(HAVE_PRI) */
15260
15261#if defined(HAVE_PRI)
15262static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15263{
15264 int x;
15265 int span;
15266 int count=0;
15267 int debug;
15268
15269 switch (cmd) {
15270 case CLI_INIT:
15271 e->command = "pri show debug";
15272 e->usage =
15273 "Usage: pri show debug\n"
15274 " Show the debug state of pri spans\n";
15275 return NULL;
15276 case CLI_GENERATE:
15277 return NULL;
15278 }
15279
15280 for (span = 0; span < NUM_SPANS; span++) {
15281 if (pris[span].pri.pri) {
15282 for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
15283 if (pris[span].pri.dchans[x]) {
15284 debug = pri_get_debug(pris[span].pri.dchans[x]);
15285 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" );
15286 count++;
15287 }
15288 }
15289 }
15290
15291 }
15292 ast_mutex_lock(&pridebugfdlock);
15293 if (pridebugfd >= 0)
15294 ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
15295 ast_mutex_unlock(&pridebugfdlock);
15296
15297 if (!count)
15298 ast_cli(a->fd, "No PRI running\n");
15299 return CLI_SUCCESS;
15300}
15301#endif /* defined(HAVE_PRI) */
15302
15303#if defined(HAVE_PRI)
15304static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15305{
15306 switch (cmd) {
15307 case CLI_INIT:
15308 e->command = "pri show version";
15309 e->usage =
15310 "Usage: pri show version\n"
15311 "Show libpri version information\n";
15312 return NULL;
15313 case CLI_GENERATE:
15314 return NULL;
15315 }
15316
15317 ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
15318
15319 return CLI_SUCCESS;
15320}
15321#endif /* defined(HAVE_PRI) */
15322
15323#if defined(HAVE_PRI)
15324static struct ast_cli_entry dahdi_pri_cli[] = {
15325 AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
15326#if defined(HAVE_PRI_SERVICE_MESSAGES)
15327 AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
15328 AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
15329#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
15330 AST_CLI_DEFINE(handle_pri_show_channels, "Displays PRI channel information"),
15331 AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI span information"),
15332 AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI span information"),
15333 AST_CLI_DEFINE(handle_pri_destroy_span, "Destroy a PRI span"),
15334 AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
15335 AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
15336 AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
15337};
15338#endif /* defined(HAVE_PRI) */
15339
15340#ifdef HAVE_OPENR2
15341
15342static char *handle_mfcr2_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15343{
15344 switch (cmd) {
15345 case CLI_INIT:
15346 e->command = "mfcr2 show version";
15347 e->usage =
15348 "Usage: mfcr2 show version\n"
15349 " Shows the version of the OpenR2 library being used.\n";
15350 return NULL;
15351 case CLI_GENERATE:
15352 return NULL;
15353 }
15354 ast_cli(a->fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
15355 return CLI_SUCCESS;
15356}
15357
15358static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15359{
15360#define FORMAT "%4s %40s\n"
15361 int i = 0;
15362 int numvariants = 0;
15363 const openr2_variant_entry_t *variants;
15364 switch (cmd) {
15365 case CLI_INIT:
15366 e->command = "mfcr2 show variants";
15367 e->usage =
15368 "Usage: mfcr2 show variants\n"
15369 " Shows the list of MFC/R2 variants supported.\n";
15370 return NULL;
15371 case CLI_GENERATE:
15372 return NULL;
15373 }
15374 if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
15375 ast_cli(a->fd, "Failed to get list of variants.\n");
15376 return CLI_FAILURE;
15377 }
15378 ast_cli(a->fd, FORMAT, "Variant Code", "Country");
15379 for (i = 0; i < numvariants; i++) {
15380 ast_cli(a->fd, FORMAT, variants[i].name, variants[i].country);
15381 }
15382 return CLI_SUCCESS;
15383#undef FORMAT
15384}
15385
15386static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15387{
15388#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
15389 int filtertype = 0;
15390 int targetnum = 0;
15391 char channo[5];
15392 char linkno[5];
15393 char anino[5];
15394 char dnisno[5];
15395 struct dahdi_pvt *p;
15396 openr2_context_t *r2context;
15397 openr2_variant_t r2variant;
15398 switch (cmd) {
15399 case CLI_INIT:
15400 e->command = "mfcr2 show channels [group|context]";
15401 e->usage =
15402 "Usage: mfcr2 show channels [group <group> | context <context>]\n"
15403 " Shows the DAHDI channels configured with MFC/R2 signaling.\n";
15404 return NULL;
15405 case CLI_GENERATE:
15406 return NULL;
15407 }
15408 if (!((a->argc == 3) || (a->argc == 5))) {
15409 return CLI_SHOWUSAGE;
15410 }
15411 if (a->argc == 5) {
15412 if (!strcasecmp(a->argv[3], "group")) {
15413 targetnum = atoi(a->argv[4]);
15414 if ((targetnum < 0) || (targetnum > 63))
15415 return CLI_SHOWUSAGE;
15416 targetnum = 1 << targetnum;
15417 filtertype = 1;
15418 } else if (!strcasecmp(a->argv[3], "context")) {
15419 filtertype = 2;
15420 } else {
15421 return CLI_SHOWUSAGE;
15422 }
15423 }
15424 ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
15426 for (p = iflist; p; p = p->next) {
15427 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15428 continue;
15429 }
15430 if (filtertype) {
15431 switch(filtertype) {
15432 case 1: /* mfcr2 show channels group <group> */
15433 if (p->group != targetnum) {
15434 continue;
15435 }
15436 break;
15437 case 2: /* mfcr2 show channels context <context> */
15438 if (strcasecmp(p->context, a->argv[4])) {
15439 continue;
15440 }
15441 break;
15442 default:
15443 ;
15444 }
15445 }
15446 r2context = openr2_chan_get_context(p->r2chan);
15447 r2variant = openr2_context_get_variant(r2context);
15448 snprintf(channo, sizeof(channo), "%d", p->channel);
15449 snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
15450 snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
15451 snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
15452 ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
15453 anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
15454 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
15455 openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
15456 }
15458 return CLI_SUCCESS;
15459#undef FORMAT
15460}
15461
15462static char *handle_mfcr2_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15463{
15464 struct dahdi_pvt *p = NULL;
15465 int channo = 0;
15466 char *toklevel = NULL;
15467 char *saveptr = NULL;
15468 char *logval = NULL;
15469 openr2_log_level_t loglevel = OR2_LOG_NOTHING;
15470 openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
15471 switch (cmd) {
15472 case CLI_INIT:
15473 e->command = "mfcr2 set debug";
15474 e->usage =
15475 "Usage: mfcr2 set debug <loglevel> <channel>\n"
15476 " Set a new logging level for the specified channel.\n"
15477 " If no channel is specified the logging level will be applied to all channels.\n";
15478 return NULL;
15479 case CLI_GENERATE:
15480 return NULL;
15481 }
15482 if (a->argc < 4) {
15483 return CLI_SHOWUSAGE;
15484 }
15485 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15486 logval = ast_strdupa(a->argv[3]);
15487 toklevel = strtok_r(logval, ",", &saveptr);
15488 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15489 ast_cli(a->fd, "Invalid MFC/R2 logging level '%s'.\n", a->argv[3]);
15490 return CLI_FAILURE;
15491 } else if (OR2_LOG_NOTHING == tmplevel) {
15492 loglevel = tmplevel;
15493 } else {
15494 loglevel |= tmplevel;
15495 while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
15496 if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
15497 ast_cli(a->fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
15498 continue;
15499 }
15500 loglevel |= tmplevel;
15501 }
15502 }
15504 for (p = iflist; p; p = p->next) {
15505 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15506 continue;
15507 }
15508 if ((channo != -1) && (p->channel != channo )) {
15509 continue;
15510 }
15511 openr2_chan_set_log_level(p->r2chan, loglevel);
15512 if (channo != -1) {
15513 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for channel %d.\n", a->argv[3], p->channel);
15514 break;
15515 }
15516 }
15517 if ((channo != -1) && !p) {
15518 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15519 }
15520 if (channo == -1) {
15521 ast_cli(a->fd, "MFC/R2 debugging set to '%s' for all channels.\n", a->argv[3]);
15522 }
15524 return CLI_SUCCESS;
15525}
15526
15527static char *handle_mfcr2_call_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15528{
15529 struct dahdi_pvt *p = NULL;
15530 int channo = 0;
15531 switch (cmd) {
15532 case CLI_INIT:
15533 e->command = "mfcr2 call files [on|off]";
15534 e->usage =
15535 "Usage: mfcr2 call files [on|off] <channel>\n"
15536 " Enable call files creation on the specified channel.\n"
15537 " If no channel is specified call files creation policy will be applied to all channels.\n";
15538 return NULL;
15539 case CLI_GENERATE:
15540 return NULL;
15541 }
15542 if (a->argc < 4) {
15543 return CLI_SHOWUSAGE;
15544 }
15545 channo = (a->argc == 5) ? atoi(a->argv[4]) : -1;
15547 for (p = iflist; p; p = p->next) {
15548 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15549 continue;
15550 }
15551 if ((channo != -1) && (p->channel != channo )) {
15552 continue;
15553 }
15554 if (ast_true(a->argv[3])) {
15555 openr2_chan_enable_call_files(p->r2chan);
15556 } else {
15557 openr2_chan_disable_call_files(p->r2chan);
15558 }
15559 if (channo != -1) {
15560 if (ast_true(a->argv[3])) {
15561 ast_cli(a->fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
15562 } else {
15563 ast_cli(a->fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
15564 }
15565 break;
15566 }
15567 }
15568 if ((channo != -1) && !p) {
15569 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15570 }
15571 if (channo == -1) {
15572 if (ast_true(a->argv[3])) {
15573 ast_cli(a->fd, "MFC/R2 Call files enabled for all channels.\n");
15574 } else {
15575 ast_cli(a->fd, "MFC/R2 Call files disabled for all channels.\n");
15576 }
15577 }
15579 return CLI_SUCCESS;
15580}
15581
15582static char *handle_mfcr2_set_idle(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15583{
15584 struct dahdi_pvt *p = NULL;
15585 int channo = 0;
15586 switch (cmd) {
15587 case CLI_INIT:
15588 e->command = "mfcr2 set idle";
15589 e->usage =
15590 "Usage: mfcr2 set idle <channel>\n"
15591 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15592 " Force the given channel into IDLE state.\n"
15593 " If no channel is specified, all channels will be set to IDLE.\n";
15594 return NULL;
15595 case CLI_GENERATE:
15596 return NULL;
15597 }
15598 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15600 for (p = iflist; p; p = p->next) {
15601 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15602 continue;
15603 }
15604 if ((channo != -1) && (p->channel != channo )) {
15605 continue;
15606 }
15607 openr2_chan_set_idle(p->r2chan);
15608 ast_mutex_lock(&p->lock);
15609 p->locallyblocked = 0;
15610 p->mfcr2call = 0;
15612 if (channo != -1) {
15613 break;
15614 }
15615 }
15616 if ((channo != -1) && !p) {
15617 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15618 }
15620 return CLI_SUCCESS;
15621}
15622
15623static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15624{
15625 struct dahdi_pvt *p = NULL;
15626 int channo = 0;
15627 switch (cmd) {
15628 case CLI_INIT:
15629 e->command = "mfcr2 set blocked";
15630 e->usage =
15631 "Usage: mfcr2 set blocked <channel>\n"
15632 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
15633 " Force the given channel into BLOCKED state.\n"
15634 " If no channel is specified, all channels will be set to BLOCKED.\n";
15635 return NULL;
15636 case CLI_GENERATE:
15637 return NULL;
15638 }
15639 channo = (a->argc == 4) ? atoi(a->argv[3]) : -1;
15641 for (p = iflist; p; p = p->next) {
15642 if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
15643 continue;
15644 }
15645 if ((channo != -1) && (p->channel != channo )) {
15646 continue;
15647 }
15648 openr2_chan_set_blocked(p->r2chan);
15649 ast_mutex_lock(&p->lock);
15650 p->locallyblocked = 1;
15652 if (channo != -1) {
15653 break;
15654 }
15655 }
15656 if ((channo != -1) && !p) {
15657 ast_cli(a->fd, "MFC/R2 channel %d not found.\n", channo);
15658 }
15660 return CLI_SUCCESS;
15661}
15662
15663static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
15664{
15665#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
15666 AST_LIST_LOCK(list_head);
15667 if (! AST_LIST_EMPTY(list_head)) {
15668 char index[5];
15669 char live_chans_str[5];
15670 char channel_list[R2_LINK_CAPACITY * 4];
15671 struct r2link_entry *cur;
15672 ast_cli(a->fd, "%s\n", title);
15673 ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
15674 AST_LIST_TRAVERSE(list_head, cur, list) {
15675 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15676 const char *thread_status = NULL;
15677 int i;
15678 int len;
15679 int inside_range;
15680 int channo;
15681 int prev_channo;
15682
15683 if (mfcr2->r2master == 0L) {
15684 thread_status = "zero";
15685 } else if (mfcr2->r2master == AST_PTHREADT_NULL) {
15686 thread_status = "none";
15687 } else {
15688 thread_status = "created";
15689 }
15690 snprintf(index, sizeof(index), "%d", mfcr2->index);
15691 snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
15692 channo = 0;
15693 prev_channo = 0;
15694 inside_range = 0;
15695 len = 0;
15696 /* Prepare nice string in channel_list[] */
15697 for (i = 0; i < mfcr2->numchans && len < sizeof(channel_list) - 1; i++) {
15698 struct dahdi_pvt *p = mfcr2->pvts[i];
15699 if (!p) {
15700 continue;
15701 }
15702 channo = p->channel;
15703 /* Don't show a range until we know the last channel number */
15704 if (prev_channo && prev_channo == channo - 1) {
15705 prev_channo = channo;
15706 inside_range = 1;
15707 continue;
15708 }
15709 if (inside_range) {
15710 /* Close range */
15711 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
15712 inside_range = 0;
15713 } else if (prev_channo) {
15714 /* Non-sequential channel numbers */
15715 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15716 } else {
15717 /* First channel number */
15718 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
15719 }
15720 prev_channo = channo;
15721 }
15722 /* Handle leftover channels */
15723 if (inside_range) {
15724 /* Close range */
15725 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
15726 inside_range = 0;
15727 } else if (prev_channo) {
15728 /* Non-sequential channel numbers */
15729 len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
15730 }
15731 // channel_list[len] = '\0';
15732 ast_cli(a->fd, FORMAT,
15733 index,
15734 thread_status,
15735 (mfcr2->nodev) ? "MISSING" : "OK",
15736 live_chans_str,
15737 channel_list);
15738 }
15739 }
15740 AST_LIST_UNLOCK(list_head);
15741#undef FORMAT
15742}
15743
15744static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15745{
15746 switch (cmd) {
15747 case CLI_INIT:
15748 e->command = "mfcr2 show links";
15749 e->usage =
15750 "Usage: mfcr2 show links\n"
15751 " Shows the DAHDI MFC/R2 links.\n";
15752 return NULL;
15753 case CLI_GENERATE:
15754 return NULL;
15755 }
15756 if (a->argc != 3) {
15757 return CLI_SHOWUSAGE;
15758 }
15759 mfcr2_show_links_of(a, &r2links, "Live links\n");
15760 mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
15761 return CLI_SUCCESS;
15762}
15763
15764static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15765{
15766 int res;
15767 int wanted_link_index;
15768 int found_link = 0;
15769 struct r2link_entry *cur = NULL;
15770
15771 switch (cmd) {
15772 case CLI_INIT:
15773 e->command = "mfcr2 destroy link";
15774 e->usage =
15775 "Usage: mfcr2 destroy link <index-number>\n"
15776 " Destroys D-channel of link and its B-channels.\n"
15777 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
15778 return NULL;
15779 case CLI_GENERATE:
15780 return NULL;
15781 }
15782 if (a->argc < 4) {
15783 return CLI_SHOWUSAGE;
15784 }
15785 res = sscanf(a->argv[3], "%30d", &wanted_link_index);
15786 if ((res != 1) || wanted_link_index < 1) {
15787 ast_cli(a->fd,
15788 "Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
15789 return CLI_SUCCESS;
15790 }
15791 AST_LIST_LOCK(&r2links);
15792 AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
15793 struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
15794 if (wanted_link_index == mfcr2->index) {
15795 AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
15796 r2links_count--;
15797 break;
15798 }
15799 }
15801 AST_LIST_UNLOCK(&r2links);
15802 if (! found_link) {
15803 ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
15804 return CLI_FAILURE;
15805 }
15806 return CLI_SUCCESS;
15807}
15808
15809static struct ast_cli_entry dahdi_mfcr2_cli[] = {
15810 AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
15811 AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
15812 AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
15813 AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
15814 AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
15815 AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
15816 AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
15817 AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
15818 AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
15819};
15820
15821#endif /* HAVE_OPENR2 */
15822
15823static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15824{
15825 int start;
15826 int end;
15827 switch (cmd) {
15828 case CLI_INIT:
15829 e->command = "dahdi destroy channels";
15830 e->usage =
15831 "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
15832 " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
15833 return NULL;
15834 case CLI_GENERATE:
15835 return NULL;
15836 }
15837 if ((a->argc < 4) || a->argc > 5) {
15838 return CLI_SHOWUSAGE;
15839 }
15840 start = atoi(a->argv[3]);
15841 if (start < 1) {
15842 ast_cli(a->fd, "Invalid starting channel number %s.\n",
15843 a->argv[4]);
15844 return CLI_FAILURE;
15845 }
15846 if (a->argc == 5) {
15847 end = atoi(a->argv[4]);
15848 if (end < 1) {
15849 ast_cli(a->fd, "Invalid ending channel number %s.\n",
15850 a->argv[4]);
15851 return CLI_FAILURE;
15852 }
15853 } else {
15854 end = start;
15855 }
15856
15857 if (end < start) {
15858 ast_cli(a->fd,
15859 "range end (%d) is smaller than range start (%d)\n",
15860 end, start);
15861 return CLI_FAILURE;
15862 }
15864 return CLI_SUCCESS;
15865}
15866
15867static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15868{
15869 int start;
15870 int end;
15871 int ret;
15872
15873 switch (cmd) {
15874 case CLI_INIT:
15875 e->command = "dahdi create channels";
15876 e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
15877 " dahdi create channels new - add channels not yet created\n"
15878 "For ISDN and SS7 the range should include complete spans.\n";
15879 return NULL;
15880 case CLI_GENERATE:
15881 return NULL;
15882 }
15883 if ((a->argc < 4) || a->argc > 5) {
15884 return CLI_SHOWUSAGE;
15885 }
15886 if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
15887 ret = dahdi_create_channel_range(0, 0);
15888 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15889 }
15890 start = atoi(a->argv[3]);
15891 if (start <= 0) {
15892 ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
15893 a->argv[3]);
15894 return CLI_FAILURE;
15895 }
15896 if (a->argc == 5) {
15897 end = atoi(a->argv[4]);
15898 if (end <= 0) {
15899 ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
15900 a->argv[4]);
15901 return CLI_FAILURE;
15902 }
15903 } else {
15904 end = start;
15905 }
15906 if (end < start) {
15907 ast_cli(a->fd,
15908 "range end (%d) is smaller than range start (%d)\n",
15909 end, start);
15910 return CLI_FAILURE;
15911 }
15912 ret = dahdi_create_channel_range(start, end);
15913 return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
15914}
15915
15916static void dahdi_softhangup_all(void)
15917{
15918 struct dahdi_pvt *p;
15919retry:
15921 for (p = iflist; p; p = p->next) {
15922 ast_mutex_lock(&p->lock);
15923 if (p->owner && !p->restartpending) {
15924 if (ast_channel_trylock(p->owner)) {
15925 if (DEBUG_ATLEAST(3))
15926 ast_verbose("Avoiding deadlock\n");
15927 /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
15930 goto retry;
15931 }
15932 if (DEBUG_ATLEAST(3))
15933 ast_verbose("Softhanging up on %s\n", ast_channel_name(p->owner));
15935 p->restartpending = 1;
15938 }
15940 }
15942}
15943
15944static int dahdi_restart(void)
15945{
15946#if defined(HAVE_PRI) || defined(HAVE_SS7)
15947 int i, j;
15948#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
15949 int cancel_code;
15950 struct dahdi_pvt *p;
15951
15953 ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
15955 ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
15956#ifdef HAVE_OPENR2
15957 dahdi_r2_destroy_links();
15958#endif
15959
15960#if defined(HAVE_PRI)
15961 for (i = 0; i < NUM_SPANS; i++) {
15962 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
15963 cancel_code = pthread_cancel(pris[i].pri.master);
15964 pthread_kill(pris[i].pri.master, SIGURG);
15965 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);
15966 pthread_join(pris[i].pri.master, NULL);
15967 ast_debug(4, "Joined thread of span %d\n", i);
15968 }
15969 }
15970#endif
15971
15972#if defined(HAVE_SS7)
15973 for (i = 0; i < NUM_SPANS; i++) {
15974 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
15975 cancel_code = pthread_cancel(linksets[i].ss7.master);
15976 pthread_kill(linksets[i].ss7.master, SIGURG);
15977 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);
15978 pthread_join(linksets[i].ss7.master, NULL);
15979 ast_debug(4, "Joined thread of span %d\n", i);
15980 }
15981 }
15982#endif /* defined(HAVE_SS7) */
15983
15986 cancel_code = pthread_cancel(monitor_thread);
15987 pthread_kill(monitor_thread, SIGURG);
15988 ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
15989 pthread_join(monitor_thread, NULL);
15990 ast_debug(4, "Joined monitor thread\n");
15991 }
15992 monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
15993
15995 while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
15996 int x = DAHDI_FLASH;
15997 ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
15998
16000 for (p = iflist; p; p = p->next) {
16001 if (p->owner) {
16002 /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
16003 ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
16004 }
16005 }
16008 }
16009
16010 /* ensure any created channels before monitor threads were stopped are hungup */
16012 ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
16014 memset(round_robin, 0, sizeof(round_robin));
16015 ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
16016
16018
16019#ifdef HAVE_PRI
16020 for (i = 0; i < NUM_SPANS; i++) {
16021 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++)
16022 dahdi_close_pri_fd(&(pris[i]), j);
16023 }
16024
16025 memset(pris, 0, sizeof(pris));
16026 for (i = 0; i < NUM_SPANS; i++) {
16027 sig_pri_init_pri(&pris[i].pri);
16028 }
16029 pri_set_error(dahdi_pri_error);
16030 pri_set_message(dahdi_pri_message);
16031#endif
16032#if defined(HAVE_SS7)
16033 for (i = 0; i < NUM_SPANS; i++) {
16034 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++)
16035 dahdi_close_ss7_fd(&(linksets[i]), j);
16036 }
16037
16038 memset(linksets, 0, sizeof(linksets));
16039 for (i = 0; i < NUM_SPANS; i++) {
16040 sig_ss7_init_linkset(&linksets[i].ss7);
16041 }
16042 ss7_set_error(dahdi_ss7_error);
16043 ss7_set_message(dahdi_ss7_message);
16044 ss7_set_hangup(sig_ss7_cb_hangup);
16045 ss7_set_notinservice(sig_ss7_cb_notinservice);
16046 ss7_set_call_null(sig_ss7_cb_call_null);
16047#endif /* defined(HAVE_SS7) */
16048
16049 if (setup_dahdi(2) != 0) {
16050 ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
16052 return 1;
16053 }
16056 return 0;
16057}
16058
16059static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16060{
16061 switch (cmd) {
16062 case CLI_INIT:
16063 e->command = "dahdi restart";
16064 e->usage =
16065 "Usage: dahdi restart\n"
16066 " Restarts the DAHDI channels: destroys them all and then\n"
16067 " re-reads them from chan_dahdi.conf.\n"
16068 " Note that this will STOP any running CALL on DAHDI channels.\n"
16069 "";
16070 return NULL;
16071 case CLI_GENERATE:
16072 return NULL;
16073 }
16074 if (a->argc != 2)
16075 return CLI_SHOWUSAGE;
16076
16077 if (dahdi_restart() != 0)
16078 return CLI_FAILURE;
16079 return CLI_SUCCESS;
16080}
16081
16082static int action_dahdirestart(struct mansession *s, const struct message *m)
16083{
16084 if (dahdi_restart() != 0) {
16085 astman_send_error(s, m, "Failed rereading DAHDI configuration");
16086 return 1;
16087 }
16088 astman_send_ack(s, m, "DAHDIRestart: Success");
16089 return 0;
16090}
16091
16092static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16093{
16094#define FORMAT "%7s %4d %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16095#define FORMAT2 "%7s %4s %-20.20s %-10.10s %-15.15s %-8.8s %-20.20s %-10.10s %-10.10s %-12.12s %-32.32s\n"
16096 ast_group_t targetnum = 0;
16097 int filtertype = 0;
16098 struct dahdi_pvt *tmp = NULL;
16099 char tmps[20];
16100 char blockstr[20];
16101
16102 switch (cmd) {
16103 case CLI_INIT:
16104 e->command = "dahdi show channels [group|context]";
16105 e->usage =
16106 "Usage: dahdi show channels [ group <group> | context <context> ]\n"
16107 " Shows a list of available channels with optional filtering\n"
16108 " <group> must be a number between 0 and 63\n";
16109 return NULL;
16110 case CLI_GENERATE:
16111 return NULL;
16112 }
16113
16114 /* syntax: dahdi show channels [ group <group> | context <context> ] */
16115
16116 if (!((a->argc == 3) || (a->argc == 5))) {
16117 return CLI_SHOWUSAGE;
16118 }
16119
16120 if (a->argc == 5) {
16121 if (!strcasecmp(a->argv[3], "group")) {
16122 targetnum = atoi(a->argv[4]);
16123 if (63 < targetnum) {
16124 return CLI_SHOWUSAGE;
16125 }
16126 targetnum = ((ast_group_t) 1) << targetnum;
16127 filtertype = 1;
16128 } else if (!strcasecmp(a->argv[3], "context")) {
16129 filtertype = 2;
16130 }
16131 }
16132
16133 ast_cli(a->fd, FORMAT2, "Chan", "Span", "Signalling", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "In Service", "Alarms", "Description");
16135 for (tmp = iflist; tmp; tmp = tmp->next) {
16136 int alm = 0;
16137 if (filtertype) {
16138 switch(filtertype) {
16139 case 1: /* dahdi show channels group <group> */
16140 if (!(tmp->group & targetnum)) {
16141 continue;
16142 }
16143 break;
16144 case 2: /* dahdi show channels context <context> */
16145 if (strcasecmp(tmp->context, a->argv[4])) {
16146 continue;
16147 }
16148 break;
16149 default:
16150 break;
16151 }
16152 }
16153 if (tmp->channel > 0) {
16154 snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
16155 alm = get_alarms(tmp);
16156 } else {
16157 ast_copy_string(tmps, "pseudo", sizeof(tmps));
16158 }
16159
16160 blockstr[0] = tmp->locallyblocked ? 'L' : ' ';
16161 blockstr[1] = tmp->remotelyblocked ? 'R' : ' ';
16162 blockstr[2] = '\0';
16163
16164 ast_cli(a->fd, FORMAT, tmps, tmp->span, sig2str(tmp->sig), tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, tmp->inservice ? "Yes" : "No",
16165 alarm2str(alm), tmp->description);
16166 }
16168 return CLI_SUCCESS;
16169#undef FORMAT
16170#undef FORMAT2
16171}
16172
16173static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16174{
16175 int channel;
16176 struct dahdi_pvt *tmp = NULL;
16177 struct dahdi_confinfo ci;
16178 struct dahdi_params ps;
16179 int x;
16180 char hwrxgain[15];
16181 char hwtxgain[15];
16182
16183 switch (cmd) {
16184 case CLI_INIT:
16185 e->command = "dahdi show channel";
16186 e->usage =
16187 "Usage: dahdi show channel <chan num>\n"
16188 " Detailed information about a given channel\n";
16189 return NULL;
16190 case CLI_GENERATE:
16191 return NULL;
16192 }
16193
16194 if (a->argc != 4)
16195 return CLI_SHOWUSAGE;
16196
16197 channel = atoi(a->argv[3]);
16198
16200 for (tmp = iflist; tmp; tmp = tmp->next) {
16201 if (tmp->channel == channel) {
16202 ast_cli(a->fd, "Channel: %d\n", tmp->channel);
16203 ast_cli(a->fd, "Description: %s\n", tmp->description);
16204 ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
16205 ast_cli(a->fd, "Span: %d\n", tmp->span);
16206 ast_cli(a->fd, "Extension: %s\n", tmp->exten);
16207 ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
16208 ast_cli(a->fd, "Context: %s\n", tmp->context);
16209 ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
16210 ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
16211#if defined(HAVE_PRI)
16212#if defined(HAVE_PRI_SUBADDR)
16213 ast_cli(a->fd, "Caller ID subaddress: %s\n", tmp->cid_subaddr);
16214#endif /* defined(HAVE_PRI_SUBADDR) */
16215#endif /* defined(HAVE_PRI) */
16216 ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
16217 ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
16218 if (tmp->vars) {
16219 struct ast_variable *v;
16220 ast_cli(a->fd, "Variables:\n");
16221 for (v = tmp->vars ; v ; v = v->next)
16222 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
16223 }
16224 ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
16225 ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
16226 ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
16227 ast_cli(a->fd, "Radio: %d\n", tmp->radio);
16228 ast_cli(a->fd, "Owner: %s\n", tmp->owner ? ast_channel_name(tmp->owner) : "<None>");
16229 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)" : "");
16230 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)" : "");
16231 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)" : "");
16232 ast_cli(a->fd, "Confno: %d\n", tmp->confno);
16233 ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
16234 ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
16235 ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
16236 ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
16237 if (tmp->busydetect) {
16238#if defined(BUSYDETECT_TONEONLY)
16239 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_TONEONLY\n");
16240#elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
16241 ast_cli(a->fd, " Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
16242#endif
16243#ifdef BUSYDETECT_DEBUG
16244 ast_cli(a->fd, " Busy Detector Debug: Enabled\n");
16245#endif
16246 ast_cli(a->fd, " Busy Count: %d\n", tmp->busycount);
16247 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);
16248 }
16249 ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
16250 ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
16251 ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
16252 ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
16253 ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
16254 ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
16255 if (tmp->hwrxgain_enabled) {
16256 snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
16257 } else {
16258 ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
16259 }
16260 if (tmp->hwtxgain_enabled) {
16261 snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
16262 } else {
16263 ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
16264 }
16265 ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
16266 ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
16267 ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
16268 ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
16269 ast_cli(a->fd, "Echo Cancellation:\n");
16270
16271 if (tmp->echocancel.head.tap_length) {
16272 ast_cli(a->fd, "\t%u taps\n", tmp->echocancel.head.tap_length);
16273 for (x = 0; x < tmp->echocancel.head.param_count; x++) {
16274 ast_cli(a->fd, "\t\t%s: %dd\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
16275 }
16276 ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
16277 } else {
16278 ast_cli(a->fd, "\tnone\n");
16279 }
16280 ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone);
16281 if (tmp->master)
16282 ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
16283 for (x = 0; x < MAX_SLAVES; x++) {
16284 if (tmp->slaves[x])
16285 ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
16286 }
16287#ifdef HAVE_OPENR2
16288 if (tmp->mfcr2) {
16289 char calldir[OR2_MAX_PATH];
16290 openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
16291 openr2_variant_t r2variant = openr2_context_get_variant(r2context);
16292 ast_cli(a->fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
16293 ast_cli(a->fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
16294 ast_cli(a->fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
16295 ast_cli(a->fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
16296 ast_cli(a->fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
16297 ast_cli(a->fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
16298 ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
16299 ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
16300#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
16301 ast_cli(a->fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
16302 ast_cli(a->fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
16303#endif
16304 ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
16305#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
16306 ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
16307#endif
16308 ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
16309 ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
16310 ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
16311 ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
16312 ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
16313 ast_cli(a->fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
16314 ast_cli(a->fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
16315 ast_cli(a->fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
16316 ast_cli(a->fd, "MFC/R2 Tx CAS: %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
16317 ast_cli(a->fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
16318 ast_cli(a->fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
16319 ast_cli(a->fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
16320 }
16321#endif
16322#if defined(HAVE_SS7)
16323 if (tmp->ss7) {
16324 struct sig_ss7_chan *chan = tmp->sig_pvt;
16325
16326 ast_cli(a->fd, "CIC: %d\n", chan->cic);
16327 }
16328#endif /* defined(HAVE_SS7) */
16329#ifdef HAVE_PRI
16330 if (tmp->pri) {
16331 struct sig_pri_chan *chan = tmp->sig_pvt;
16332
16333 ast_cli(a->fd, "PRI Flags: ");
16334 if (chan->resetting != SIG_PRI_RESET_IDLE) {
16335 ast_cli(a->fd, "Resetting=%u ", chan->resetting);
16336 }
16337 if (chan->call)
16338 ast_cli(a->fd, "Call ");
16339 if (chan->allocated) {
16340 ast_cli(a->fd, "Allocated ");
16341 }
16342 ast_cli(a->fd, "\n");
16343 if (tmp->logicalspan)
16344 ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
16345 else
16346 ast_cli(a->fd, "PRI Logical Span: Implicit\n");
16347 }
16348#endif
16349 memset(&ci, 0, sizeof(ci));
16350 ps.channo = tmp->channel;
16351 if (tmp->subs[SUB_REAL].dfd > -1) {
16352 memset(&ci, 0, sizeof(ci));
16353 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
16354 ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, (unsigned)ci.confmode);
16355 }
16356 if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
16357 ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
16358 }
16359 memset(&ps, 0, sizeof(ps));
16360 if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
16361 ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
16362 } else {
16363 ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
16364 }
16365 }
16367 return CLI_SUCCESS;
16368 }
16369 }
16371
16372 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16373 return CLI_FAILURE;
16374}
16375
16376static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16377{
16378 int i, j;
16379 switch (cmd) {
16380 case CLI_INIT:
16381 e->command = "dahdi show cadences";
16382 e->usage =
16383 "Usage: dahdi show cadences\n"
16384 " Shows all cadences currently defined\n";
16385 return NULL;
16386 case CLI_GENERATE:
16387 return NULL;
16388 }
16389 for (i = 0; i < num_cadence; i++) {
16390 char output[1024];
16391 char tmp[16], tmp2[64];
16392 snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
16393 term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
16394
16395 for (j = 0; j < 16; j++) {
16396 if (cadences[i].ringcadence[j] == 0)
16397 break;
16398 snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
16399 if (cidrings[i] * 2 - 1 == j)
16400 term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
16401 else
16402 term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
16403 if (j != 0)
16404 strncat(output, ",", sizeof(output) - strlen(output) - 1);
16405 strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
16406 }
16407 ast_cli(a->fd,"%s\n",output);
16408 }
16409 return CLI_SUCCESS;
16410}
16411
16412static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
16413{
16414 alarmstr[0] = '\0';
16415 if (spaninfo->alarms > 0) {
16416 if (spaninfo->alarms & DAHDI_ALARM_BLUE) {
16417 strcat(alarmstr, "BLU/");
16418 }
16419 if (spaninfo->alarms & DAHDI_ALARM_YELLOW) {
16420 strcat(alarmstr, "YEL/");
16421 }
16422 if (spaninfo->alarms & DAHDI_ALARM_RED) {
16423 strcat(alarmstr, "RED/");
16424 }
16425 if (spaninfo->alarms & DAHDI_ALARM_LOOPBACK) {
16426 strcat(alarmstr, "LB/");
16427 }
16428 if (spaninfo->alarms & DAHDI_ALARM_RECOVER) {
16429 strcat(alarmstr, "REC/");
16430 }
16431 if (spaninfo->alarms & DAHDI_ALARM_NOTOPEN) {
16432 strcat(alarmstr, "NOP/");
16433 }
16434 if (!strlen(alarmstr)) {
16435 strcat(alarmstr, "UUU/");
16436 }
16437 if (strlen(alarmstr)) {
16438 /* Strip trailing / */
16439 alarmstr[strlen(alarmstr) - 1] = '\0';
16440 }
16441 } else {
16442 if (spaninfo->numchans) {
16443 strcpy(alarmstr, "OK");
16444 } else {
16445 strcpy(alarmstr, "UNCONFIGURED");
16446 }
16447 }
16448}
16449
16450/* Based on irqmiss.c */
16451static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16452{
16453 #define FORMAT "%4d %-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
16454 #define FORMAT2 "%4s %-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
16455 int span;
16456 int res;
16457 char alarmstr[50];
16458
16459 int ctl;
16460 struct dahdi_spaninfo s;
16461
16462 switch (cmd) {
16463 case CLI_INIT:
16464 e->command = "dahdi show status";
16465 e->usage =
16466 "Usage: dahdi show status\n"
16467 " Shows a list of DAHDI cards with status\n";
16468 return NULL;
16469 case CLI_GENERATE:
16470 return NULL;
16471 }
16472 ctl = open("/dev/dahdi/ctl", O_RDWR);
16473 if (ctl < 0) {
16474 ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
16475 return CLI_FAILURE;
16476 }
16477 ast_cli(a->fd, FORMAT2, "Span", "Description", "Alarms", "IRQ", "bpviol", "CRC", "Framing", "Coding", "Options", "LBO");
16478
16479 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
16480 s.spanno = span;
16481 res = ioctl(ctl, DAHDI_SPANSTAT, &s);
16482 if (res) {
16483 continue;
16484 }
16485 build_alarm_info(alarmstr, &s);
16486 ast_cli(a->fd, FORMAT, span, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count,
16487 s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
16488 s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
16489 s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
16490 "CAS",
16491 s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
16492 s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
16493 s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
16494 "Unknown",
16495 s.lineconfig & DAHDI_CONFIG_CRC4 ?
16496 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
16497 s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
16498 lbostr[s.lbo]
16499 );
16500 }
16501 close(ctl);
16502
16503 return CLI_SUCCESS;
16504#undef FORMAT
16505#undef FORMAT2
16506}
16507
16508static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16509{
16510 int pseudo_fd = -1;
16511 struct dahdi_versioninfo vi;
16512
16513 switch (cmd) {
16514 case CLI_INIT:
16515 e->command = "dahdi show version";
16516 e->usage =
16517 "Usage: dahdi show version\n"
16518 " Shows the DAHDI version in use\n";
16519 return NULL;
16520 case CLI_GENERATE:
16521 return NULL;
16522 }
16523 if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
16524 ast_cli(a->fd, "Failed to open control file to get version.\n");
16525 return CLI_SUCCESS;
16526 }
16527
16528 strcpy(vi.version, "Unknown");
16529 strcpy(vi.echo_canceller, "Unknown");
16530
16531 if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
16532 ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
16533 else
16534 ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
16535
16536 close(pseudo_fd);
16537
16538 return CLI_SUCCESS;
16539}
16540
16541static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16542{
16543 int channel;
16544 float gain;
16545 int tx;
16546 struct dahdi_pvt *tmp = NULL;
16547
16548 switch (cmd) {
16549 case CLI_INIT:
16550 e->command = "dahdi set hwgain {rx|tx}";
16551 e->usage =
16552 "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
16553 " Sets the hardware gain on a given channel and overrides the\n"
16554 " value provided at module loadtime. Changes take effect\n"
16555 " immediately whether the channel is in use or not.\n"
16556 "\n"
16557 " <rx|tx> which direction do you want to change (relative to our module)\n"
16558 " <chan num> is the channel number relative to the device\n"
16559 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
16560 "\n"
16561 " Please note:\n"
16562 " * hwgain is only supportable by hardware with analog ports because\n"
16563 " hwgain works on the analog side of an analog-digital conversion.\n";
16564 return NULL;
16565 case CLI_GENERATE:
16566 return NULL;
16567 }
16568
16569 if (a->argc != 6)
16570 return CLI_SHOWUSAGE;
16571
16572 if (!strcasecmp("rx", a->argv[3]))
16573 tx = 0; /* rx */
16574 else if (!strcasecmp("tx", a->argv[3]))
16575 tx = 1; /* tx */
16576 else
16577 return CLI_SHOWUSAGE;
16578
16579 channel = atoi(a->argv[4]);
16580 gain = atof(a->argv[5]);
16581
16583
16584 for (tmp = iflist; tmp; tmp = tmp->next) {
16585
16586 if (tmp->channel != channel)
16587 continue;
16588
16589 if (tmp->subs[SUB_REAL].dfd == -1)
16590 break;
16591
16592 if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
16593 ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
16595 return CLI_FAILURE;
16596 }
16597 ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
16598 tx ? "tx" : "rx", gain, channel);
16599
16600 if (tx) {
16601 tmp->hwtxgain_enabled = 1;
16602 tmp->hwtxgain = gain;
16603 } else {
16604 tmp->hwrxgain_enabled = 1;
16605 tmp->hwrxgain = gain;
16606 }
16607 break;
16608 }
16609
16611
16612 if (tmp)
16613 return CLI_SUCCESS;
16614
16615 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16616 return CLI_FAILURE;
16617
16618}
16619
16620static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16621{
16622 int channel;
16623 float gain;
16624 int tx;
16625 int res;
16626 struct dahdi_pvt *tmp = NULL;
16627
16628 switch (cmd) {
16629 case CLI_INIT:
16630 e->command = "dahdi set swgain {rx|tx}";
16631 e->usage =
16632 "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
16633 " Sets the software gain on a given channel and overrides the\n"
16634 " value provided at module loadtime. Changes take effect\n"
16635 " immediately whether the channel is in use or not.\n"
16636 "\n"
16637 " <rx|tx> which direction do you want to change (relative to our module)\n"
16638 " <chan num> is the channel number relative to the device\n"
16639 " <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
16640 return NULL;
16641 case CLI_GENERATE:
16642 return NULL;
16643 }
16644
16645 if (a->argc != 6)
16646 return CLI_SHOWUSAGE;
16647
16648 if (!strcasecmp("rx", a->argv[3]))
16649 tx = 0; /* rx */
16650 else if (!strcasecmp("tx", a->argv[3]))
16651 tx = 1; /* tx */
16652 else
16653 return CLI_SHOWUSAGE;
16654
16655 channel = atoi(a->argv[4]);
16656 gain = atof(a->argv[5]);
16657
16659 for (tmp = iflist; tmp; tmp = tmp->next) {
16660
16661 if (tmp->channel != channel)
16662 continue;
16663
16664 if (tmp->subs[SUB_REAL].dfd == -1)
16665 break;
16666
16667 if (tx)
16668 res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, gain, tmp->txdrc, tmp->law);
16669 else
16670 res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, gain, tmp->rxdrc, tmp->law);
16671
16672 if (res) {
16673 ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
16675 return CLI_FAILURE;
16676 }
16677
16678 ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
16679 tx ? "tx" : "rx", gain, channel);
16680
16681 if (tx) {
16682 tmp->txgain = gain;
16683 } else {
16684 tmp->rxgain = gain;
16685 }
16686 break;
16687 }
16689
16690 if (tmp)
16691 return CLI_SUCCESS;
16692
16693 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16694 return CLI_FAILURE;
16695
16696}
16697
16698static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16699{
16700 int channel;
16701 int on;
16702 struct dahdi_pvt *dahdi_chan = NULL;
16703
16704 switch (cmd) {
16705 case CLI_INIT:
16706 e->command = "dahdi set dnd";
16707 e->usage =
16708 "Usage: dahdi set dnd <chan#> <on|off>\n"
16709 " Sets/resets DND (Do Not Disturb) mode on a channel.\n"
16710 " Changes take effect immediately.\n"
16711 " <chan num> is the channel number\n"
16712 " <on|off> Enable or disable DND mode?\n"
16713 ;
16714 return NULL;
16715 case CLI_GENERATE:
16716 return NULL;
16717 }
16718
16719 if (a->argc != 5)
16720 return CLI_SHOWUSAGE;
16721
16722 if ((channel = atoi(a->argv[3])) <= 0) {
16723 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16724 return CLI_SHOWUSAGE;
16725 }
16726
16727 if (ast_true(a->argv[4]))
16728 on = 1;
16729 else if (ast_false(a->argv[4]))
16730 on = 0;
16731 else {
16732 ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
16733 return CLI_SHOWUSAGE;
16734 }
16735
16737 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16738 if (dahdi_chan->channel != channel)
16739 continue;
16740
16741 /* Found the channel. Actually set it */
16742 dahdi_dnd(dahdi_chan, on);
16743 break;
16744 }
16746
16747 if (!dahdi_chan) {
16748 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16749 return CLI_FAILURE;
16750 }
16751
16752 return CLI_SUCCESS;
16753}
16754
16755static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
16756{
16757 int channel;
16758 int on;
16759 int override = 1;
16760 struct dahdi_pvt *dahdi_chan = NULL;
16761
16762 switch (cmd) {
16763 case CLI_INIT:
16764 e->command = "dahdi set mwi";
16765 e->usage =
16766 "Usage: dahdi set mwi <chan#> <on|off|reset>\n"
16767 " Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
16768 " This may be used regardless of whether the channel is assigned any mailboxes.\n"
16769 " When active, this setting will override the voicemail status to set MWI.\n"
16770 " Once cleared, the voicemail status will resume control of MWI.\n"
16771 " Changes are queued for when the channel is idle and persist until cleared.\n"
16772 " <chan num> is the channel number\n"
16773 " <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
16774 ;
16775 return NULL;
16776 case CLI_GENERATE:
16777 return NULL;
16778 }
16779
16780 if (a->argc != 5)
16781 return CLI_SHOWUSAGE;
16782
16783 if ((channel = atoi(a->argv[3])) <= 0) {
16784 ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
16785 return CLI_SHOWUSAGE;
16786 }
16787
16788 if (ast_true(a->argv[4])) {
16789 on = 1;
16790 } else if (ast_false(a->argv[4])) {
16791 on = 0;
16792 } else if (!strcmp(a->argv[4], "reset")) {
16793 override = 0;
16794 } else {
16795 ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
16796 return CLI_SHOWUSAGE;
16797 }
16798
16800 for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
16801 if (dahdi_chan->channel != channel)
16802 continue;
16803
16804 /* Found the channel. Actually set it */
16805 if (override) {
16806 dahdi_chan->mwioverride_disposition = on;
16807 ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
16808 }
16809 dahdi_chan->mwioverride_active = override;
16810 /* The do_monitor thread will take care of actually sending the MWI
16811 * at an appropriate time for the channel. */
16812 break;
16813 }
16815
16816 if (!dahdi_chan) {
16817 ast_cli(a->fd, "Unable to find given channel %d\n", channel);
16818 return CLI_FAILURE;
16819 }
16820
16821 return CLI_SUCCESS;
16822}
16823
16824static struct ast_cli_entry dahdi_cli[] = {
16826 AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
16827 AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
16828 AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
16829 AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
16830 AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
16831 AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
16832 AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
16833 AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
16834 AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
16835 AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
16836 AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
16837};
16838
16839#define TRANSFER 0
16840#define HANGUP 1
16841
16842static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
16843{
16844 if (p) {
16845 switch (mode) {
16846 case TRANSFER:
16847 p->fake_event = DAHDI_EVENT_WINKFLASH;
16848 break;
16849 case HANGUP:
16850 p->fake_event = DAHDI_EVENT_ONHOOK;
16851 break;
16852 default:
16853 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));
16854 }
16855 }
16856 return 0;
16857}
16858static struct dahdi_pvt *find_channel(int channel)
16859{
16860 struct dahdi_pvt *p;
16861
16863 for (p = iflist; p; p = p->next) {
16864 if (p->channel == channel) {
16865 break;
16866 }
16867 }
16869 return p;
16870}
16871
16872/*!
16873 * \internal
16874 * \brief Get private struct using given numeric channel string.
16875 *
16876 * \param channel Numeric channel number string get private struct.
16877 *
16878 * \retval pvt on success.
16879 * \retval NULL on error.
16880 */
16881static struct dahdi_pvt *find_channel_from_str(const char *channel)
16882{
16883 int chan_num;
16884
16885 if (sscanf(channel, "%30d", &chan_num) != 1) {
16886 /* Not numeric string. */
16887 return NULL;
16888 }
16889
16890 return find_channel(chan_num);
16891}
16892
16893static int print_subchannel(struct dahdi_pvt *p, int subchan, char *buffer, size_t len)
16894{
16895 if (!p->subs[subchan].owner) {
16896 return -1;
16897 }
16898 ast_channel_lock(p->subs[subchan].owner);
16899 snprintf(buffer, len, "%s", ast_channel_name(p->subs[subchan].owner));
16900 ast_channel_unlock(p->subs[subchan].owner);
16901 return 0;
16902}
16903
16904#define REQUIRE_FXO_SIG() \
16905 if (!(dahdip->sigtype & __DAHDI_SIG_FXO)) { \
16906 ast_log(LOG_WARNING, "DAHDI channel %d is not FXO signalled\n", p->channel); \
16907 return -1; \
16908 }
16909
16910static int dahdichan_read_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, char *buffer, size_t len)
16911{
16912 struct analog_pvt *analog_p = p->sig_pvt;
16913
16914 /* R/O properties */
16915 if (!strcasecmp(property, "owner")) {
16916 return print_subchannel(p, SUB_REAL, buffer, len);
16917 } else if (!strcasecmp(property, "callwait")) {
16918 return print_subchannel(p, SUB_CALLWAIT, buffer, len);
16919 } else if (!strcasecmp(property, "threeway")) {
16920 return print_subchannel(p, SUB_THREEWAY, buffer, len);
16921 /* R/W properties */
16922 } else if (!strcasecmp(property, "polarity")) {
16924 snprintf(buffer, len, "%d", p->polarity);
16925 } else if (!strcasecmp(property, "dnd")) {
16927 snprintf(buffer, len, "%d", analog_p->dnd);
16928 } else if (!strcasecmp(property, "callforward")) {
16930 snprintf(buffer, len, "%s", analog_p->call_forward);
16931 } else if (!strcasecmp(property, "lastexten")) {
16933 snprintf(buffer, len, "%s", analog_p->lastexten);
16934 } else {
16935 ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
16936 return -1;
16937 }
16938 return 0;
16939}
16940
16941static int dahdichan_write_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, const char *value)
16942{
16943 struct analog_pvt *analog_p = p->sig_pvt;
16944
16945 /* We don't need to check ast_strlen_zero(value) because it's obviously not NULL.
16946 * It may even be okay for it to be an empty string, but that's a per-setting thing. */
16947
16948 /* R/O properties */
16949 if (!strcasecmp(property, "owner") || !strcasecmp(property, "callwait") || !strcasecmp(property, "threeway")) {
16950 ast_log(LOG_ERROR, "DAHDI subchannel names are R/O\n");
16951 return -1;
16952 /* R/W properties */
16953 } else if (!strcasecmp(property, "polarity")) {
16954 int polarity = atoi(value);
16957 ast_log(LOG_ERROR, "Invalid polarity: '%s'\n", value);
16958 return -1;
16959 }
16961 } else if (!strcasecmp(property, "dnd")) {
16962 int dnd = atoi(value);
16964 analog_dnd(analog_p, dnd ? 1 : 0);
16965 } else if (!strcasecmp(property, "callforward")) {
16967 if (strlen(value) >= sizeof(analog_p->call_forward) - 1) {
16968 ast_log(LOG_ERROR, "Provided call forwarding target '%s' is too long\n", value);
16969 }
16970 ast_copy_string(analog_p->call_forward, value, sizeof(analog_p->call_forward)); /* Could be empty to clear value */
16971 } else if (!strcasecmp(property, "lastexten")) {
16973 if (strlen(value) >= sizeof(analog_p->lastexten) - 1) {
16974 ast_log(LOG_ERROR, "Provided lastexten target '%s' is too long\n", value);
16975 }
16976 ast_copy_string(analog_p->lastexten, value, sizeof(analog_p->lastexten)); /* Could be empty to clear value */
16977 } else {
16978 ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
16979 return -1;
16980 }
16981 return 0;
16982}
16983#undef REQUIRE_FXO_SIG
16984
16985static int dahdichan_helper(struct ast_channel *chan, char *data, const char *value, char *buffer, size_t buflen)
16986{
16987 char *parse;
16988 struct dahdi_pvt *pvt;
16989 struct dahdi_params dahdip;
16990 int res;
16992 AST_APP_ARG(property);
16993 AST_APP_ARG(dahdichan);
16994 );
16995
16996 parse = ast_strdupa(data);
16998
16999 if (buflen > 0) {
17000 *buffer = '\0';
17001 }
17002
17003 if (!ast_strlen_zero(args.dahdichan)) {
17004 /* DAHDI channel number explicitly provided, find it. */
17005 int channo = atoi(args.dahdichan);
17006 pvt = find_channel(channo);
17007 if (!pvt) {
17008 ast_log(LOG_ERROR, "DAHDI channel %d does not exist\n", channo);
17009 return -1;
17010 }
17011 } else {
17012 /* No channel specified explicitly, so implicitly use the current channel, in which case it must be a DAHDI channel. */
17013 if (!chan || !ast_channel_tech(chan) || strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17014 ast_log(LOG_WARNING, "%s is not a DAHDI channel, and no DAHDI channel specified\n", ast_channel_name(chan));
17015 return -1;
17016 }
17017 pvt = ast_channel_tech_pvt(chan);
17018 }
17019
17020 memset(&dahdip, 0, sizeof(dahdip));
17021 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17022 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->channel, strerror(errno));
17023 return -1;
17024 }
17025
17026 /* We have the channel private to use. */
17027 ast_mutex_lock(&pvt->lock);
17028 if (value) {
17029 res = dahdichan_write_property(pvt, &dahdip, args.property, value);
17030 } else {
17031 res = dahdichan_read_property(pvt, &dahdip, args.property, buffer, buflen);
17032 }
17033 ast_mutex_unlock(&pvt->lock);
17034 return res;
17035}
17036
17037static int dahdichan_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
17038{
17039 return dahdichan_helper(chan, data, NULL, buffer, buflen);
17040}
17041
17042static int dahdichan_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
17043{
17044 return dahdichan_helper(chan, data, value, NULL, 0);
17045}
17046
17048 .name = "DAHDI_CHANNEL",
17049 .write = dahdichan_write,
17050 .read = dahdichan_read,
17051};
17052
17053/*! \todo The standalone POLARITY function can and should be deprecated/removed, since its functionality is now part of DAHDI_CHANNEL. */
17054
17055static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
17056{
17057 struct dahdi_params dahdip;
17058 struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
17059 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17060 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
17061 return -1;
17062 }
17063 memset(&dahdip, 0, sizeof(dahdip));
17064 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17065 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
17066 return -1;
17067 }
17068 return dahdichan_read_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", buffer, buflen);
17069}
17070
17071static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
17072{
17073 struct dahdi_params dahdip;
17074 struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
17075 if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
17076 ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
17077 return -1;
17078 }
17079 memset(&dahdip, 0, sizeof(dahdip));
17080 if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
17081 ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
17082 return -1;
17083 }
17084 return dahdichan_write_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", value);
17085}
17086
17088 .name = "POLARITY",
17089 .write = polarity_write,
17090 .read = polarity_read,
17091};
17092
17093static int action_dahdidndon(struct mansession *s, const struct message *m)
17094{
17095 struct dahdi_pvt *p;
17096 const char *channel = astman_get_header(m, "DAHDIChannel");
17097
17098 if (ast_strlen_zero(channel)) {
17099 astman_send_error(s, m, "No channel specified");
17100 return 0;
17101 }
17103 if (!p) {
17104 astman_send_error(s, m, "No such channel");
17105 return 0;
17106 }
17107 dahdi_dnd(p, 1);
17108 astman_send_ack(s, m, "DND Enabled");
17109 return 0;
17110}
17111
17112static int action_dahdidndoff(struct mansession *s, const struct message *m)
17113{
17114 struct dahdi_pvt *p;
17115 const char *channel = astman_get_header(m, "DAHDIChannel");
17116
17117 if (ast_strlen_zero(channel)) {
17118 astman_send_error(s, m, "No channel specified");
17119 return 0;
17120 }
17122 if (!p) {
17123 astman_send_error(s, m, "No such channel");
17124 return 0;
17125 }
17126 dahdi_dnd(p, 0);
17127 astman_send_ack(s, m, "DND Disabled");
17128 return 0;
17129}
17130
17131static int action_transfer(struct mansession *s, const struct message *m)
17132{
17133 struct dahdi_pvt *p;
17134 const char *channel = astman_get_header(m, "DAHDIChannel");
17135
17136 if (ast_strlen_zero(channel)) {
17137 astman_send_error(s, m, "No channel specified");
17138 return 0;
17139 }
17141 if (!p) {
17142 astman_send_error(s, m, "No such channel");
17143 return 0;
17144 }
17145 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
17146 astman_send_error(s, m, "Channel signaling is not analog");
17147 return 0;
17148 }
17150 astman_send_ack(s, m, "DAHDITransfer");
17151 return 0;
17152}
17153
17154static int action_transferhangup(struct mansession *s, const struct message *m)
17155{
17156 struct dahdi_pvt *p;
17157 const char *channel = astman_get_header(m, "DAHDIChannel");
17158
17159 if (ast_strlen_zero(channel)) {
17160 astman_send_error(s, m, "No channel specified");
17161 return 0;
17162 }
17164 if (!p) {
17165 astman_send_error(s, m, "No such channel");
17166 return 0;
17167 }
17168 if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
17169 astman_send_error(s, m, "Channel signaling is not analog");
17170 return 0;
17171 }
17173 astman_send_ack(s, m, "DAHDIHangup");
17174 return 0;
17175}
17176
17177static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
17178{
17179 struct dahdi_pvt *p;
17180 const char *channel = astman_get_header(m, "DAHDIChannel");
17181 const char *number = astman_get_header(m, "Number");
17182 int i;
17183
17184 if (ast_strlen_zero(channel)) {
17185 astman_send_error(s, m, "No channel specified");
17186 return 0;
17187 }
17188 if (ast_strlen_zero(number)) {
17189 astman_send_error(s, m, "No number specified");
17190 return 0;
17191 }
17193 if (!p) {
17194 astman_send_error(s, m, "No such channel");
17195 return 0;
17196 }
17197 if (!p->owner) {
17198 astman_send_error(s, m, "Channel does not have it's owner");
17199 return 0;
17200 }
17201 for (i = 0; i < strlen(number); i++) {
17202 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = number[i] };
17203 dahdi_queue_frame(p, &f);
17204 }
17205 astman_send_ack(s, m, "DAHDIDialOffhook");
17206 return 0;
17207}
17208
17209static int action_dahdishowchannels(struct mansession *s, const struct message *m)
17210{
17211 struct dahdi_pvt *tmp = NULL;
17212 const char *id = astman_get_header(m, "ActionID");
17213 const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
17214 char idText[256];
17215 int channels = 0;
17216 int dahdichanquery;
17217
17218 if (!dahdichannel || sscanf(dahdichannel, "%30d", &dahdichanquery) != 1) {
17219 /* Not numeric string. */
17220 dahdichanquery = -1;
17221 }
17222
17223 idText[0] = '\0';
17224 if (!ast_strlen_zero(id)) {
17225 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17226 }
17227
17228 astman_send_listack(s, m, "DAHDI channel status will follow", "start");
17229
17231
17232 for (tmp = iflist; tmp; tmp = tmp->next) {
17233 if (tmp->channel > 0) {
17234 int alm;
17235
17236 /* If a specific channel is queried for, only deliver status for that channel */
17237 if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
17238 continue;
17239
17240 alm = get_alarms(tmp);
17241 channels++;
17242 if (tmp->owner) {
17243 /* Add data if we have a current call */
17244 astman_append(s,
17245 "Event: DAHDIShowChannels\r\n"
17246 "DAHDIChannel: %d\r\n"
17247 "Channel: %s\r\n"
17248 "Uniqueid: %s\r\n"
17249 "AccountCode: %s\r\n"
17250 "Signalling: %s\r\n"
17251 "SignallingCode: %d\r\n"
17252 "Context: %s\r\n"
17253 "DND: %s\r\n"
17254 "Alarm: %s\r\n"
17255 "Description: %s\r\n"
17256 "%s"
17257 "\r\n",
17258 tmp->channel,
17259 ast_channel_name(tmp->owner),
17262 sig2str(tmp->sig),
17263 tmp->sig,
17264 tmp->context,
17265 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17266 alarm2str(alm),
17267 tmp->description, idText);
17268 } else {
17269 astman_append(s,
17270 "Event: DAHDIShowChannels\r\n"
17271 "DAHDIChannel: %d\r\n"
17272 "Signalling: %s\r\n"
17273 "SignallingCode: %d\r\n"
17274 "Context: %s\r\n"
17275 "DND: %s\r\n"
17276 "Alarm: %s\r\n"
17277 "Description: %s\r\n"
17278 "%s"
17279 "\r\n",
17280 tmp->channel, sig2str(tmp->sig), tmp->sig,
17281 tmp->context,
17282 dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
17283 alarm2str(alm),
17284 tmp->description, idText);
17285 }
17286 }
17287 }
17288
17290
17291 astman_send_list_complete_start(s, m, "DAHDIShowChannelsComplete", channels);
17292 astman_append(s, "Items: %d\r\n", channels);
17294 return 0;
17295}
17296
17297static int action_dahdishowstatus(struct mansession *s, const struct message *m)
17298{
17299 const char *id = astman_get_header(m, "ActionID");
17300 int span;
17301 int res;
17302 char alarmstr[50];
17303 int ctl;
17304 char idText[256];
17305 int numspans = 0;
17306 struct dahdi_spaninfo spaninfo;
17307
17308 ctl = open("/dev/dahdi/ctl", O_RDWR);
17309 if (ctl < 0) {
17310 astman_send_error(s, m, "No DAHDI detected");
17311 return 0;
17312 }
17313
17314 idText[0] = '\0';
17315 if (!ast_strlen_zero(id)) {
17316 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
17317 }
17318 astman_send_listack(s, m, "DAHDI span statuses will follow", "start");
17319
17320 for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
17321 spaninfo.spanno = span;
17322 res = ioctl(ctl, DAHDI_SPANSTAT, &spaninfo);
17323 if (res) {
17324 continue;
17325 }
17326 numspans++;
17327 build_alarm_info(alarmstr, &spaninfo);
17328 astman_append(s,
17329 "Event: DAHDIShowStatus\r\n"
17330 "Span: %d\r\n"
17331 "Description: %s\r\n"
17332 "Alarms: %s\r\n"
17333 "IRQ: %d\r\n"
17334 "bpviol: %d\r\n"
17335 "CRC: %d\r\n"
17336 "Framing: %s\r\n"
17337 "Coding: %s\r\n"
17338 "Options: %s\r\n"
17339 "LBO: %s\r\n"
17340 "%s"
17341 "\r\n",
17342 span, spaninfo.desc, alarmstr, spaninfo.irqmisses, spaninfo.bpvcount, spaninfo.crc4count,
17343 spaninfo.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
17344 spaninfo.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
17345 spaninfo.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
17346 "CAS",
17347 spaninfo.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
17348 spaninfo.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
17349 spaninfo.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
17350 "Unk",
17351 spaninfo.lineconfig & DAHDI_CONFIG_CRC4 ?
17352 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" :
17353 spaninfo.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : "",
17354 lbostr[spaninfo.lbo],
17355 idText);
17356 }
17357 close(ctl);
17358
17359 astman_send_list_complete_start(s, m, "DAHDIShowStatusComplete", numspans);
17360 astman_append(s, "Items: %d\r\n", numspans);
17362 return 0;
17363}
17364
17365#if defined(HAVE_PRI)
17366static int action_prishowspans(struct mansession *s, const struct message *m)
17367{
17368 int count;
17369 int idx;
17370 int span_query;
17371 struct dahdi_pri *dspan;
17372 const char *id = astman_get_header(m, "ActionID");
17373 const char *span_str = astman_get_header(m, "Span");
17374 char action_id[256];
17375 const char *show_cmd = "PRIShowSpans";
17376
17377 /* NOTE: Asking for span 0 gets all spans. */
17378 if (!ast_strlen_zero(span_str)) {
17379 span_query = atoi(span_str);
17380 } else {
17381 span_query = 0;
17382 }
17383
17384 if (!ast_strlen_zero(id)) {
17385 snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
17386 } else {
17387 action_id[0] = '\0';
17388 }
17389
17390 astman_send_listack(s, m, "Span status will follow", "start");
17391
17392 count = 0;
17393 for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
17394 dspan = &pris[idx];
17395
17396 /* If a specific span is asked for, only deliver status for that span. */
17397 if (0 < span_query && dspan->pri.span != span_query) {
17398 continue;
17399 }
17400
17401 if (dspan->pri.pri) {
17402 count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
17403 action_id);
17404 }
17405 }
17406
17407 astman_send_list_complete_start(s, m, "PRIShowSpansComplete", count);
17408 astman_append(s, "Items: %d\r\n", count);
17410 return 0;
17411}
17412#endif /* defined(HAVE_PRI) */
17413
17414#if defined(HAVE_SS7)
17415static int linkset_addsigchan(int sigchan)
17416{
17417 struct dahdi_ss7 *link;
17418 int res;
17419 int curfd;
17420 struct dahdi_params params;
17421 struct dahdi_bufferinfo bi;
17422 struct dahdi_spaninfo si;
17423
17424 if (sigchan < 0) {
17425 ast_log(LOG_ERROR, "Invalid sigchan!\n");
17426 return -1;
17427 }
17428 if (cur_ss7type < 0) {
17429 ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
17430 return -1;
17431 }
17432 if (cur_pointcode < 0) {
17433 ast_log(LOG_ERROR, "Unspecified pointcode!\n");
17434 return -1;
17435 }
17436 if (cur_adjpointcode < 0) {
17437 ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
17438 return -1;
17439 }
17440 if (cur_defaultdpc < 0) {
17441 ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
17442 return -1;
17443 }
17444 if (cur_networkindicator < 0) {
17445 ast_log(LOG_ERROR, "Invalid networkindicator!\n");
17446 return -1;
17447 }
17448 link = ss7_resolve_linkset(cur_linkset);
17449 if (!link) {
17450 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
17451 return -1;
17452 }
17453 if (link->ss7.numsigchans >= SIG_SS7_NUM_DCHANS) {
17454 ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
17455 return -1;
17456 }
17457
17458 curfd = link->ss7.numsigchans;
17459
17460 /* Open signaling channel */
17461 link->ss7.fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
17462 if (link->ss7.fds[curfd] < 0) {
17463 ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan,
17464 strerror(errno));
17465 return -1;
17466 }
17467 if (ioctl(link->ss7.fds[curfd], DAHDI_SPECIFY, &sigchan) == -1) {
17468 dahdi_close_ss7_fd(link, curfd);
17469 ast_log(LOG_ERROR, "Unable to specify SS7 sigchan %d (%s)\n", sigchan,
17470 strerror(errno));
17471 return -1;
17472 }
17473
17474 /* Get signaling channel parameters */
17475 memset(&params, 0, sizeof(params));
17476 res = ioctl(link->ss7.fds[curfd], DAHDI_GET_PARAMS, &params);
17477 if (res) {
17478 dahdi_close_ss7_fd(link, curfd);
17479 ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan,
17480 strerror(errno));
17481 return -1;
17482 }
17483 if (params.sigtype != DAHDI_SIG_HDLCFCS
17484 && params.sigtype != DAHDI_SIG_HARDHDLC
17485 && params.sigtype != DAHDI_SIG_MTP2) {
17486 dahdi_close_ss7_fd(link, curfd);
17487 ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
17488 return -1;
17489 }
17490
17491 /* Set signaling channel buffer policy. */
17492 memset(&bi, 0, sizeof(bi));
17493 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
17494 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
17495 bi.numbufs = 32;
17496 bi.bufsize = 512;
17497 if (ioctl(link->ss7.fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
17498 ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n",
17499 sigchan, strerror(errno));
17500 dahdi_close_ss7_fd(link, curfd);
17501 return -1;
17502 }
17503
17504 /* Get current signaling channel alarm status. */
17505 memset(&si, 0, sizeof(si));
17506 res = ioctl(link->ss7.fds[curfd], DAHDI_SPANSTAT, &si);
17507 if (res) {
17508 dahdi_close_ss7_fd(link, curfd);
17509 ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan,
17510 strerror(errno));
17511 }
17512
17513 res = sig_ss7_add_sigchan(&link->ss7, curfd, cur_ss7type,
17514 (params.sigtype == DAHDI_SIG_MTP2)
17515 ? SS7_TRANSPORT_DAHDIMTP2
17516 : SS7_TRANSPORT_DAHDIDCHAN,
17517 si.alarms, cur_networkindicator, cur_pointcode, cur_adjpointcode, cur_slc);
17518 if (res) {
17519 dahdi_close_ss7_fd(link, curfd);
17520 return -1;
17521 }
17522
17523 ++link->ss7.numsigchans;
17524
17525 return 0;
17526}
17527#endif /* defined(HAVE_SS7) */
17528
17529#if defined(HAVE_SS7)
17530static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17531{
17532 int span;
17533 switch (cmd) {
17534 case CLI_INIT:
17535 e->command = "ss7 set debug {on|off} linkset";
17536 e->usage =
17537 "Usage: ss7 set debug {on|off} linkset <linkset>\n"
17538 " Enables debugging on a given SS7 linkset\n";
17539 return NULL;
17540 case CLI_GENERATE:
17541 return NULL;
17542 }
17543
17544 if (a->argc < 6) {
17545 return CLI_SHOWUSAGE;
17546 }
17547
17548 span = atoi(a->argv[5]);
17549 if ((span < 1) || (span > NUM_SPANS)) {
17550 ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS);
17551 return CLI_SUCCESS;
17552 }
17553 if (!linksets[span-1].ss7.ss7) {
17554 ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
17555 } else {
17556 if (!strcasecmp(a->argv[3], "on")) {
17557 linksets[span - 1].ss7.debug = 1;
17558 ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
17559 ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
17560 } else {
17561 linksets[span - 1].ss7.debug = 0;
17562 ss7_set_debug(linksets[span-1].ss7.ss7, 0);
17563 ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
17564 }
17565 }
17566
17567 return CLI_SUCCESS;
17568}
17569#endif /* defined(HAVE_SS7) */
17570
17571#if defined(HAVE_SS7)
17572static char *handle_ss7_cic_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17573{
17574 int linkset, cic;
17575 int blocked, i;
17576 int do_block = 0;
17577 unsigned int dpc;
17578
17579 switch (cmd) {
17580 case CLI_INIT:
17581 e->command = "ss7 {block|unblock} cic";
17582 e->usage =
17583 "Usage: ss7 {block|unblock} cic <linkset> <dpc> <CIC>\n"
17584 " Sends a remote {blocking|unblocking} request for the given CIC on the specified linkset\n";
17585 return NULL;
17586 case CLI_GENERATE:
17587 return NULL;
17588 }
17589
17590 if (a->argc == 6) {
17591 linkset = atoi(a->argv[3]);
17592 } else {
17593 return CLI_SHOWUSAGE;
17594 }
17595
17596 if (!strcasecmp(a->argv[1], "block")) {
17597 do_block = 1;
17598 } else if (strcasecmp(a->argv[1], "unblock")) {
17599 return CLI_SHOWUSAGE;
17600 }
17601
17602 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17603 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17604 return CLI_SUCCESS;
17605 }
17606
17607 if (!linksets[linkset-1].ss7.ss7) {
17608 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17609 return CLI_SUCCESS;
17610 }
17611
17612 cic = atoi(a->argv[5]);
17613 if (cic < 1) {
17614 ast_cli(a->fd, "Invalid CIC specified!\n");
17615 return CLI_SUCCESS;
17616 }
17617
17618 dpc = atoi(a->argv[4]);
17619 if (dpc < 1) {
17620 ast_cli(a->fd, "Invalid DPC specified!\n");
17621 return CLI_SUCCESS;
17622 }
17623
17624 for (i = 0; i < linksets[linkset-1].ss7.numchans; i++) {
17625 if (linksets[linkset-1].ss7.pvts[i] && linksets[linkset-1].ss7.pvts[i]->cic == cic && linksets[linkset-1].ss7.pvts[i]->dpc == dpc) {
17626 blocked = linksets[linkset-1].ss7.pvts[i]->locallyblocked;
17627 if (!do_block ^ !(blocked & SS7_BLOCKED_MAINTENANCE)) {
17628 if (sig_ss7_cic_blocking(&linksets[linkset-1].ss7, do_block, i) < 0) {
17629 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17630 } else {
17631 ast_cli(a->fd, "Sent %sblocking request for linkset %d on CIC %d DPC %d\n", (do_block) ? "" : "un", linkset, cic, dpc);
17632 }
17633 } else if (!do_block && blocked) {
17634 ast_cli(a->fd, "CIC %d is hardware locally blocked!\n", cic);
17635 } else {
17636 ast_cli(a->fd, "CIC %d %s locally blocked\n", cic, do_block ? "already" : "is not");
17637 }
17638 return CLI_SUCCESS;
17639 }
17640 }
17641
17642 ast_cli(a->fd, "Invalid CIC specified!\n");
17643 return CLI_SUCCESS;
17644}
17645#endif /* defined(HAVE_SS7) */
17646
17647#if defined(HAVE_SS7)
17648static char *handle_ss7_linkset_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17649{
17650 int linkset, i;
17651 enum {
17652 DO_BLOCK,
17653 DO_UNBLOCK,
17654 DO_RESET,
17655 } do_what;
17656
17657 switch (cmd) {
17658 case CLI_INIT:
17659 e->command = "ss7 {reset|block|unblock} linkset";
17660 e->usage =
17661 "Usage: ss7 {reset|block|unblock} linkset <linkset number>\n"
17662 " Sends a remote {reset|blocking|unblocking} request for all CICs on the given linkset\n";
17663 return NULL;
17664 case CLI_GENERATE:
17665 return NULL;
17666 }
17667
17668 if (a->argc == 4) {
17669 linkset = atoi(a->argv[3]);
17670 } else {
17671 return CLI_SHOWUSAGE;
17672 }
17673
17674 if (!strcasecmp(a->argv[1], "block")) {
17675 do_what = DO_BLOCK;
17676 } else if (!strcasecmp(a->argv[1], "unblock")) {
17677 do_what = DO_UNBLOCK;
17678 } else if (!strcasecmp(a->argv[1], "reset")) {
17679 do_what = DO_RESET;
17680 } else {
17681 return CLI_SHOWUSAGE;
17682 }
17683
17684 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17685 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17686 return CLI_SUCCESS;
17687 }
17688
17689 if (!linksets[linkset - 1].ss7.ss7) {
17690 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17691 return CLI_SUCCESS;
17692 }
17693
17694 for (i = 0; i < linksets[linkset - 1].ss7.numchans; i++) {
17695 /* XXX Should be done with GRS/CGB/CGU instead - see ss7_reset_linkset() */
17696 if (linksets[linkset - 1].ss7.pvts[i]) {
17697 switch (do_what) {
17698 case DO_BLOCK:
17699 case DO_UNBLOCK:
17700 if (sig_ss7_cic_blocking(&linksets[linkset - 1].ss7, do_what == DO_BLOCK, i)) {
17701 ast_cli(a->fd, "Sent remote %s request on CIC %d\n",
17702 (do_what == DO_BLOCK) ? "blocking" : "unblocking",
17703 linksets[linkset - 1].ss7.pvts[i]->cic);
17704 }
17705 break;
17706 case DO_RESET:
17707 if (sig_ss7_reset_cic(&linksets[linkset - 1].ss7,
17708 linksets[linkset - 1].ss7.pvts[i]->cic,
17709 linksets[linkset - 1].ss7.pvts[i]->dpc)) {
17710 ast_cli(a->fd, "Sent reset request on CIC %d\n",
17711 linksets[linkset - 1].ss7.pvts[i]->cic);
17712 }
17713 break;
17714 }
17715 }
17716 }
17717
17718 return CLI_SUCCESS;
17719}
17720#endif /* defined(HAVE_SS7) */
17721
17722#if defined(HAVE_SS7)
17723static char *handle_ss7_group_blocking(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17724{
17725 int linkset, cic, range, chanpos;
17726 int i, dpc, orient = 0;
17727 int do_block = 0;
17728 unsigned char state[255];
17729
17730 switch (cmd) {
17731 case CLI_INIT:
17732 e->command = "ss7 {block|unblock} group";
17733 e->usage =
17734 "Usage: ss7 {block|unblock} group <linkset> <dpc> <1st. CIC> <range> [H]\n"
17735 " Sends a remote {blocking|unblocking} request for CIC range on the specified linkset\n";
17736 return NULL;
17737 case CLI_GENERATE:
17738 return NULL;
17739 }
17740
17741 if (a->argc == 7 || a->argc == 8) {
17742 linkset = atoi(a->argv[3]);
17743 } else {
17744 return CLI_SHOWUSAGE;
17745 }
17746
17747 if (!strcasecmp(a->argv[1], "block")) {
17748 do_block = 1;
17749 } else if (strcasecmp(a->argv[1], "unblock")) {
17750 return CLI_SHOWUSAGE;
17751 }
17752
17753 if (a->argc == 8) {
17754 if (!strcasecmp(a->argv[7], "H")) {
17755 orient = 1;
17756 } else {
17757 return CLI_SHOWUSAGE;
17758 }
17759 }
17760
17761 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17762 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17763 return CLI_SUCCESS;
17764 }
17765
17766 if (!linksets[linkset-1].ss7.ss7) {
17767 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17768 return CLI_SUCCESS;
17769 }
17770
17771 cic = atoi(a->argv[5]);
17772 if (cic < 1) {
17773 ast_cli(a->fd, "Invalid CIC specified!\n");
17774 return CLI_SUCCESS;
17775 }
17776
17777 range = atoi(a->argv[6]);
17778 /* ITU-T Q.763 3.43 - range 0 is reserved, which makes a range of 2 CICs a minimum group */
17779 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17780 ast_cli(a->fd, "Invalid range specified!\n");
17781 return CLI_SUCCESS;
17782 }
17783
17784 dpc = atoi(a->argv[4]);
17785 if (dpc < 1) {
17786 ast_cli(a->fd, "Invalid DPC specified!\n");
17787 return CLI_SUCCESS;
17788 }
17789
17790 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17791 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17792 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17793 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17794 return CLI_SHOWUSAGE;
17795 }
17796
17797 memset(state, 0, sizeof(state));
17798 for (i = 0; i <= range; ++i) {
17799 state[i] = 1;
17800 }
17801
17802 /* We are guaranteed to find chanpos because of sig_ss7_find_cic_range() includes it. */
17803 chanpos = sig_ss7_find_cic(&linksets[linkset-1].ss7, cic, dpc);
17804 if (sig_ss7_group_blocking(&linksets[linkset-1].ss7, do_block, chanpos, cic + range, state, orient)) {
17805 ast_cli(a->fd, "Unable allocate new ss7call\n");
17806 } else {
17807 ast_cli(a->fd, "Sending remote%s %sblocking request linkset %d on CIC %d range %d\n",
17808 orient ? " hardware" : "", do_block ? "" : "un", linkset, cic, range);
17809 }
17810
17811 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17812
17813 /* Break poll on the linkset so it sends our messages */
17814 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17815 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17816 }
17817 return CLI_SUCCESS;
17818}
17819#endif /* defined(HAVE_SS7) */
17820
17821#if defined(HAVE_SS7)
17822static char *handle_ss7_group_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17823{
17824 int linkset, cic, range;
17825 unsigned int dpc;
17826
17827 switch (cmd) {
17828 case CLI_INIT:
17829 e->command = "ss7 reset group";
17830 e->usage =
17831 "Usage: ss7 reset group <linkset> <dpc> <1st CIC> <range>\n"
17832 " Send a GRS for the given CIC range on the specified linkset\n";
17833 return NULL;
17834 case CLI_GENERATE:
17835 return NULL;
17836 }
17837
17838 if (a->argc == 7) {
17839 linkset = atoi(a->argv[3]);
17840 } else {
17841 return CLI_SHOWUSAGE;
17842 }
17843
17844 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17845 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
17846 return CLI_SUCCESS;
17847 }
17848
17849 if (!linksets[linkset-1].ss7.ss7) {
17850 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17851 return CLI_SUCCESS;
17852 }
17853
17854 cic = atoi(a->argv[5]);
17855
17856 if (cic < 1) {
17857 ast_cli(a->fd, "Invalid CIC specified!\n");
17858 return CLI_SUCCESS;
17859 }
17860
17861 range = atoi(a->argv[6]);
17862 if (range < 1 || range > (linksets[linkset - 1].ss7.type == SS7_ANSI ? 24 : 31)) {
17863 ast_cli(a->fd, "Invalid range specified!\n");
17864 return CLI_SUCCESS;
17865 }
17866
17867 dpc = atoi(a->argv[4]);
17868 if (dpc < 1) {
17869 ast_cli(a->fd, "Invalid DPC specified!\n");
17870 return CLI_SUCCESS;
17871 }
17872
17873 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17874 if (!sig_ss7_find_cic_range(&linksets[linkset-1].ss7, cic, cic + range, dpc)) {
17875 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17876 ast_cli(a->fd, "Invalid CIC/RANGE\n");
17877 return CLI_SHOWUSAGE;
17878 }
17879
17880 if (sig_ss7_reset_group(&linksets[linkset-1].ss7, cic, dpc, range)) {
17881 ast_cli(a->fd, "Unable to allocate new ss7call\n");
17882 } else {
17883 ast_cli(a->fd, "GRS sent ... \n");
17884 }
17885
17886 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17887
17888 /* Break poll on the linkset so it sends our messages */
17889 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
17890 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
17891 }
17892 return CLI_SUCCESS;
17893}
17894#endif /* defined(HAVE_SS7) */
17895
17896#if defined(HAVE_SS7)
17897static char *handle_ss7_show_calls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17898{
17899 int linkset;
17900
17901 switch (cmd) {
17902 case CLI_INIT:
17903 e->command = "ss7 show calls";
17904 e->usage =
17905 "Usage: ss7 show calls <linkset>\n"
17906 " Show SS7 calls on the specified linkset\n";
17907 return NULL;
17908 case CLI_GENERATE:
17909 return NULL;
17910 }
17911
17912 if (a->argc == 4) {
17913 linkset = atoi(a->argv[3]);
17914 } else {
17915 return CLI_SHOWUSAGE;
17916 }
17917
17918 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17919 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17920 return CLI_SUCCESS;
17921 }
17922
17923 if (!linksets[linkset-1].ss7.ss7) {
17924 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17925 return CLI_SUCCESS;
17926 }
17927
17928 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
17929 isup_show_calls(linksets[linkset-1].ss7.ss7, &ast_cli, a->fd);
17930 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
17931
17932 return CLI_SUCCESS;
17933}
17934#endif /* defined(HAVE_SS7) */
17935
17936#if defined(HAVE_SS7)
17937static char *handle_ss7_reset_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17938{
17939 int linkset, cic, res;
17940 unsigned int dpc;
17941
17942 switch (cmd) {
17943 case CLI_INIT:
17944 e->command = "ss7 reset cic";
17945 e->usage =
17946 "Usage: ss7 reset cic <linkset> <dpc> <CIC>\n"
17947 " Send a RSC for the given CIC on the specified linkset\n";
17948 return NULL;
17949 case CLI_GENERATE:
17950 return NULL;
17951 }
17952
17953 if (a->argc == 6) {
17954 linkset = atoi(a->argv[3]);
17955 } else {
17956 return CLI_SHOWUSAGE;
17957 }
17958
17959 if ((linkset < 1) || (linkset > NUM_SPANS)) {
17960 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
17961 return CLI_SUCCESS;
17962 }
17963
17964 if (!linksets[linkset-1].ss7.ss7) {
17965 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
17966 return CLI_SUCCESS;
17967 }
17968
17969 cic = atoi(a->argv[5]);
17970
17971 if (cic < 1) {
17972 ast_cli(a->fd, "Invalid CIC specified!\n");
17973 return CLI_SUCCESS;
17974 }
17975
17976 dpc = atoi(a->argv[4]);
17977 if (dpc < 1) {
17978 ast_cli(a->fd, "Invalid DPC specified!\n");
17979 return CLI_SUCCESS;
17980 }
17981
17982 res = sig_ss7_reset_cic(&linksets[linkset-1].ss7, cic, dpc);
17983
17984 ast_cli(a->fd, "%s RSC for linkset %d on CIC %d DPC %d\n", res ? "Sent" : "Failed", linkset, cic, dpc);
17985
17986 return CLI_SUCCESS;
17987}
17988#endif /* defined(HAVE_SS7) */
17989
17990#if defined(HAVE_SS7)
17991static char *handle_ss7_net_mng(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
17992{
17993 int linkset;
17994 unsigned int slc;
17995 unsigned int arg = 0;
17996 const char *res;
17997
17998 switch (cmd) {
17999 case CLI_INIT:
18000 e->command = "ss7 mtp3";
18001 e->usage =
18002 "Usage: ss7 mtp3 <linkset> <slc> coo|coa|cbd|cba|eco|eca|tfp|tfa|lin|lun|lia|lua|lid|lfu <arg>\n"
18003 " Send a NET MNG message\n"
18004 " WARNING!!! WARNING!!! We are not a STP, just for testing/development purposes\n";
18005 return NULL;
18006 case CLI_GENERATE:
18007 return NULL;
18008 }
18009
18010 if (a->argc < 5) {
18011 return CLI_SHOWUSAGE;
18012 }
18013
18014 linkset = atoi(a->argv[2]);
18015 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18016 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
18017 return CLI_SUCCESS;
18018 }
18019 if (!linksets[linkset-1].ss7.ss7) {
18020 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18021 return CLI_SUCCESS;
18022 }
18023
18024 slc = atoi(a->argv[3]);
18025
18026 if (a->argc == 6) {
18027 arg = atoi(a->argv[5]);
18028 }
18029
18030 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
18031 res = mtp3_net_mng(linksets[linkset-1].ss7.ss7, slc, a->argv[4], arg);
18032 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
18033
18034 /* Break poll on the linkset so it sends our messages */
18035 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
18036 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
18037 }
18038
18039 ast_cli(a->fd, "%s", res);
18040
18041 return CLI_SUCCESS;
18042}
18043#endif /* defined(HAVE_SS7) */
18044
18045#if defined(HAVE_SS7)
18046static char *handle_ss7_mtp3_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18047{
18048 int linkset;
18049 unsigned int slc = 0;
18050
18051 switch (cmd) {
18052 case CLI_INIT:
18053 e->command = "ss7 restart mtp3";
18054 e->usage =
18055 "Usage: ss7 restart mtp3 <linkset> <slc>\n"
18056 " Restart link\n";
18057 return NULL;
18058 case CLI_GENERATE:
18059 return NULL;
18060 }
18061
18062 if (a->argc < 5) {
18063 return CLI_SHOWUSAGE;
18064 }
18065
18066 linkset = atoi(a->argv[3]);
18067 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18068 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[2], 1, NUM_SPANS);
18069 return CLI_SUCCESS;
18070 }
18071 if (!linksets[linkset-1].ss7.ss7) {
18072 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18073 return CLI_SUCCESS;
18074 }
18075
18076 slc = atoi(a->argv[4]);
18077
18078 ast_mutex_lock(&linksets[linkset-1].ss7.lock);
18079 mtp3_init_restart(linksets[linkset-1].ss7.ss7, slc);
18080 ast_mutex_unlock(&linksets[linkset-1].ss7.lock);
18081
18082 /* Break poll on the linkset so it sends our messages */
18083 if (linksets[linkset-1].ss7.master != AST_PTHREADT_NULL) {
18084 pthread_kill(linksets[linkset-1].ss7.master, SIGURG);
18085 }
18086
18087 return CLI_SUCCESS;
18088}
18089#endif /* defined(HAVE_SS7) */
18090
18091#if defined(HAVE_SS7)
18092static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18093{
18094 int linkset;
18095 struct sig_ss7_linkset *ss7;
18096 switch (cmd) {
18097 case CLI_INIT:
18098 e->command = "ss7 show linkset";
18099 e->usage =
18100 "Usage: ss7 show linkset <span>\n"
18101 " Shows the status of an SS7 linkset.\n";
18102 return NULL;
18103 case CLI_GENERATE:
18104 return NULL;
18105 }
18106
18107 if (a->argc < 4) {
18108 return CLI_SHOWUSAGE;
18109 }
18110
18111 linkset = atoi(a->argv[3]);
18112 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18113 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
18114 return CLI_SUCCESS;
18115 }
18116 ss7 = &linksets[linkset - 1].ss7;
18117 if (!ss7->ss7) {
18118 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18119 return CLI_SUCCESS;
18120 }
18121
18122 ast_cli(a->fd, "SS7 flags: 0x%x\n", ss7->flags);
18123 ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
18124 ast_cli(a->fd, "SS7 calling nai: %i\n", ss7->calling_nai);
18125 ast_cli(a->fd, "SS7 called nai: %i\n", ss7->called_nai);
18126 ast_cli(a->fd, "SS7 nationalprefix: %s\n", ss7->nationalprefix);
18127 ast_cli(a->fd, "SS7 internationalprefix: %s\n", ss7->internationalprefix);
18128 ast_cli(a->fd, "SS7 unknownprefix: %s\n", ss7->unknownprefix);
18129 ast_cli(a->fd, "SS7 networkroutedprefix: %s\n", ss7->networkroutedprefix);
18130 ast_cli(a->fd, "SS7 subscriberprefix: %s\n", ss7->subscriberprefix);
18131 ss7_show_linkset(ss7->ss7, &ast_cli, a->fd);
18132
18133 return CLI_SUCCESS;
18134}
18135#endif /* defined(HAVE_SS7) */
18136
18137#if defined(HAVE_SS7)
18138static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18139{
18140 int linkset;
18141
18142 switch (cmd) {
18143 case CLI_INIT:
18144 e->command = "ss7 show channels";
18145 e->usage =
18146 "Usage: ss7 show channels\n"
18147 " Displays SS7 channel information at a glance.\n";
18148 return NULL;
18149 case CLI_GENERATE:
18150 return NULL;
18151 }
18152
18153 if (a->argc != 3) {
18154 return CLI_SHOWUSAGE;
18155 }
18156
18158 for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
18159 if (linksets[linkset].ss7.ss7) {
18160 sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
18161 }
18162 }
18163 return CLI_SUCCESS;
18164}
18165#endif /* defined(HAVE_SS7) */
18166
18167#if defined(HAVE_SS7)
18168static char *handle_ss7_show_cics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18169{
18170#define FORMAT "%5s %5s %6s %12s %-12s\n"
18171#define FORMAT2 "%5i %5i %6i %12s %-12s\n"
18172 int i, linkset, dpc = 0;
18173 struct sig_ss7_linkset *ss7;
18174 char *state;
18175 char blocking[12];
18176
18177 switch (cmd) {
18178 case CLI_INIT:
18179 e->command = "ss7 show cics";
18180 e->usage =
18181 "Usage: ss7 show cics <linkset> [dpc]\n"
18182 " Shows the cics of an SS7 linkset.\n";
18183 return NULL;
18184 case CLI_GENERATE:
18185 return NULL;
18186 }
18187
18188 if (a->argc < 4 || a->argc > 5) {
18189 return CLI_SHOWUSAGE;
18190 }
18191
18192 linkset = atoi(a->argv[3]);
18193
18194 if ((linkset < 1) || (linkset > NUM_SPANS)) {
18195 ast_cli(a->fd, "Invalid linkset %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
18196 return CLI_SUCCESS;
18197 }
18198
18199 if (!linksets[linkset-1].ss7.ss7) {
18200 ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
18201 return CLI_SUCCESS;
18202 }
18203 ss7 = &linksets[linkset-1].ss7;
18204
18205 if (a->argc == 5) {
18206 dpc = atoi(a->argv[4]);
18207 if (dpc < 1) {
18208 ast_cli(a->fd, "Invalid DPC specified!\n");
18209 return CLI_SUCCESS;
18210 }
18211 }
18212
18213 ast_cli(a->fd, FORMAT, "CIC", "DPC", "DAHDI", "STATE", "BLOCKING");
18214
18215 for (i = 0; i < ss7->numchans; i++) {
18216 if (!dpc || (ss7->pvts[i] && ss7->pvts[i]->dpc == dpc)) {
18217 struct dahdi_pvt *p = ss7->pvts[i]->chan_pvt;
18218
18219 if (ss7->pvts[i]->owner) {
18220 state = "Used";
18221 } else if (ss7->pvts[i]->ss7call) {
18222 state = "Pending";
18223 } else if (!p->inservice) {
18224 state = "NotInServ";
18225 } else {
18226 state = "Idle";
18227 }
18228
18229 if (p->locallyblocked) {
18230 strcpy(blocking, "L:");
18232 strcat(blocking, "M");
18233 } else {
18234 strcat(blocking, " ");
18235 }
18236
18238 strcat(blocking, "H");
18239 } else {
18240 strcat(blocking, " ");
18241 }
18242 } else {
18243 strcpy(blocking, " ");
18244 }
18245
18246 if (p->remotelyblocked) {
18247 strcat(blocking, " R:");
18249 strcat(blocking, "M");
18250 } else {
18251 strcat(blocking, " ");
18252 }
18253
18255 strcat(blocking, "H");
18256 } else {
18257 strcat(blocking, " ");
18258 }
18259 }
18260
18261 ast_cli(a->fd, FORMAT2, ss7->pvts[i]->cic, ss7->pvts[i]->dpc, ss7->pvts[i]->channel, state, blocking);
18262 }
18263 }
18264
18265 return CLI_SUCCESS;
18266#undef FORMAT
18267#undef FORMAT2
18268}
18269#endif /* defined(HAVE_SS7) */
18270
18271#if defined(HAVE_SS7)
18272static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
18273{
18274 switch (cmd) {
18275 case CLI_INIT:
18276 e->command = "ss7 show version";
18277 e->usage =
18278 "Usage: ss7 show version\n"
18279 " Show the libss7 version\n";
18280 return NULL;
18281 case CLI_GENERATE:
18282 return NULL;
18283 }
18284
18285 ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
18286
18287 return CLI_SUCCESS;
18288}
18289#endif /* defined(HAVE_SS7) */
18290
18291#if defined(HAVE_SS7)
18292static struct ast_cli_entry dahdi_ss7_cli[] = {
18293 AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"),
18294 AST_CLI_DEFINE(handle_ss7_cic_blocking, "Blocks/Unblocks the given CIC"),
18295 AST_CLI_DEFINE(handle_ss7_linkset_mng, "Resets/Blocks/Unblocks all CICs on a linkset"),
18296 AST_CLI_DEFINE(handle_ss7_group_blocking, "Blocks/Unblocks the given CIC range"),
18297 AST_CLI_DEFINE(handle_ss7_reset_cic, "Resets the given CIC"),
18298 AST_CLI_DEFINE(handle_ss7_group_reset, "Resets the given CIC range"),
18299 AST_CLI_DEFINE(handle_ss7_mtp3_restart, "Restart a link"),
18300 AST_CLI_DEFINE(handle_ss7_net_mng, "Send an NET MNG message"),
18301 AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
18302 AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
18303 AST_CLI_DEFINE(handle_ss7_show_calls, "Show ss7 calls"),
18304 AST_CLI_DEFINE(handle_ss7_show_cics, "Show cics on a linkset"),
18305 AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
18306};
18307#endif /* defined(HAVE_SS7) */
18308
18309#if defined(HAVE_PRI)
18310#if defined(HAVE_PRI_CCSS)
18311/*!
18312 * \internal
18313 * \brief CC agent initialization.
18314 * \since 1.8
18315 *
18316 * \param agent CC core agent control.
18317 * \param chan Original channel the agent will attempt to recall.
18318 *
18319 * \details
18320 * This callback is called when the CC core is initialized. Agents should allocate
18321 * any private data necessary for the call and assign it to the private_data
18322 * on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the
18323 * specific agent type, they should be set in this function as well.
18324 *
18325 * \retval 0 on success.
18326 * \retval -1 on error.
18327 */
18328static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
18329{
18330 struct dahdi_pvt *pvt;
18331 struct sig_pri_chan *pvt_chan;
18332 int res;
18333
18334 ast_assert(!strcmp(ast_channel_tech(chan)->type, "DAHDI"));
18335
18336 pvt = ast_channel_tech_pvt(chan);
18337 if (dahdi_sig_pri_lib_handles(pvt->sig)) {
18338 pvt_chan = pvt->sig_pvt;
18339 } else {
18340 pvt_chan = NULL;
18341 }
18342 if (!pvt_chan) {
18343 return -1;
18344 }
18345
18347
18348 res = sig_pri_cc_agent_init(agent, pvt_chan);
18349 if (res) {
18351 }
18352 return res;
18353}
18354#endif /* defined(HAVE_PRI_CCSS) */
18355#endif /* defined(HAVE_PRI) */
18356
18357#if defined(HAVE_PRI)
18358#if defined(HAVE_PRI_CCSS)
18359/*!
18360 * \internal
18361 * \brief Destroy private data on the agent.
18362 * \since 1.8
18363 *
18364 * \param agent CC core agent control.
18365 *
18366 * \details
18367 * The core will call this function upon completion
18368 * or failure of CC.
18369 */
18370static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
18371{
18373
18375}
18376#endif /* defined(HAVE_PRI_CCSS) */
18377#endif /* defined(HAVE_PRI) */
18378
18379#if defined(HAVE_PRI)
18380#if defined(HAVE_PRI_CCSS)
18381static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
18382 .type = dahdi_pri_cc_type,
18383 .init = dahdi_pri_cc_agent_init,
18384 .start_offer_timer = sig_pri_cc_agent_start_offer_timer,
18385 .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
18386 .respond = sig_pri_cc_agent_req_rsp,
18387 .status_request = sig_pri_cc_agent_status_req,
18388 .stop_ringing = sig_pri_cc_agent_stop_ringing,
18389 .party_b_free = sig_pri_cc_agent_party_b_free,
18390 .start_monitoring = sig_pri_cc_agent_start_monitoring,
18391 .callee_available = sig_pri_cc_agent_callee_available,
18392 .destructor = dahdi_pri_cc_agent_destructor,
18393};
18394#endif /* defined(HAVE_PRI_CCSS) */
18395#endif /* defined(HAVE_PRI) */
18396
18397#if defined(HAVE_PRI)
18398#if defined(HAVE_PRI_CCSS)
18399static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
18400 .type = dahdi_pri_cc_type,
18401 .request_cc = sig_pri_cc_monitor_req_cc,
18402 .suspend = sig_pri_cc_monitor_suspend,
18403 .unsuspend = sig_pri_cc_monitor_unsuspend,
18404 .status_response = sig_pri_cc_monitor_status_rsp,
18405 .cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
18406 .destructor = sig_pri_cc_monitor_destructor,
18407};
18408#endif /* defined(HAVE_PRI_CCSS) */
18409#endif /* defined(HAVE_PRI) */
18410
18411static int __unload_module(void)
18412{
18413 struct dahdi_pvt *p;
18414#if defined(HAVE_PRI) || defined(HAVE_SS7)
18415 int i, j;
18416#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18417
18418#ifdef HAVE_PRI
18419 for (i = 0; i < NUM_SPANS; i++) {
18420 if (pris[i].pri.master != AST_PTHREADT_NULL) {
18421 pthread_cancel(pris[i].pri.master);
18422 pthread_kill(pris[i].pri.master, SIGURG);
18423 }
18424 }
18425 ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
18426 ast_unregister_application(dahdi_send_keypad_facility_app);
18427#ifdef HAVE_PRI_PROG_W_CAUSE
18428 ast_unregister_application(dahdi_send_callrerouting_facility_app);
18429#endif
18430#endif
18431#if defined(HAVE_SS7)
18432 for (i = 0; i < NUM_SPANS; i++) {
18433 if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
18434 pthread_cancel(linksets[i].ss7.master);
18435 pthread_kill(linksets[i].ss7.master, SIGURG);
18436 }
18437 }
18438 ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
18439#endif /* defined(HAVE_SS7) */
18440#if defined(HAVE_OPENR2)
18441 dahdi_r2_destroy_links();
18442 ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
18443 ast_unregister_application(dahdi_accept_r2_call_app);
18444#endif
18445
18448
18450 ast_manager_unregister("DAHDIDialOffhook");
18451 ast_manager_unregister("DAHDIHangup");
18452 ast_manager_unregister("DAHDITransfer");
18453 ast_manager_unregister("DAHDIDNDoff");
18454 ast_manager_unregister("DAHDIDNDon");
18455 ast_manager_unregister("DAHDIShowChannels");
18456 ast_manager_unregister("DAHDIShowStatus");
18457 ast_manager_unregister("DAHDIRestart");
18458#if defined(HAVE_PRI)
18459 ast_manager_unregister("PRIShowSpans");
18460 ast_manager_unregister("PRIDebugSet");
18461 ast_manager_unregister("PRIDebugFileSet");
18462 ast_manager_unregister("PRIDebugFileUnset");
18463#endif /* defined(HAVE_PRI) */
18465
18466 /* Hangup all interfaces if they have an owner */
18468 for (p = iflist; p; p = p->next) {
18469 if (p->owner)
18471 }
18473
18476 pthread_cancel(monitor_thread);
18477 pthread_kill(monitor_thread, SIGURG);
18478 pthread_join(monitor_thread, NULL);
18479 }
18482
18484
18485#if defined(HAVE_PRI)
18486 for (i = 0; i < NUM_SPANS; i++) {
18487 if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
18488 pthread_join(pris[i].pri.master, NULL);
18489 }
18490 for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
18491 dahdi_close_pri_fd(&(pris[i]), j);
18492 }
18493 sig_pri_stop_pri(&pris[i].pri);
18494 }
18495#if defined(HAVE_PRI_CCSS)
18496 ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
18497 ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
18498#endif /* defined(HAVE_PRI_CCSS) */
18500#endif
18501
18502#if defined(HAVE_SS7)
18503 for (i = 0; i < NUM_SPANS; i++) {
18504 if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
18505 pthread_join(linksets[i].ss7.master, NULL);
18506 }
18507 for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
18508 dahdi_close_ss7_fd(&(linksets[i]), j);
18509 }
18510 if (linksets[i].ss7.ss7) {
18511 ss7_destroy(linksets[i].ss7.ss7);
18512 linksets[i].ss7.ss7 = NULL;
18513 }
18514 }
18515#endif /* defined(HAVE_SS7) */
18517
18519
18522 STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
18523 return 0;
18524}
18525
18526static int unload_module(void)
18527{
18528#if defined(HAVE_PRI) || defined(HAVE_SS7)
18529 int y;
18530#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
18531#ifdef HAVE_PRI
18532 for (y = 0; y < NUM_SPANS; y++)
18533 ast_mutex_destroy(&pris[y].pri.lock);
18534#endif
18535#if defined(HAVE_SS7)
18536 for (y = 0; y < NUM_SPANS; y++)
18537 ast_mutex_destroy(&linksets[y].ss7.lock);
18538#endif /* defined(HAVE_SS7) */
18539 return __unload_module();
18540}
18541
18542static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
18543{
18544 char *c, *chan;
18545 int x, start, finish;
18546 struct dahdi_pvt *tmp;
18547
18548 if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
18549 ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
18550 return -1;
18551 }
18552
18553 c = ast_strdupa(value);
18554
18555 while ((chan = strsep(&c, ","))) {
18556 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
18557 /* Range */
18558 } else if (sscanf(chan, "%30d", &start)) {
18559 /* Just one */
18560 finish = start;
18561 } else if (!strcasecmp(chan, "pseudo")) {
18562 finish = start = CHAN_PSEUDO;
18563 } else {
18564 ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
18565 return -1;
18566 }
18567 if (finish < start) {
18568 ast_log(LOG_WARNING, "Silliness: %d < %d\n", start, finish);
18569 x = finish;
18570 finish = start;
18571 start = x;
18572 }
18573
18574 for (x = start; x <= finish; x++) {
18575 if (conf->wanted_channels_start &&
18576 (x < conf->wanted_channels_start ||
18577 x > conf->wanted_channels_end)
18578 ) {
18579 continue;
18580 }
18581 tmp = mkintf(x, conf, reload);
18582
18583 if (tmp) {
18584 ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
18585 } else {
18586 ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
18587 (reload == 1) ? "reconfigure" : "register", value);
18588 return -1;
18589 }
18590 if (x == CHAN_PSEUDO) {
18591 has_pseudo = 1;
18592 }
18593 }
18594 }
18595
18596 return 0;
18597}
18598
18599/** The length of the parameters list of 'dahdichan'.
18600 * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
18601#define MAX_CHANLIST_LEN 80
18602
18603static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
18604{
18605 char *parse = ast_strdupa(data);
18606 char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
18607 unsigned int param_count;
18608 unsigned int x;
18609
18610 if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
18611 return;
18612
18613 memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
18614
18615 /* first parameter is tap length, process it here */
18616
18617 x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
18618
18619 if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
18620 confp->chan.echocancel.head.tap_length = x;
18621 else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
18622 confp->chan.echocancel.head.tap_length = 128;
18623
18624 /* now process any remaining parameters */
18625
18626 for (x = 1; x < param_count; x++) {
18627 struct {
18628 char *name;
18629 char *value;
18630 } param;
18631
18632 if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
18633 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, params[x]);
18634 continue;
18635 }
18636
18637 if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
18638 ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %u: '%s'\n", line, param.name);
18639 continue;
18640 }
18641
18642 strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
18643
18644 if (param.value) {
18645 if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
18646 ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %u: '%s'\n", line, param.value);
18647 continue;
18648 }
18649 }
18650 confp->chan.echocancel.head.param_count++;
18651 }
18652}
18653
18654#if defined(HAVE_PRI)
18655#if defined(HAVE_PRI_DISPLAY_TEXT)
18656/*!
18657 * \internal
18658 * \brief Determine the configured display text options.
18659 * \since 10.0
18660 *
18661 * \param value Configuration value string.
18662 *
18663 * \return Configured display text option flags.
18664 */
18665static unsigned long dahdi_display_text_option(const char *value)
18666{
18667 char *val_str;
18668 char *opt_str;
18669 unsigned long options;
18670
18671 options = 0;
18672 val_str = ast_strdupa(value);
18673
18674 for (;;) {
18675 opt_str = strsep(&val_str, ",");
18676 if (!opt_str) {
18677 break;
18678 }
18679 opt_str = ast_strip(opt_str);
18680 if (!*opt_str) {
18681 continue;
18682 }
18683
18684 if (!strcasecmp(opt_str, "block")) {
18685 options |= PRI_DISPLAY_OPTION_BLOCK;
18686 } else if (!strcasecmp(opt_str, "name_initial")) {
18687 options |= PRI_DISPLAY_OPTION_NAME_INITIAL;
18688 } else if (!strcasecmp(opt_str, "name_update")) {
18689 options |= PRI_DISPLAY_OPTION_NAME_UPDATE;
18690 } else if (!strcasecmp(opt_str, "name")) {
18691 options |= (PRI_DISPLAY_OPTION_NAME_INITIAL | PRI_DISPLAY_OPTION_NAME_UPDATE);
18692 } else if (!strcasecmp(opt_str, "text")) {
18693 options |= PRI_DISPLAY_OPTION_TEXT;
18694 }
18695 }
18696 return options;
18697}
18698#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
18699#endif /* defined(HAVE_PRI) */
18700
18701#if defined(HAVE_PRI)
18702#if defined(HAVE_PRI_DATETIME_SEND)
18703/*!
18704 * \internal
18705 * \brief Determine the configured date/time send policy option.
18706 * \since 10.0
18707 *
18708 * \param value Configuration value string.
18709 *
18710 * \return Configured date/time send policy option.
18711 */
18712static int dahdi_datetime_send_option(const char *value)
18713{
18714 int option;
18715
18716 option = PRI_DATE_TIME_SEND_DEFAULT;
18717
18718 if (ast_false(value)) {
18719 option = PRI_DATE_TIME_SEND_NO;
18720 } else if (!strcasecmp(value, "date")) {
18721 option = PRI_DATE_TIME_SEND_DATE;
18722 } else if (!strcasecmp(value, "date_hh")) {
18723 option = PRI_DATE_TIME_SEND_DATE_HH;
18724 } else if (!strcasecmp(value, "date_hhmm")) {
18725 option = PRI_DATE_TIME_SEND_DATE_HHMM;
18726 } else if (!strcasecmp(value, "date_hhmmss")) {
18727 option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
18728 }
18729
18730 return option;
18731}
18732#endif /* defined(HAVE_PRI_DATETIME_SEND) */
18733#endif /* defined(HAVE_PRI) */
18734
18735/*! process_dahdi() - ignore keyword 'channel' and similar */
18736#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
18737/*! process_dahdi() - No warnings on non-existing configuration keywords */
18738#define PROC_DAHDI_OPT_NOWARN (1 << 1)
18739
18740static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
18741{
18742 int count_pattern = 0;
18743 int norval = 0;
18744 const char *temp = NULL;
18745
18746 for (; ;) {
18747 /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
18748 if (!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
18749 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18750 break;
18751 }
18752
18753 busy_cadence->pattern[count_pattern] = norval;
18754
18755 count_pattern++;
18756 if (count_pattern == 4) {
18757 break;
18758 }
18759
18760 temp = strchr(v->value, ',');
18761 if (temp == NULL) {
18762 break;
18763 }
18764 v->value = temp + 1;
18765 }
18766 busy_cadence->length = count_pattern;
18767
18768 if (count_pattern % 2 != 0) {
18769 /* The pattern length must be divisible by two */
18770 ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
18771 }
18772
18773}
18774
18775static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
18776{
18777 struct dahdi_pvt *tmp;
18778 int y;
18779 struct ast_variable *dahdichan = NULL;
18780
18781 /* Re-parse any cadences from beginning, rather than appending until we run out of room */
18783
18784 for (; v; v = v->next) {
18786 continue;
18787
18788 /* Create the interface list */
18789 if (!strcasecmp(v->name, "channel") || !strcasecmp(v->name, "channels")) {
18791 ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
18792 continue;
18793 }
18794 if (build_channels(confp, v->value, reload, v->lineno)) {
18795 if (confp->ignore_failed_channels) {
18796 ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
18797 continue;
18798 } else {
18799 return -1;
18800 }
18801 }
18802 ast_debug(1, "Channel '%s' configured.\n", v->value);
18803 } else if (!strcasecmp(v->name, "ignore_failed_channels")) {
18805 } else if (!strcasecmp(v->name, "buffers")) {
18806 if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
18807 ast_log(LOG_WARNING, "Using default buffer policy.\n");
18808 confp->chan.buf_no = numbufs;
18809 confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
18810 }
18811 } else if (!strcasecmp(v->name, "faxbuffers")) {
18812 if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
18813 confp->chan.usefaxbuffers = 1;
18814 }
18815 } else if (!strcasecmp(v->name, "dahdichan")) {
18816 /* Only process the last dahdichan value. */
18817 dahdichan = v;
18818 } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
18820 } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
18822 } else if (!strcasecmp(v->name, "dring1context")) {
18824 } else if (!strcasecmp(v->name, "dring2context")) {
18826 } else if (!strcasecmp(v->name, "dring3context")) {
18828 } else if (!strcasecmp(v->name, "dring1range")) {
18829 confp->chan.drings.ringnum[0].range = atoi(v->value);
18830 } else if (!strcasecmp(v->name, "dring2range")) {
18831 confp->chan.drings.ringnum[1].range = atoi(v->value);
18832 } else if (!strcasecmp(v->name, "dring3range")) {
18833 confp->chan.drings.ringnum[2].range = atoi(v->value);
18834 } else if (!strcasecmp(v->name, "dring1")) {
18835 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]);
18836 } else if (!strcasecmp(v->name, "dring2")) {
18837 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]);
18838 } else if (!strcasecmp(v->name, "dring3")) {
18839 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]);
18840 } else if (!strcasecmp(v->name, "usecallerid")) {
18841 confp->chan.use_callerid = ast_true(v->value);
18842 } else if (!strcasecmp(v->name, "cidsignalling")) {
18843 if (!strcasecmp(v->value, "bell"))
18845 else if (!strcasecmp(v->value, "v23"))
18847 else if (!strcasecmp(v->value, "dtmf"))
18849 else if (!strcasecmp(v->value, "smdi"))
18851 else if (!strcasecmp(v->value, "v23_jp"))
18853 else if (ast_true(v->value))
18855 } else if (!strcasecmp(v->name, "cidstart")) {
18856 if (!strcasecmp(v->value, "ring"))
18857 confp->chan.cid_start = CID_START_RING;
18858 else if (!strcasecmp(v->value, "polarity_in"))
18860 else if (!strcasecmp(v->value, "polarity"))
18862 else if (!strcasecmp(v->value, "dtmf"))
18864 else if (ast_true(v->value))
18865 confp->chan.cid_start = CID_START_RING;
18866 } else if (!strcasecmp(v->name, "threewaycalling")) {
18867 confp->chan.threewaycalling = ast_true(v->value);
18868 } else if (!strcasecmp(v->name, "threewaysilenthold")) {
18870 } else if (!strcasecmp(v->name, "cancallforward")) {
18871 confp->chan.cancallforward = ast_true(v->value);
18872 } else if (!strcasecmp(v->name, "relaxdtmf")) {
18873 if (ast_true(v->value))
18875 else
18876 confp->chan.dtmfrelax = 0;
18877 } else if (!strcasecmp(v->name, "mailbox")) {
18878 ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
18879 } else if (!strcasecmp(v->name, "description")) {
18880 ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
18881 } else if (!strcasecmp(v->name, "adsi")) {
18882 confp->chan.adsi = ast_true(v->value);
18883 } else if (!strcasecmp(v->name, "usesmdi")) {
18884 confp->chan.use_smdi = ast_true(v->value);
18885 } else if (!strcasecmp(v->name, "smdiport")) {
18886 ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
18887 } else if (!strcasecmp(v->name, "transfer")) {
18888 confp->chan.transfer = ast_true(v->value);
18889 } else if (!strcasecmp(v->name, "canpark")) {
18890 confp->chan.canpark = ast_true(v->value);
18891 } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
18892 confp->chan.echocanbridged = ast_true(v->value);
18893 } else if (!strcasecmp(v->name, "busydetect")) {
18894 confp->chan.busydetect = ast_true(v->value);
18895 } else if (!strcasecmp(v->name, "busycount")) {
18896 confp->chan.busycount = atoi(v->value);
18897 } else if (!strcasecmp(v->name, "busypattern")) {
18899 } else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18901 } else if (!strcasecmp(v->name, "lastnumredial")) {
18902 confp->chan.lastnumredial = ast_true(v->value);
18903 } else if (!strcasecmp(v->name, "callprogress")) {
18904 confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
18905 if (ast_true(v->value))
18907 } else if (!strcasecmp(v->name, "waitfordialtone")) {
18908 confp->chan.waitfordialtone = atoi(v->value);
18909 } else if (!strcasecmp(v->name, "dialtone_detect")) {
18910 if (!strcasecmp(v->value, "always")) {
18911 confp->chan.dialtone_detect = -1;
18912 } else if (ast_true(v->value)) {
18914 } else if (ast_false(v->value)) {
18915 confp->chan.dialtone_detect = 0;
18916 } else {
18917 confp->chan.dialtone_detect = ast_strlen_zero(v->value) ? 0 : (8 * atoi(v->value)) / READ_SIZE;
18918 }
18919 } else if (!strcasecmp(v->name, "faxdetect")) {
18920 confp->chan.callprogress &= ~CALLPROGRESS_FAX;
18921 if (!strcasecmp(v->value, "incoming")) {
18923 } else if (!strcasecmp(v->value, "outgoing")) {
18925 } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
18927 } else if (!strcasecmp(v->name, "faxdetect_timeout")) {
18928 if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) {
18929 confp->chan.faxdetect_timeout = 0;
18930 }
18931 } else if (!strcasecmp(v->name, "firstdigit_timeout")) {
18932 if (sscanf(v->value, "%30d", &confp->chan.firstdigit_timeout) != 1
18933 || confp->chan.firstdigit_timeout <= 0) {
18935 }
18936 } else if (!strcasecmp(v->name, "interdigit_timeout")) {
18937 if (sscanf(v->value, "%30d", &confp->chan.interdigit_timeout) != 1
18938 || confp->chan.interdigit_timeout <= 0) {
18940 }
18941 } else if (!strcasecmp(v->name, "matchdigit_timeout")) {
18942 if (sscanf(v->value, "%30d", &confp->chan.matchdigit_timeout) != 1
18943 || confp->chan.matchdigit_timeout <= 0) {
18945 }
18946 } else if (!strcasecmp(v->name, "echocancel")) {
18947 process_echocancel(confp, v->value, v->lineno);
18948 } else if (!strcasecmp(v->name, "echotraining")) {
18949 if (sscanf(v->value, "%30d", &y) == 1) {
18950 if ((y < 10) || (y > 4000)) {
18951 ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);
18952 } else {
18953 confp->chan.echotraining = y;
18954 }
18955 } else if (ast_true(v->value)) {
18956 confp->chan.echotraining = 400;
18957 } else
18958 confp->chan.echotraining = 0;
18959 } else if (!strcasecmp(v->name, "hidecallerid")) {
18960 confp->chan.hidecallerid = ast_true(v->value);
18961 } else if (!strcasecmp(v->name, "hidecalleridname")) {
18962 confp->chan.hidecalleridname = ast_true(v->value);
18963 } else if (!strcasecmp(v->name, "pulsedial")) {
18964 confp->chan.pulse = ast_true(v->value);
18965 } else if (!strcasecmp(v->name, "callreturn")) {
18966 confp->chan.callreturn = ast_true(v->value);
18967 } else if (!strcasecmp(v->name, "callwaiting")) {
18968 confp->chan.callwaiting = ast_true(v->value);
18969 } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
18971 } else if (!strcasecmp(v->name, "callwaitingdeluxe")) {
18972 confp->chan.callwaitingdeluxe = ast_true(v->value);
18973 } else if (!strcasecmp(v->name, "context")) {
18974 ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
18975 } else if (!strcasecmp(v->name, "language")) {
18976 ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
18977 } else if (!strcasecmp(v->name, "progzone")) {
18978 ast_copy_string(progzone, v->value, sizeof(progzone));
18979 } else if (!strcasecmp(v->name, "mohinterpret")
18980 ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
18981 ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
18982 } else if (!strcasecmp(v->name, "mohsuggest")) {
18983 ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
18984 } else if (!strcasecmp(v->name, "parkinglot")) {
18985 ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
18986 } else if (!strcasecmp(v->name, "stripmsd")) {
18987 ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
18988 confp->chan.stripmsd = atoi(v->value);
18989 } else if (!strcasecmp(v->name, "jitterbuffers")) {
18990 numbufs = atoi(v->value);
18991 } else if (!strcasecmp(v->name, "group")) {
18992 confp->chan.group = ast_get_group(v->value);
18993 } else if (!strcasecmp(v->name, "callgroup")) {
18994 if (!CHAN_IS_FXO_SIG(confp->chan.sig)) {
18995 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
18996 }
18997 if (!strcasecmp(v->value, "none"))
18998 confp->chan.callgroup = 0;
18999 else
19000 confp->chan.callgroup = ast_get_group(v->value);
19001 } else if (!strcasecmp(v->name, "pickupgroup")) {
19002 if (!CHAN_IS_FXO_SIG(confp->chan.sig)) {
19003 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
19004 }
19005 if (!strcasecmp(v->value, "none"))
19006 confp->chan.pickupgroup = 0;
19007 else
19008 confp->chan.pickupgroup = ast_get_group(v->value);
19009 } else if (!strcasecmp(v->name, "namedcallgroup")) {
19010 if (!CHAN_IS_FXO_SIG(confp->chan.sig)) {
19011 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
19012 }
19014 } else if (!strcasecmp(v->name, "namedpickupgroup")) {
19015 if (!CHAN_IS_FXO_SIG(confp->chan.sig)) {
19016 ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
19017 }
19019 } else if (!strcasecmp(v->name, "setvar")) {
19020 if (v->value) {
19021 char *varval = NULL;
19022 struct ast_variable *tmpvar;
19023 char varname[strlen(v->value) + 1];
19024 strcpy(varname, v->value); /* safe */
19025 if ((varval = strchr(varname, '='))) {
19026 *varval++ = '\0';
19027 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
19028 if (ast_variable_list_replace(&confp->chan.vars, tmpvar)) {
19029 tmpvar->next = confp->chan.vars;
19030 confp->chan.vars = tmpvar;
19031 }
19032 }
19033 }
19034 }
19035 } else if (!strcasecmp(v->name, "immediate")) {
19036 confp->chan.immediate = ast_true(v->value);
19037 } else if (!strcasecmp(v->name, "immediatering")) {
19038 confp->chan.immediatering = ast_true(v->value);
19039 } else if (!strcasecmp(v->name, "transfertobusy")) {
19040 confp->chan.transfertobusy = ast_true(v->value);
19041 } else if (!strcasecmp(v->name, "dialmode")) {
19042 if (!strcasecmp(v->value, "pulse")) {
19044 } else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
19046 } else if (!strcasecmp(v->value, "none")) {
19048 } else {
19050 }
19051 } else if (!strcasecmp(v->name, "mwimonitor")) {
19052 confp->chan.mwimonitor_neon = 0;
19053 confp->chan.mwimonitor_fsk = 0;
19054 confp->chan.mwimonitor_rpas = 0;
19055 if (strcasestr(v->value, "fsk")) {
19056 confp->chan.mwimonitor_fsk = 1;
19057 }
19058 if (strcasestr(v->value, "rpas")) {
19059 confp->chan.mwimonitor_rpas = 1;
19060 }
19061 if (strcasestr(v->value, "neon")) {
19062 confp->chan.mwimonitor_neon = 1;
19063 }
19064 /* If set to true or yes, assume that simple fsk is desired */
19065 if (ast_true(v->value)) {
19066 confp->chan.mwimonitor_fsk = 1;
19067 }
19068 } else if (!strcasecmp(v->name, "hwrxgain")) {
19069 confp->chan.hwrxgain_enabled = 0;
19070 if (strcasecmp(v->value, "disabled")) {
19071 if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
19072 confp->chan.hwrxgain_enabled = 1;
19073 } else {
19074 ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
19075 }
19076 }
19077 } else if (!strcasecmp(v->name, "hwtxgain")) {
19078 confp->chan.hwtxgain_enabled = 0;
19079 if (strcasecmp(v->value, "disabled")) {
19080 if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
19081 confp->chan.hwtxgain_enabled = 1;
19082 } else {
19083 ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
19084 }
19085 }
19086 } else if (!strcasecmp(v->name, "cid_rxgain")) {
19087 if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
19088 ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
19089 }
19090 } else if (!strcasecmp(v->name, "rxgain")) {
19091 if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
19092 ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
19093 }
19094 } else if (!strcasecmp(v->name, "txgain")) {
19095 if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
19096 ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
19097 }
19098 } else if (!strcasecmp(v->name, "txdrc")) {
19099 if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) {
19100 ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value);
19101 }
19102 } else if (!strcasecmp(v->name, "rxdrc")) {
19103 if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) {
19104 ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value);
19105 }
19106 } else if (!strcasecmp(v->name, "tonezone")) {
19107 if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
19108 ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
19109 }
19110 } else if (!strcasecmp(v->name, "callerid")) {
19111 if (!strcasecmp(v->value, "asreceived")) {
19112 confp->chan.cid_num[0] = '\0';
19113 confp->chan.cid_name[0] = '\0';
19114 } else {
19115 ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
19116 }
19117 } else if (!strcasecmp(v->name, "fullname")) {
19118 ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
19119 } else if (!strcasecmp(v->name, "cid_number")) {
19120 ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
19121 } else if (!strcasecmp(v->name, "cid_tag")) {
19122 ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
19123 } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
19124 confp->chan.dahditrcallerid = ast_true(v->value);
19125 } else if (!strcasecmp(v->name, "restrictcid")) {
19126 confp->chan.restrictcid = ast_true(v->value);
19127 } else if (!strcasecmp(v->name, "usecallingpres")) {
19128 confp->chan.use_callingpres = ast_true(v->value);
19129 } else if (!strcasecmp(v->name, "accountcode")) {
19130 ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
19131 } else if (!strcasecmp(v->name, "amaflags")) {
19133 if (y < 0)
19134 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
19135 else
19136 confp->chan.amaflags = y;
19137 } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
19138 confp->chan.polarityonanswerdelay = atoi(v->value);
19139 } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
19141 } else if (!strcasecmp(v->name, "ani_info_digits")) {
19142 confp->chan.ani_info_digits = atoi(v->value);
19143 } else if (!strcasecmp(v->name, "ani_wink_time")) {
19144 confp->chan.ani_wink_time = atoi(v->value);
19145 } else if (!strcasecmp(v->name, "ani_timeout")) {
19146 confp->chan.ani_timeout = atoi(v->value);
19147 } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
19149 } else if (!strcasecmp(v->name, "autoreoriginate")) {
19150 confp->chan.reoriginate = ast_true(v->value);
19151 } else if (!strcasecmp(v->name, "sendcalleridafter")) {
19152 confp->chan.sendcalleridafter = atoi(v->value);
19153 } else if (!strcasecmp(v->name, "mwimonitornotify")) {
19155 } else if (ast_cc_is_config_param(v->name)) {
19156 ast_cc_set_param(confp->chan.cc_params, v->name, v->value);
19157 } else if (!strcasecmp(v->name, "mwisendtype")) {
19158#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */
19159 if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
19160 mwisend_rpas = 1;
19161 } else {
19162 mwisend_rpas = 0;
19163 }
19164#else
19165 /* Default is fsk, to turn it off you must specify nofsk */
19166 memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting));
19167 if (strcasestr(v->value, "nofsk")) { /* NoFSK */
19168 confp->chan.mwisend_fsk = 0;
19169 } else { /* Default FSK */
19170 confp->chan.mwisend_fsk = 1;
19171 }
19172 if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */
19173 confp->chan.mwisend_rpas = 1;
19174 } else {
19175 confp->chan.mwisend_rpas = 0;
19176 }
19177 if (strcasestr(v->value, "lrev")) { /* Line Reversal */
19178 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV;
19179 }
19180 if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */
19181 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC;
19182 }
19183 if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ) { /* 90V DC pulses */
19184 confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC;
19185 }
19186#endif
19187 } else if (reload != 1) {
19188 if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
19189 int orig_radio = confp->chan.radio;
19190 int orig_outsigmod = confp->chan.outsigmod;
19191 int orig_auto = confp->is_sig_auto;
19192
19193 confp->chan.radio = 0;
19194 confp->chan.outsigmod = -1;
19195 confp->is_sig_auto = 0;
19196 if (!strcasecmp(v->value, "em")) {
19197 confp->chan.sig = SIG_EM;
19198 } else if (!strcasecmp(v->value, "em_e1")) {
19199 confp->chan.sig = SIG_EM_E1;
19200 } else if (!strcasecmp(v->value, "em_w")) {
19201 confp->chan.sig = SIG_EMWINK;
19202 } else if (!strcasecmp(v->value, "fxs_ls")) {
19203 confp->chan.sig = SIG_FXSLS;
19204 } else if (!strcasecmp(v->value, "fxs_gs")) {
19205 confp->chan.sig = SIG_FXSGS;
19206 } else if (!strcasecmp(v->value, "fxs_ks")) {
19207 confp->chan.sig = SIG_FXSKS;
19208 } else if (!strcasecmp(v->value, "fxo_ls")) {
19209 confp->chan.sig = SIG_FXOLS;
19210 } else if (!strcasecmp(v->value, "fxo_gs")) {
19211 confp->chan.sig = SIG_FXOGS;
19212 } else if (!strcasecmp(v->value, "fxo_ks")) {
19213 confp->chan.sig = SIG_FXOKS;
19214 } else if (!strcasecmp(v->value, "fxs_rx")) {
19215 confp->chan.sig = SIG_FXSKS;
19216 confp->chan.radio = 1;
19217 } else if (!strcasecmp(v->value, "fxo_rx")) {
19218 confp->chan.sig = SIG_FXOLS;
19219 confp->chan.radio = 1;
19220 } else if (!strcasecmp(v->value, "fxs_tx")) {
19221 confp->chan.sig = SIG_FXSLS;
19222 confp->chan.radio = 1;
19223 } else if (!strcasecmp(v->value, "fxo_tx")) {
19224 confp->chan.sig = SIG_FXOGS;
19225 confp->chan.radio = 1;
19226 } else if (!strcasecmp(v->value, "em_rx")) {
19227 confp->chan.sig = SIG_EM;
19228 confp->chan.radio = 1;
19229 } else if (!strcasecmp(v->value, "em_tx")) {
19230 confp->chan.sig = SIG_EM;
19231 confp->chan.radio = 1;
19232 } else if (!strcasecmp(v->value, "em_rxtx")) {
19233 confp->chan.sig = SIG_EM;
19234 confp->chan.radio = 2;
19235 } else if (!strcasecmp(v->value, "em_txrx")) {
19236 confp->chan.sig = SIG_EM;
19237 confp->chan.radio = 2;
19238 } else if (!strcasecmp(v->value, "sf")) {
19239 confp->chan.sig = SIG_SF;
19240 } else if (!strcasecmp(v->value, "sf_w")) {
19241 confp->chan.sig = SIG_SFWINK;
19242 } else if (!strcasecmp(v->value, "sf_featd")) {
19243 confp->chan.sig = SIG_FEATD;
19244 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19245 confp->chan.sig = SIG_FEATDMF;
19246 } else if (!strcasecmp(v->value, "sf_featb")) {
19247 confp->chan.sig = SIG_SF_FEATB;
19248 } else if (!strcasecmp(v->value, "sf")) {
19249 confp->chan.sig = SIG_SF;
19250 } else if (!strcasecmp(v->value, "sf_rx")) {
19251 confp->chan.sig = SIG_SF;
19252 confp->chan.radio = 1;
19253 } else if (!strcasecmp(v->value, "sf_tx")) {
19254 confp->chan.sig = SIG_SF;
19255 confp->chan.radio = 1;
19256 } else if (!strcasecmp(v->value, "sf_rxtx")) {
19257 confp->chan.sig = SIG_SF;
19258 confp->chan.radio = 2;
19259 } else if (!strcasecmp(v->value, "sf_txrx")) {
19260 confp->chan.sig = SIG_SF;
19261 confp->chan.radio = 2;
19262 } else if (!strcasecmp(v->value, "featd")) {
19263 confp->chan.sig = SIG_FEATD;
19264 } else if (!strcasecmp(v->value, "featdmf")) {
19265 confp->chan.sig = SIG_FEATDMF;
19266 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19267 confp->chan.sig = SIG_FEATDMF_TA;
19268 } else if (!strcasecmp(v->value, "e911")) {
19269 confp->chan.sig = SIG_E911;
19270 } else if (!strcasecmp(v->value, "fgccama")) {
19271 confp->chan.sig = SIG_FGC_CAMA;
19272 } else if (!strcasecmp(v->value, "fgccamamf")) {
19273 confp->chan.sig = SIG_FGC_CAMAMF;
19274 } else if (!strcasecmp(v->value, "featb")) {
19275 confp->chan.sig = SIG_FEATB;
19276#ifdef HAVE_PRI
19277 } else if (!strcasecmp(v->value, "pri_net")) {
19278 confp->chan.sig = SIG_PRI;
19279 confp->pri.pri.nodetype = PRI_NETWORK;
19280 } else if (!strcasecmp(v->value, "pri_cpe")) {
19281 confp->chan.sig = SIG_PRI;
19282 confp->pri.pri.nodetype = PRI_CPE;
19283 } else if (!strcasecmp(v->value, "bri_cpe")) {
19284 confp->chan.sig = SIG_BRI;
19285 confp->pri.pri.nodetype = PRI_CPE;
19286 } else if (!strcasecmp(v->value, "bri_net")) {
19287 confp->chan.sig = SIG_BRI;
19288 confp->pri.pri.nodetype = PRI_NETWORK;
19289 } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
19290 confp->chan.sig = SIG_BRI_PTMP;
19291 confp->pri.pri.nodetype = PRI_CPE;
19292 } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
19293#if defined(HAVE_PRI_CALL_HOLD)
19294 confp->chan.sig = SIG_BRI_PTMP;
19295 confp->pri.pri.nodetype = PRI_NETWORK;
19296#else
19297 ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode! For now, sucks for you. (line %d)\n", v->lineno);
19298#endif /* !defined(HAVE_PRI_CALL_HOLD) */
19299#endif
19300#if defined(HAVE_SS7)
19301 } else if (!strcasecmp(v->value, "ss7")) {
19302 confp->chan.sig = SIG_SS7;
19303#endif /* defined(HAVE_SS7) */
19304#ifdef HAVE_OPENR2
19305 } else if (!strcasecmp(v->value, "mfcr2")) {
19306 confp->chan.sig = SIG_MFCR2;
19307#endif
19308 } else if (!strcasecmp(v->value, "auto")) {
19309 confp->is_sig_auto = 1;
19310 } else {
19311 confp->chan.outsigmod = orig_outsigmod;
19312 confp->chan.radio = orig_radio;
19313 confp->is_sig_auto = orig_auto;
19314 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19315 }
19316 } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
19317 if (!strcasecmp(v->value, "em")) {
19318 confp->chan.outsigmod = SIG_EM;
19319 } else if (!strcasecmp(v->value, "em_e1")) {
19320 confp->chan.outsigmod = SIG_EM_E1;
19321 } else if (!strcasecmp(v->value, "em_w")) {
19322 confp->chan.outsigmod = SIG_EMWINK;
19323 } else if (!strcasecmp(v->value, "sf")) {
19324 confp->chan.outsigmod = SIG_SF;
19325 } else if (!strcasecmp(v->value, "sf_w")) {
19326 confp->chan.outsigmod = SIG_SFWINK;
19327 } else if (!strcasecmp(v->value, "sf_featd")) {
19328 confp->chan.outsigmod = SIG_FEATD;
19329 } else if (!strcasecmp(v->value, "sf_featdmf")) {
19330 confp->chan.outsigmod = SIG_FEATDMF;
19331 } else if (!strcasecmp(v->value, "sf_featb")) {
19332 confp->chan.outsigmod = SIG_SF_FEATB;
19333 } else if (!strcasecmp(v->value, "sf")) {
19334 confp->chan.outsigmod = SIG_SF;
19335 } else if (!strcasecmp(v->value, "featd")) {
19336 confp->chan.outsigmod = SIG_FEATD;
19337 } else if (!strcasecmp(v->value, "featdmf")) {
19338 confp->chan.outsigmod = SIG_FEATDMF;
19339 } else if (!strcasecmp(v->value, "featdmf_ta")) {
19340 confp->chan.outsigmod = SIG_FEATDMF_TA;
19341 } else if (!strcasecmp(v->value, "e911")) {
19342 confp->chan.outsigmod = SIG_E911;
19343 } else if (!strcasecmp(v->value, "fgccama")) {
19344 confp->chan.outsigmod = SIG_FGC_CAMA;
19345 } else if (!strcasecmp(v->value, "fgccamamf")) {
19346 confp->chan.outsigmod = SIG_FGC_CAMAMF;
19347 } else if (!strcasecmp(v->value, "featb")) {
19348 confp->chan.outsigmod = SIG_FEATB;
19349 } else {
19350 ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
19351 }
19352#ifdef HAVE_PRI
19353 } else if (!strcasecmp(v->name, "pridialplan")) {
19354 if (!strcasecmp(v->value, "national")) {
19355 confp->pri.pri.dialplan = PRI_NATIONAL_ISDN + 1;
19356 } else if (!strcasecmp(v->value, "unknown")) {
19357 confp->pri.pri.dialplan = PRI_UNKNOWN + 1;
19358 } else if (!strcasecmp(v->value, "private")) {
19359 confp->pri.pri.dialplan = PRI_PRIVATE + 1;
19360 } else if (!strcasecmp(v->value, "international")) {
19361 confp->pri.pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
19362 } else if (!strcasecmp(v->value, "local")) {
19363 confp->pri.pri.dialplan = PRI_LOCAL_ISDN + 1;
19364 } else if (!strcasecmp(v->value, "dynamic")) {
19365 confp->pri.pri.dialplan = -1;
19366 } else if (!strcasecmp(v->value, "redundant")) {
19367 confp->pri.pri.dialplan = -2;
19368 } else {
19369 ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
19370 }
19371 } else if (!strcasecmp(v->name, "prilocaldialplan")) {
19372 if (!strcasecmp(v->value, "national")) {
19373 confp->pri.pri.localdialplan = PRI_NATIONAL_ISDN + 1;
19374 } else if (!strcasecmp(v->value, "unknown")) {
19375 confp->pri.pri.localdialplan = PRI_UNKNOWN + 1;
19376 } else if (!strcasecmp(v->value, "private")) {
19377 confp->pri.pri.localdialplan = PRI_PRIVATE + 1;
19378 } else if (!strcasecmp(v->value, "international")) {
19379 confp->pri.pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
19380 } else if (!strcasecmp(v->value, "local")) {
19381 confp->pri.pri.localdialplan = PRI_LOCAL_ISDN + 1;
19382 } else if (!strcasecmp(v->value, "from_channel")) {
19383 confp->pri.pri.localdialplan = 0;
19384 } else if (!strcasecmp(v->value, "dynamic")) {
19385 confp->pri.pri.localdialplan = -1;
19386 } else if (!strcasecmp(v->value, "redundant")) {
19387 confp->pri.pri.localdialplan = -2;
19388 } else {
19389 ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
19390 }
19391 } else if (!strcasecmp(v->name, "pricpndialplan")) {
19392 if (!strcasecmp(v->value, "national")) {
19393 confp->pri.pri.cpndialplan = PRI_NATIONAL_ISDN + 1;
19394 } else if (!strcasecmp(v->value, "unknown")) {
19395 confp->pri.pri.cpndialplan = PRI_UNKNOWN + 1;
19396 } else if (!strcasecmp(v->value, "private")) {
19397 confp->pri.pri.cpndialplan = PRI_PRIVATE + 1;
19398 } else if (!strcasecmp(v->value, "international")) {
19399 confp->pri.pri.cpndialplan = PRI_INTERNATIONAL_ISDN + 1;
19400 } else if (!strcasecmp(v->value, "local")) {
19401 confp->pri.pri.cpndialplan = PRI_LOCAL_ISDN + 1;
19402 } else if (!strcasecmp(v->value, "from_channel")) {
19403 confp->pri.pri.cpndialplan = 0;
19404 } else if (!strcasecmp(v->value, "dynamic")) {
19405 confp->pri.pri.cpndialplan = -1;
19406 } else if (!strcasecmp(v->value, "redundant")) {
19407 confp->pri.pri.cpndialplan = -2;
19408 } else {
19409 ast_log(LOG_WARNING, "Unknown PRI cpndialplan '%s' at line %d.\n", v->value, v->lineno);
19410 }
19411 } else if (!strcasecmp(v->name, "switchtype")) {
19412 if (!strcasecmp(v->value, "national"))
19413 confp->pri.pri.switchtype = PRI_SWITCH_NI2;
19414 else if (!strcasecmp(v->value, "ni1"))
19415 confp->pri.pri.switchtype = PRI_SWITCH_NI1;
19416 else if (!strcasecmp(v->value, "dms100"))
19417 confp->pri.pri.switchtype = PRI_SWITCH_DMS100;
19418 else if (!strcasecmp(v->value, "4ess"))
19419 confp->pri.pri.switchtype = PRI_SWITCH_ATT4ESS;
19420 else if (!strcasecmp(v->value, "5ess"))
19421 confp->pri.pri.switchtype = PRI_SWITCH_LUCENT5E;
19422 else if (!strcasecmp(v->value, "euroisdn"))
19423 confp->pri.pri.switchtype = PRI_SWITCH_EUROISDN_E1;
19424 else if (!strcasecmp(v->value, "qsig"))
19425 confp->pri.pri.switchtype = PRI_SWITCH_QSIG;
19426 else {
19427 ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
19428 return -1;
19429 }
19430 } else if (!strcasecmp(v->name, "msn")) {
19431 ast_copy_string(confp->pri.pri.msn_list, v->value,
19432 sizeof(confp->pri.pri.msn_list));
19433 } else if (!strcasecmp(v->name, "nsf")) {
19434 if (!strcasecmp(v->value, "sdn"))
19435 confp->pri.pri.nsf = PRI_NSF_SDN;
19436 else if (!strcasecmp(v->value, "megacom"))
19437 confp->pri.pri.nsf = PRI_NSF_MEGACOM;
19438 else if (!strcasecmp(v->value, "tollfreemegacom"))
19439 confp->pri.pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
19440 else if (!strcasecmp(v->value, "accunet"))
19441 confp->pri.pri.nsf = PRI_NSF_ACCUNET;
19442 else if (!strcasecmp(v->value, "none"))
19443 confp->pri.pri.nsf = PRI_NSF_NONE;
19444 else {
19445 ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
19446 confp->pri.pri.nsf = PRI_NSF_NONE;
19447 }
19448 } else if (!strcasecmp(v->name, "priindication")) {
19449 if (!strcasecmp(v->value, "outofband"))
19450 confp->chan.priindication_oob = 1;
19451 else if (!strcasecmp(v->value, "inband"))
19452 confp->chan.priindication_oob = 0;
19453 else
19454 ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
19455 v->value, v->lineno);
19456 } else if (!strcasecmp(v->name, "priexclusive")) {
19457 confp->chan.priexclusive = ast_true(v->value);
19458 } else if (!strcasecmp(v->name, "internationalprefix")) {
19459 ast_copy_string(confp->pri.pri.internationalprefix, v->value, sizeof(confp->pri.pri.internationalprefix));
19460 } else if (!strcasecmp(v->name, "nationalprefix")) {
19461 ast_copy_string(confp->pri.pri.nationalprefix, v->value, sizeof(confp->pri.pri.nationalprefix));
19462 } else if (!strcasecmp(v->name, "localprefix")) {
19463 ast_copy_string(confp->pri.pri.localprefix, v->value, sizeof(confp->pri.pri.localprefix));
19464 } else if (!strcasecmp(v->name, "privateprefix")) {
19465 ast_copy_string(confp->pri.pri.privateprefix, v->value, sizeof(confp->pri.pri.privateprefix));
19466 } else if (!strcasecmp(v->name, "unknownprefix")) {
19467 ast_copy_string(confp->pri.pri.unknownprefix, v->value, sizeof(confp->pri.pri.unknownprefix));
19468 } else if (!strcasecmp(v->name, "resetinterval")) {
19469 if (!strcasecmp(v->value, "never"))
19470 confp->pri.pri.resetinterval = -1;
19471 else if (atoi(v->value) >= 60)
19472 confp->pri.pri.resetinterval = atoi(v->value);
19473 else
19474 ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
19475 v->value, v->lineno);
19476 } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
19477 confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
19478 } else if (!strcasecmp(v->name, "minunused")) {
19479 confp->pri.pri.minunused = atoi(v->value);
19480 } else if (!strcasecmp(v->name, "minidle")) {
19481 confp->pri.pri.minidle = atoi(v->value);
19482 } else if (!strcasecmp(v->name, "idleext")) {
19483 ast_copy_string(confp->pri.pri.idleext, v->value, sizeof(confp->pri.pri.idleext));
19484 } else if (!strcasecmp(v->name, "idledial")) {
19485 ast_copy_string(confp->pri.pri.idledial, v->value, sizeof(confp->pri.pri.idledial));
19486 } else if (!strcasecmp(v->name, "overlapdial")) {
19487 if (ast_true(v->value)) {
19488 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19489 } else if (!strcasecmp(v->value, "incoming")) {
19490 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
19491 } else if (!strcasecmp(v->value, "outgoing")) {
19492 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
19493 } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
19494 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
19495 } else {
19496 confp->pri.pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
19497 }
19498#ifdef HAVE_PRI_PROG_W_CAUSE
19499 } else if (!strcasecmp(v->name, "qsigchannelmapping")) {
19500 if (!strcasecmp(v->value, "logical")) {
19501 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL;
19502 } else if (!strcasecmp(v->value, "physical")) {
19503 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19504 } else {
19505 confp->pri.pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL;
19506 }
19507#endif
19508 } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
19509 confp->pri.pri.discardremoteholdretrieval = ast_true(v->value);
19510#if defined(HAVE_PRI_SERVICE_MESSAGES)
19511 } else if (!strcasecmp(v->name, "service_message_support")) {
19512 /* assuming switchtype for this channel group has been configured already */
19513 if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
19514 || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
19515 || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
19516 confp->pri.pri.enable_service_message_support = 1;
19517 } else {
19518 confp->pri.pri.enable_service_message_support = 0;
19519 }
19520#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
19521#ifdef HAVE_PRI_INBANDDISCONNECT
19522 } else if (!strcasecmp(v->name, "inbanddisconnect")) {
19523 confp->pri.pri.inbanddisconnect = ast_true(v->value);
19524#endif
19525 } else if (!strcasecmp(v->name, "pritimer")) {
19526#ifdef PRI_GETSET_TIMERS
19527 char tmp[20];
19528 char *timerc;
19529 char *c;
19530 int timer;
19531 int timeridx;
19532
19533 ast_copy_string(tmp, v->value, sizeof(tmp));
19534 c = tmp;
19535 timerc = strsep(&c, ",");
19536 if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
19537 timeridx = pri_timer2idx(timerc);
19538 timer = atoi(c);
19539 if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
19541 "'%s' is not a valid ISDN timer at line %d.\n", timerc,
19542 v->lineno);
19543 } else if (!timer) {
19545 "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
19546 c, timerc, v->lineno);
19547 } else {
19548 confp->pri.pri.pritimers[timeridx] = timer;
19549 }
19550 } else {
19552 "'%s' is not a valid ISDN timer configuration string at line %d.\n",
19553 v->value, v->lineno);
19554 }
19555#endif /* PRI_GETSET_TIMERS */
19556 } else if (!strcasecmp(v->name, "facilityenable")) {
19557 confp->pri.pri.facilityenable = ast_true(v->value);
19558#if defined(HAVE_PRI_AOC_EVENTS)
19559 } else if (!strcasecmp(v->name, "aoc_enable")) {
19560 confp->pri.pri.aoc_passthrough_flag = 0;
19561 if (strchr(v->value, 's') || strchr(v->value, 'S')) {
19562 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
19563 }
19564 if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
19565 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
19566 }
19567 if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
19568 confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
19569 }
19570 } else if (!strcasecmp(v->name, "aoce_delayhangup")) {
19571 confp->pri.pri.aoce_delayhangup = ast_true(v->value);
19572#endif /* defined(HAVE_PRI_AOC_EVENTS) */
19573#if defined(HAVE_PRI_CALL_HOLD)
19574 } else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
19575 confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
19576#endif /* defined(HAVE_PRI_CALL_HOLD) */
19577 } else if (!strcasecmp(v->name, "moh_signaling")
19578 || !strcasecmp(v->name, "moh_signalling")) {
19579 if (!strcasecmp(v->value, "moh")) {
19580 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19581 } else if (!strcasecmp(v->value, "notify")) {
19582 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_NOTIFY;
19583#if defined(HAVE_PRI_CALL_HOLD)
19584 } else if (!strcasecmp(v->value, "hold")) {
19585 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_HOLD;
19586#endif /* defined(HAVE_PRI_CALL_HOLD) */
19587 } else {
19588 confp->pri.pri.moh_signaling = SIG_PRI_MOH_SIGNALING_MOH;
19589 }
19590#if defined(HAVE_PRI_CCSS)
19591 } else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
19592 if (!strcasecmp(v->value, "global")) {
19593 confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
19594 } else if (!strcasecmp(v->value, "specific")) {
19595 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19596 } else {
19597 confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
19598 }
19599 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
19600 if (!strcasecmp(v->value, "release")) {
19601 confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
19602 } else if (!strcasecmp(v->value, "retain")) {
19603 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19604 } else if (!strcasecmp(v->value, "do_not_care")) {
19605 confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
19606 } else {
19607 confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
19608 }
19609 } else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
19610 if (!strcasecmp(v->value, "release")) {
19611 confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
19612 } else if (!strcasecmp(v->value, "retain")) {
19613 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19614 } else {
19615 confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
19616 }
19617#endif /* defined(HAVE_PRI_CCSS) */
19618#if defined(HAVE_PRI_CALL_WAITING)
19619 } else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
19620 confp->pri.pri.max_call_waiting_calls = atoi(v->value);
19621 if (confp->pri.pri.max_call_waiting_calls < 0) {
19622 /* Negative values are not allowed. */
19623 confp->pri.pri.max_call_waiting_calls = 0;
19624 }
19625 } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
19626 confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
19627#endif /* defined(HAVE_PRI_CALL_WAITING) */
19628#if defined(HAVE_PRI_MWI)
19629 } else if (!strcasecmp(v->name, "mwi_mailboxes")) {
19630 ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
19631 sizeof(confp->pri.pri.mwi_mailboxes));
19632 } else if (!strcasecmp(v->name, "mwi_vm_boxes")) {
19633 ast_copy_string(confp->pri.pri.mwi_vm_boxes, v->value,
19634 sizeof(confp->pri.pri.mwi_vm_boxes));
19635 } else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
19636 ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
19637 sizeof(confp->pri.pri.mwi_vm_numbers));
19638#endif /* defined(HAVE_PRI_MWI) */
19639 } else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
19640 confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
19641 } else if (!strcasecmp(v->name, "inband_on_setup_ack")) {
19642 confp->pri.pri.inband_on_setup_ack = ast_true(v->value);
19643 } else if (!strcasecmp(v->name, "inband_on_proceeding")) {
19644 confp->pri.pri.inband_on_proceeding = ast_true(v->value);
19645#if defined(HAVE_PRI_DISPLAY_TEXT)
19646 } else if (!strcasecmp(v->name, "display_send")) {
19647 confp->pri.pri.display_flags_send = dahdi_display_text_option(v->value);
19648 } else if (!strcasecmp(v->name, "display_receive")) {
19649 confp->pri.pri.display_flags_receive = dahdi_display_text_option(v->value);
19650#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
19651#if defined(HAVE_PRI_MCID)
19652 } else if (!strcasecmp(v->name, "mcid_send")) {
19653 confp->pri.pri.mcid_send = ast_true(v->value);
19654#endif /* defined(HAVE_PRI_MCID) */
19655#if defined(HAVE_PRI_DATETIME_SEND)
19656 } else if (!strcasecmp(v->name, "datetime_send")) {
19657 confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
19658#endif /* defined(HAVE_PRI_DATETIME_SEND) */
19659 } else if (!strcasecmp(v->name, "layer1_presence")) {
19660 if (!strcasecmp(v->value, "required")) {
19661 confp->pri.pri.layer1_ignored = 0;
19662 } else if (!strcasecmp(v->value, "ignore")) {
19663 confp->pri.pri.layer1_ignored = 1;
19664 } else {
19665 /* Default */
19666 confp->pri.pri.layer1_ignored = 0;
19667 }
19668#if defined(HAVE_PRI_L2_PERSISTENCE)
19669 } else if (!strcasecmp(v->name, "layer2_persistence")) {
19670 if (!strcasecmp(v->value, "keep_up")) {
19671 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_KEEP_UP;
19672 } else if (!strcasecmp(v->value, "leave_down")) {
19673 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_LEAVE_DOWN;
19674 } else {
19675 confp->pri.pri.l2_persistence = PRI_L2_PERSISTENCE_DEFAULT;
19676 }
19677#endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
19678 } else if (!strcasecmp(v->name, "colp_send")) {
19679 if (!strcasecmp(v->value, "block")) {
19680 confp->pri.pri.colp_send = SIG_PRI_COLP_BLOCK;
19681 } else if (!strcasecmp(v->value, "connect")) {
19682 confp->pri.pri.colp_send = SIG_PRI_COLP_CONNECT;
19683 } else if (!strcasecmp(v->value, "update")) {
19684 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19685 } else {
19686 confp->pri.pri.colp_send = SIG_PRI_COLP_UPDATE;
19687 }
19688#endif /* HAVE_PRI */
19689#if defined(HAVE_SS7)
19690 } else if (!strcasecmp(v->name, "ss7type")) {
19691 if (!strcasecmp(v->value, "itu")) {
19692 cur_ss7type = SS7_ITU;
19693 } else if (!strcasecmp(v->value, "ansi")) {
19694 cur_ss7type = SS7_ANSI;
19695 } else {
19696 ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
19697 }
19698 } else if (!strcasecmp(v->name, "slc")) {
19699 cur_slc = atoi(v->value);
19700 } else if (!strcasecmp(v->name, "linkset")) {
19701 cur_linkset = atoi(v->value);
19702 } else if (!strcasecmp(v->name, "pointcode")) {
19703 cur_pointcode = parse_pointcode(v->value);
19704 } else if (!strcasecmp(v->name, "adjpointcode")) {
19705 cur_adjpointcode = parse_pointcode(v->value);
19706 } else if (!strcasecmp(v->name, "defaultdpc")) {
19707 cur_defaultdpc = parse_pointcode(v->value);
19708 } else if (!strcasecmp(v->name, "cicbeginswith")) {
19709 cur_cicbeginswith = atoi(v->value);
19710 } else if (!strcasecmp(v->name, "networkindicator")) {
19711 if (!strcasecmp(v->value, "national")) {
19712 cur_networkindicator = SS7_NI_NAT;
19713 } else if (!strcasecmp(v->value, "national_spare")) {
19714 cur_networkindicator = SS7_NI_NAT_SPARE;
19715 } else if (!strcasecmp(v->value, "international")) {
19716 cur_networkindicator = SS7_NI_INT;
19717 } else if (!strcasecmp(v->value, "international_spare")) {
19718 cur_networkindicator = SS7_NI_INT_SPARE;
19719 } else {
19720 cur_networkindicator = -1;
19721 }
19722 } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
19723 ast_copy_string(confp->ss7.ss7.internationalprefix, v->value, sizeof(confp->ss7.ss7.internationalprefix));
19724 } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
19725 ast_copy_string(confp->ss7.ss7.nationalprefix, v->value, sizeof(confp->ss7.ss7.nationalprefix));
19726 } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
19727 ast_copy_string(confp->ss7.ss7.subscriberprefix, v->value, sizeof(confp->ss7.ss7.subscriberprefix));
19728 } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
19729 ast_copy_string(confp->ss7.ss7.unknownprefix, v->value, sizeof(confp->ss7.ss7.unknownprefix));
19730 } else if (!strcasecmp(v->name, "ss7_networkroutedprefix")) {
19731 ast_copy_string(confp->ss7.ss7.networkroutedprefix, v->value, sizeof(confp->ss7.ss7.networkroutedprefix));
19732 } else if (!strcasecmp(v->name, "ss7_called_nai")) {
19733 if (!strcasecmp(v->value, "national")) {
19734 confp->ss7.ss7.called_nai = SS7_NAI_NATIONAL;
19735 } else if (!strcasecmp(v->value, "international")) {
19736 confp->ss7.ss7.called_nai = SS7_NAI_INTERNATIONAL;
19737 } else if (!strcasecmp(v->value, "subscriber")) {
19738 confp->ss7.ss7.called_nai = SS7_NAI_SUBSCRIBER;
19739 } else if (!strcasecmp(v->value, "unknown")) {
19740 confp->ss7.ss7.called_nai = SS7_NAI_UNKNOWN;
19741 } else if (!strcasecmp(v->value, "dynamic")) {
19742 confp->ss7.ss7.called_nai = SS7_NAI_DYNAMIC;
19743 } else {
19744 ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
19745 }
19746 } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
19747 if (!strcasecmp(v->value, "national")) {
19748 confp->ss7.ss7.calling_nai = SS7_NAI_NATIONAL;
19749 } else if (!strcasecmp(v->value, "international")) {
19750 confp->ss7.ss7.calling_nai = SS7_NAI_INTERNATIONAL;
19751 } else if (!strcasecmp(v->value, "subscriber")) {
19752 confp->ss7.ss7.calling_nai = SS7_NAI_SUBSCRIBER;
19753 } else if (!strcasecmp(v->value, "unknown")) {
19754 confp->ss7.ss7.calling_nai = SS7_NAI_UNKNOWN;
19755 } else if (!strcasecmp(v->value, "dynamic")) {
19756 confp->ss7.ss7.calling_nai = SS7_NAI_DYNAMIC;
19757 } else {
19758 ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
19759 }
19760 } else if (!strcasecmp(v->name, "sigchan")) {
19761 int sigchan, res;
19762 sigchan = atoi(v->value);
19763 res = linkset_addsigchan(sigchan);
19764 if (res < 0) {
19765 return -1;
19766 }
19767 } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
19768 struct dahdi_ss7 *link;
19769 link = ss7_resolve_linkset(cur_linkset);
19770 if (!link) {
19771 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19772 return -1;
19773 }
19774 if (ast_true(v->value)) {
19775 link->ss7.flags |= LINKSET_FLAG_EXPLICITACM;
19776 } else {
19777 link->ss7.flags &= ~LINKSET_FLAG_EXPLICITACM;
19778 }
19779 } else if (!strcasecmp(v->name, "ss7_autoacm")) {
19780 struct dahdi_ss7 *link;
19781 link = ss7_resolve_linkset(cur_linkset);
19782 if (!link) {
19783 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19784 return -1;
19785 }
19786 if (ast_true(v->value)) {
19787 link->ss7.flags |= LINKSET_FLAG_AUTOACM;
19788 } else {
19789 link->ss7.flags &= ~LINKSET_FLAG_AUTOACM;
19790 }
19791 } else if (!strcasecmp(v->name, "ss7_initialhwblo")) {
19792 struct dahdi_ss7 *link;
19793 link = ss7_resolve_linkset(cur_linkset);
19794 if (!link) {
19795 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19796 return -1;
19797 }
19798 if (ast_true(v->value)) {
19799 link->ss7.flags |= LINKSET_FLAG_INITIALHWBLO;
19800 } else {
19801 link->ss7.flags &= ~LINKSET_FLAG_INITIALHWBLO;
19802 }
19803 } else if (!strcasecmp(v->name, "ss7_use_echocontrol")) {
19804 struct dahdi_ss7 *link;
19805 link = ss7_resolve_linkset(cur_linkset);
19806 if (!link) {
19807 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19808 return -1;
19809 }
19810 if (ast_true(v->value)) {
19811 link->ss7.flags |= LINKSET_FLAG_USEECHOCONTROL;
19812 } else {
19813 link->ss7.flags &= ~LINKSET_FLAG_USEECHOCONTROL;
19814 }
19815 } else if (!strcasecmp(v->name, "ss7_default_echocontrol")) {
19816 struct dahdi_ss7 *link;
19817 link = ss7_resolve_linkset(cur_linkset);
19818 if (!link) {
19819 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19820 return -1;
19821 }
19822 if (ast_true(v->value)) {
19823 link->ss7.flags |= LINKSET_FLAG_DEFAULTECHOCONTROL;
19824 } else {
19825 link->ss7.flags &= ~LINKSET_FLAG_DEFAULTECHOCONTROL;
19826 }
19827 } else if (!strncasecmp(v->name, "isup_timer.", 11)) {
19828 struct dahdi_ss7 *link;
19829 link = ss7_resolve_linkset(cur_linkset);
19830 if (!link) {
19831 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19832 return -1;
19833 }
19834 if (!link->ss7.ss7) {
19835 ast_log(LOG_ERROR, "Please specify isup timers after sigchan!\n");
19836 /*! \todo Remove cast after libss7 API is changed to const char */
19837 } else if (!ss7_set_isup_timer(link->ss7.ss7, (char*) strstr(v->name, ".") + 1, atoi(v->value))) {
19838 ast_log(LOG_ERROR, "Invalid isup timer %s\n", v->name);
19839 }
19840 } else if (!strncasecmp(v->name, "mtp3_timer.", 11)) {
19841 struct dahdi_ss7 *link;
19842 link = ss7_resolve_linkset(cur_linkset);
19843 if (!link) {
19844 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19845 return -1;
19846 }
19847 if (!link->ss7.ss7) {
19848 ast_log(LOG_ERROR, "Please specify mtp3 timers after sigchan!\n");
19849 /*! \todo Remove cast after libss7 API is changed to const char */
19850 } else if (!ss7_set_mtp3_timer(link->ss7.ss7, (char*) strstr(v->name, ".") + 1, atoi(v->value))) {
19851 ast_log(LOG_ERROR, "Invalid mtp3 timer %s\n", v->name);
19852 }
19853 } else if (!strcasecmp(v->name, "inr_if_no_calling")) {
19854 struct dahdi_ss7 *link;
19855 link = ss7_resolve_linkset(cur_linkset);
19856 if (!link) {
19857 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19858 return -1;
19859 }
19860 if (!link->ss7.ss7) {
19861 ast_log(LOG_ERROR, "Please specify inr_if_no_calling after sigchan!\n");
19862 } else if (ast_true(v->value)) {
19863 ss7_set_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19864 } else {
19865 ss7_clear_flags(link->ss7.ss7, SS7_INR_IF_NO_CALLING);
19866 }
19867 } else if (!strcasecmp(v->name, "non_isdn_access")) {
19868 struct dahdi_ss7 *link;
19869 link = ss7_resolve_linkset(cur_linkset);
19870 if (!link) {
19871 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19872 return -1;
19873 }
19874 if (!link->ss7.ss7) {
19875 ast_log(LOG_ERROR, "Please specify non_isdn_access after sigchan!\n");
19876 } else if (ast_true(v->value)) {
19877 ss7_clear_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19878 } else {
19879 ss7_set_flags(link->ss7.ss7, SS7_ISDN_ACCESS_INDICATOR);
19880 }
19881 } else if (!strcasecmp(v->name, "sls_shift")) {
19882 struct dahdi_ss7 *link;
19883 int sls_shift = atoi(v->value);
19884
19885 if (sls_shift < 0 || sls_shift > 7) {
19886 ast_log(LOG_ERROR, "Invalid sls_shift value. Must be between 0 and 7\n");
19887 return -1;
19888 }
19889
19890 link = ss7_resolve_linkset(cur_linkset);
19891 if (!link) {
19892 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19893 return -1;
19894 }
19895 if (!link->ss7.ss7) {
19896 ast_log(LOG_ERROR, "Please specify sls_shift after sigchan!\n");
19897 } else {
19898 ss7_set_sls_shift(link->ss7.ss7, sls_shift);
19899 }
19900 } else if (!strcasecmp(v->name, "cause_location")) {
19901 struct dahdi_ss7 *link;
19902 int cause_location = atoi(v->value);
19903
19904 if (cause_location < 0 || cause_location > 15) {
19905 ast_log(LOG_ERROR, "Invalid cause_location value. Must be between 0 and 15\n");
19906 return -1;
19907 }
19908 link = ss7_resolve_linkset(cur_linkset);
19909 if (!link) {
19910 ast_log(LOG_ERROR, "Invalid linkset number. Must be between 1 and %d\n", NUM_SPANS + 1);
19911 return -1;
19912 }
19913 if (!link->ss7.ss7) {
19914 ast_log(LOG_ERROR, "Please specify cause_location after sigchan!\n");
19915 } else {
19916 ss7_set_cause_location(link->ss7.ss7, cause_location);
19917 }
19918#endif /* defined(HAVE_SS7) */
19919#ifdef HAVE_OPENR2
19920 } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
19921 ast_copy_string(confp->mfcr2.r2proto_file, v->value, sizeof(confp->mfcr2.r2proto_file));
19922 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);
19923 } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
19924 ast_copy_string(confp->mfcr2.logdir, v->value, sizeof(confp->mfcr2.logdir));
19925 } else if (!strcasecmp(v->name, "mfcr2_variant")) {
19926 confp->mfcr2.variant = openr2_proto_get_variant(v->value);
19927 if (OR2_VAR_UNKNOWN == confp->mfcr2.variant) {
19928 ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d, defaulting to ITU.\n", v->value, v->lineno);
19929 confp->mfcr2.variant = OR2_VAR_ITU;
19930 }
19931 } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
19932 confp->mfcr2.mfback_timeout = atoi(v->value);
19933 if (!confp->mfcr2.mfback_timeout) {
19934 ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
19935 confp->mfcr2.mfback_timeout = -1;
19936 } else if (confp->mfcr2.mfback_timeout > 0 && confp->mfcr2.mfback_timeout < 500) {
19937 ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
19938 }
19939 } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
19940 confp->mfcr2.metering_pulse_timeout = atoi(v->value);
19941 if (confp->mfcr2.metering_pulse_timeout > 500) {
19942 ast_log(LOG_WARNING, "Metering pulse timeout greater than 500ms is not recommended, you have been warned!\n");
19943 }
19944#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
19945 } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
19946 confp->mfcr2.dtmf_detection = ast_true(v->value) ? 1 : 0;
19947 } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
19948 confp->mfcr2.dtmf_dialing = ast_true(v->value) ? 1 : 0;
19949 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
19950 confp->mfcr2.dtmf_time_on = atoi(v->value);
19951 } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
19952 confp->mfcr2.dtmf_time_off = atoi(v->value);
19953#endif
19954#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 3
19955 } else if (!strcasecmp(v->name, "mfcr2_dtmf_end_timeout")) {
19956 confp->mfcr2.dtmf_end_timeout = atoi(v->value);
19957#endif
19958 } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
19959 confp->mfcr2.get_ani_first = ast_true(v->value) ? 1 : 0;
19960 } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
19961 confp->mfcr2.double_answer = ast_true(v->value) ? 1 : 0;
19962 } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
19963 confp->mfcr2.charge_calls = ast_true(v->value) ? 1 : 0;
19964 } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
19965 confp->mfcr2.accept_on_offer = ast_true(v->value) ? 1 : 0;
19966 } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
19967 confp->mfcr2.allow_collect_calls = ast_true(v->value) ? 1 : 0;
19968 } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
19969 confp->mfcr2.forced_release = ast_true(v->value) ? 1 : 0;
19970 } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
19971 confp->mfcr2.immediate_accept = ast_true(v->value) ? 1 : 0;
19972#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
19973 } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
19974 confp->mfcr2.skip_category_request = ast_true(v->value) ? 1 : 0;
19975#endif
19976 } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
19977 confp->mfcr2.call_files = ast_true(v->value) ? 1 : 0;
19978 } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
19979 confp->mfcr2.max_ani = atoi(v->value);
19980 if (confp->mfcr2.max_ani >= AST_MAX_EXTENSION) {
19981 confp->mfcr2.max_ani = AST_MAX_EXTENSION - 1;
19982 }
19983 } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
19984 confp->mfcr2.max_dnis = atoi(v->value);
19985 if (confp->mfcr2.max_dnis >= AST_MAX_EXTENSION) {
19986 confp->mfcr2.max_dnis = AST_MAX_EXTENSION - 1;
19987 }
19988 } else if (!strcasecmp(v->name, "mfcr2_category")) {
19989 confp->mfcr2.category = openr2_proto_get_category(v->value);
19990 if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == confp->mfcr2.category) {
19991 confp->mfcr2.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
19992 ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
19993 v->value, v->lineno);
19994 }
19995 } else if (!strcasecmp(v->name, "mfcr2_logging")) {
19996 openr2_log_level_t tmplevel;
19997 char *clevel;
19998 char *logval;
19999 char copy[strlen(v->value) + 1];
20000 strcpy(copy, v->value); /* safe */
20001 logval = copy;
20002 while (logval) {
20003 clevel = strsep(&logval,",");
20004 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
20005 ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", clevel, v->lineno);
20006 continue;
20007 }
20008 confp->mfcr2.loglevel |= tmplevel;
20009 }
20010#endif /* HAVE_OPENR2 */
20011 } else if (!strcasecmp(v->name, "cadence")) {
20012 /* setup to scan our argument */
20013 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
20014 int i;
20015 struct dahdi_ring_cadence new_cadence;
20016 int cid_location = -1;
20017 int firstcadencepos = 0;
20018 char original_args[80];
20019 int cadence_is_ok = 1;
20020
20021 ast_copy_string(original_args, v->value, sizeof(original_args));
20022 /* 16 cadences allowed (8 pairs) */
20023 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]);
20024
20025 /* Cadence must be even (on/off) */
20026 if (element_count % 2 == 1) {
20027 ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
20028 cadence_is_ok = 0;
20029 }
20030
20031 /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
20032 if (element_count > ARRAY_LEN(c)) {
20033 element_count = ARRAY_LEN(c);
20034 }
20035
20036 /* Ring cadences cannot be negative */
20037 for (i = 0; i < element_count; i++) {
20038 if (c[i] == 0) {
20039 ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
20040 cadence_is_ok = 0;
20041 break;
20042 } else if (c[i] < 0) {
20043 if (i % 2 == 1) {
20044 /* Silence duration, negative possibly okay */
20045 if (cid_location == -1) {
20046 cid_location = i;
20047 c[i] *= -1;
20048 } else {
20049 ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
20050 cadence_is_ok = 0;
20051 break;
20052 }
20053 } else {
20054 if (firstcadencepos == 0) {
20055 firstcadencepos = i; /* only recorded to avoid duplicate specification */
20056 /* duration will be passed negative to the DAHDI driver */
20057 } else {
20058 ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
20059 cadence_is_ok = 0;
20060 break;
20061 }
20062 }
20063 }
20064 }
20065
20066 /* Substitute our scanned cadence */
20067 for (i = 0; i < 16; i++) {
20068 new_cadence.ringcadence[i] = c[i];
20069 }
20070
20071 if (cadence_is_ok) {
20072 /* ---we scanned it without getting annoyed; now some sanity checks--- */
20073 if (element_count < 2) {
20074 ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
20075 } else {
20076 if (cid_location == -1) {
20077 /* user didn't say; default to first pause */
20078 cid_location = 1;
20079 } else {
20080 /* convert element_index to cidrings value */
20081 cid_location = (cid_location + 1) / 2;
20082 }
20083 /* ---we like their cadence; try to install it--- */
20085 /* this is the first user-defined cadence; clear the default user cadences */
20086 num_cadence = 0;
20087 if ((num_cadence+1) >= NUM_CADENCE_MAX)
20088 ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
20089 else {
20090 cadences[num_cadence] = new_cadence;
20091 cidrings[num_cadence++] = cid_location;
20092 ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
20093 }
20094 }
20095 }
20096 } else if (!strcasecmp(v->name, "ringtimeout")) {
20097 ringt_base = (atoi(v->value) * 8) / READ_SIZE;
20098 } else if (!strcasecmp(v->name, "prewink")) {
20099 confp->timing.prewinktime = atoi(v->value);
20100 } else if (!strcasecmp(v->name, "preflash")) {
20101 confp->timing.preflashtime = atoi(v->value);
20102 } else if (!strcasecmp(v->name, "wink")) {
20103 confp->timing.winktime = atoi(v->value);
20104 } else if (!strcasecmp(v->name, "flash")) {
20105 confp->timing.flashtime = atoi(v->value);
20106 } else if (!strcasecmp(v->name, "start")) {
20107 confp->timing.starttime = atoi(v->value);
20108 } else if (!strcasecmp(v->name, "rxwink")) {
20109 confp->timing.rxwinktime = atoi(v->value);
20110 } else if (!strcasecmp(v->name, "rxflash")) {
20111 confp->timing.rxflashtime = atoi(v->value);
20112 } else if (!strcasecmp(v->name, "debounce")) {
20113 confp->timing.debouncetime = atoi(v->value);
20114 } else if (!strcasecmp(v->name, "toneduration")) {
20115 int toneduration;
20116 int ctlfd;
20117 int res;
20118 struct dahdi_dialparams dps;
20119
20120 ctlfd = open("/dev/dahdi/ctl", O_RDWR);
20121 if (ctlfd == -1) {
20122 ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
20123 return -1;
20124 }
20125
20126 toneduration = atoi(v->value);
20127 if (toneduration > -1) {
20128 memset(&dps, 0, sizeof(dps));
20129
20130 dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
20131 res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
20132 if (res < 0) {
20133 ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
20134 close(ctlfd);
20135 return -1;
20136 }
20137 }
20138 close(ctlfd);
20139 } else if (!strcasecmp(v->name, "defaultcic")) {
20141 } else if (!strcasecmp(v->name, "defaultozz")) {
20143 } else if (!strcasecmp(v->name, "mwilevel")) {
20144 mwilevel = atoi(v->value);
20145 } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
20146 dtmfcid_level = atoi(v->value);
20147 } else if (!strcasecmp(v->name, "reportalarms")) {
20148 if (!strcasecmp(v->value, "all"))
20150 if (!strcasecmp(v->value, "none"))
20151 report_alarms = 0;
20152 else if (!strcasecmp(v->value, "channels"))
20154 else if (!strcasecmp(v->value, "spans"))
20156 }
20157 } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
20158 ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
20159 }
20160
20161 if (dahdichan) {
20162 /* Process the deferred dahdichan value. */
20163 if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
20164 if (confp->ignore_failed_channels) {
20166 "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
20167 dahdichan->value);
20168 } else {
20169 return -1;
20170 }
20171 }
20172 }
20173
20174 /*
20175 * Since confp has already filled individual dahdi_pvt objects with channels
20176 * at this point, clear the variables in confp's pvt.
20177 */
20178 if (confp->chan.vars) {
20180 confp->chan.vars = NULL;
20181 }
20182
20183 /* mark the first channels of each DAHDI span to watch for their span alarms */
20184 for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
20185 if (!tmp->destroy && tmp->span != y) {
20186 tmp->manages_span_alarms = 1;
20187 y = tmp->span;
20188 } else {
20189 tmp->manages_span_alarms = 0;
20190 }
20191 }
20192
20193 /*< \todo why check for the pseudo in the per-channel section.
20194 * Any actual use for manual setup of the pseudo channel? */
20195 if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
20196 /* use the default configuration for a channel, so
20197 that any settings from real configured channels
20198 don't "leak" into the pseudo channel config
20199 */
20201
20202 if (conf.chan.cc_params) {
20203 tmp = mkintf(CHAN_PSEUDO, &conf, reload);
20204 } else {
20205 tmp = NULL;
20206 }
20207 if (tmp) {
20208 ast_verb(3, "Automatically generated pseudo channel\n");
20209 has_pseudo = 1;
20210 } else {
20211 ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
20212 }
20213 ast_cc_config_params_destroy(conf.chan.cc_params);
20214 }
20215
20216 /* Since named callgroup and named pickup group are ref'd to dahdi_pvt at this point, unref container in confp's pvt. */
20219
20220 return 0;
20221}
20222
20223/*!
20224 * \internal
20225 * \brief Deep copy struct dahdi_chan_conf.
20226 * \since 1.8
20227 *
20228 * \param dest Destination.
20229 * \param src Source.
20230 */
20231static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
20232{
20233 struct ast_cc_config_params *cc_params;
20234
20235 cc_params = dest->chan.cc_params;
20236 *dest = *src;
20237 dest->chan.cc_params = cc_params;
20239}
20240
20241/*!
20242 * \internal
20243 * \brief Setup DAHDI channel driver.
20244 *
20245 * \param reload enum: load_module(0), reload(1), restart(2).
20246 * \param default_conf Default config parameters. So cc_params can be properly destroyed.
20247 * \param base_conf Default config parameters per section. So cc_params can be properly destroyed.
20248 * \param conf Local config parameters. So cc_params can be properly destroyed.
20249 *
20250 * \retval 0 on success.
20251 * \retval -1 on error.
20252 */
20253static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
20254{
20255 struct ast_config *cfg;
20256 struct ast_config;
20257 struct ast_variable *v;
20258 struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
20259 const char *chans;
20260 const char *cat;
20261 int res;
20262
20263#ifdef HAVE_PRI
20264 const char *c;
20265 int spanno;
20266 int i;
20267 int logicalspan;
20268 int trunkgroup;
20269 int dchannels[SIG_PRI_NUM_DCHANS];
20270#endif
20271 int have_cfg_now;
20272 static int had_cfg_before = 1;/* So initial load will complain if we don't have cfg. */
20273
20274 cfg = ast_config_load(config, config_flags);
20275 have_cfg_now = !!cfg;
20276 if (!cfg) {
20277 /* Error if we have no config file */
20278 if (had_cfg_before) {
20279 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
20281 }
20282 cfg = ast_config_new();/* Dummy config */
20283 if (!cfg) {
20284 return 0;
20285 }
20286 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
20288 cfg = ast_config_load(config, config_flags);
20289 have_cfg_now = !!cfg;
20290 if (!cfg) {
20291 if (had_cfg_before) {
20292 /* We should have been able to load the config. */
20293 ast_log(LOG_ERROR, "Bad. Unable to load config %s\n", config);
20294 return 0;
20295 }
20296 cfg = ast_config_new();/* Dummy config */
20297 if (!cfg) {
20298 return 0;
20299 }
20300 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20301 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20302 return 0;
20303 }
20304 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
20305 ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config);
20306 return 0;
20307 } else {
20309 }
20310 had_cfg_before = have_cfg_now;
20311
20312 /* It's a little silly to lock it, but we might as well just to be sure */
20314#ifdef HAVE_PRI
20315 if (reload != 1) {
20316 /* Process trunkgroups first */
20317 v = ast_variable_browse(cfg, "trunkgroups");
20318 while (v) {
20319 if (!strcasecmp(v->name, "trunkgroup")) {
20320 trunkgroup = atoi(v->value);
20321 if (trunkgroup > 0) {
20322 if ((c = strchr(v->value, ','))) {
20323 i = 0;
20324 memset(dchannels, 0, sizeof(dchannels));
20325 while (c && (i < SIG_PRI_NUM_DCHANS)) {
20326 dchannels[i] = atoi(c + 1);
20327 if (dchannels[i] < 0) {
20328 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);
20329 } else
20330 i++;
20331 c = strchr(c + 1, ',');
20332 }
20333 if (i) {
20334 if (pri_create_trunkgroup(trunkgroup, dchannels)) {
20335 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);
20336 } else
20337 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");
20338 } else
20339 ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20340 } else
20341 ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
20342 } else
20343 ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20344 } else if (!strcasecmp(v->name, "spanmap")) {
20345 spanno = atoi(v->value);
20346 if (spanno > 0) {
20347 if ((c = strchr(v->value, ','))) {
20348 trunkgroup = atoi(c + 1);
20349 if (trunkgroup > 0) {
20350 if ((c = strchr(c + 1, ',')))
20351 logicalspan = atoi(c + 1);
20352 else
20353 logicalspan = 0;
20354 if (logicalspan >= 0) {
20355 if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
20356 ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20357 } else
20358 ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
20359 } else
20360 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);
20361 } else
20362 ast_log(LOG_WARNING, "Trunk group must be a positive number at line %d of chan_dahdi.conf\n", v->lineno);
20363 } else
20364 ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
20365 } else
20366 ast_log(LOG_WARNING, "Span number must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
20367 } else {
20368 ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
20369 }
20370 v = v->next;
20371 }
20372 }
20373#endif
20374
20375 /* Copy the default jb config over global_jbconf */
20376 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
20377
20378 mwimonitornotify[0] = '\0';
20379
20380 v = ast_variable_browse(cfg, "channels");
20381 if ((res = process_dahdi(base_conf,
20382 "" /* Must be empty for the channels category. Silly voicemail mailbox. */,
20383 v, reload, 0))) {
20385 ast_config_destroy(cfg);
20386 return res;
20387 }
20388
20389 /* Now get configuration from all normal sections in chan_dahdi.conf: */
20390 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
20391 /* [channels] and [trunkgroups] are used. Let's also reserve
20392 * [globals] and [general] for future use
20393 */
20394 if (!strcasecmp(cat, "general") ||
20395 !strcasecmp(cat, "trunkgroups") ||
20396 !strcasecmp(cat, "globals") ||
20397 !strcasecmp(cat, "channels")) {
20398 continue;
20399 }
20400
20401 chans = ast_variable_retrieve(cfg, cat, "dahdichan");
20402 if (ast_strlen_zero(chans)) {
20403 /* Section is useless without a dahdichan value present. */
20404 continue;
20405 }
20406
20407 /* Copy base_conf to conf. */
20408 deep_copy_dahdi_chan_conf(conf, base_conf);
20409
20410 if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
20412 ast_config_destroy(cfg);
20413 return res;
20414 }
20415 }
20416
20417 ast_config_destroy(cfg);
20419
20420#ifdef HAVE_PRI
20421 if (reload != 1) {
20422 int x;
20423 for (x = 0; x < NUM_SPANS; x++) {
20424 if (pris[x].pri.pvts[0] &&
20425 pris[x].pri.master == AST_PTHREADT_NULL) {
20426 prepare_pri(pris + x);
20427 if (sig_pri_start_pri(&pris[x].pri)) {
20428 ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
20429 return -1;
20430 } else
20431 ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
20432 }
20433 }
20434 }
20435#endif
20436#if defined(HAVE_SS7)
20437 if (reload != 1) {
20438 int x;
20439 for (x = 0; x < NUM_SPANS; x++) {
20440 if (linksets[x].ss7.ss7) {
20441 if (ast_pthread_create(&linksets[x].ss7.master, NULL, ss7_linkset, &linksets[x].ss7)) {
20442 ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
20443 return -1;
20444 } else
20445 ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
20446 }
20447 }
20448 }
20449#endif /* defined(HAVE_SS7) */
20450#ifdef HAVE_OPENR2
20451 if (reload != 1) {
20452 struct r2link_entry *cur;
20453 int x = 0;
20454 AST_LIST_LOCK(&r2links);
20455 AST_LIST_TRAVERSE(&r2links, cur, list) {
20456 struct dahdi_mfcr2 *r2 = &cur->mfcr2;
20457 if (r2->r2master == AST_PTHREADT_NULL) {
20458 if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
20459 ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
20460 return -1;
20461 } else {
20462 ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
20463 }
20464 x++;
20465 }
20466 }
20467 AST_LIST_UNLOCK(&r2links);
20468 }
20469#endif
20470 /* And start the monitor for the first time */
20472 return 0;
20473}
20474
20475/*!
20476 * \internal
20477 * \brief Setup DAHDI channel driver.
20478 *
20479 * \param reload enum: load_module(0), reload(1), restart(2).
20480 *
20481 * \retval 0 on success.
20482 * \retval -1 on error.
20483 */
20484static int setup_dahdi(int reload)
20485{
20486 int res;
20487 struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
20488 struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
20490
20491 if (default_conf.chan.cc_params && base_conf.chan.cc_params && conf.chan.cc_params) {
20492 res = setup_dahdi_int(reload, &default_conf, &base_conf, &conf);
20493 } else {
20494 res = -1;
20495 }
20498 ast_cc_config_params_destroy(conf.chan.cc_params);
20499
20500 return res;
20501}
20502
20503/*!
20504 * \brief Load the module
20505 *
20506 * Module loading including tests for configuration or dependencies.
20507 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
20508 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
20509 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
20510 * configuration file or other non-critical problem return
20511 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
20512 */
20513static int load_module(void)
20514{
20515 int res;
20516#if defined(HAVE_PRI) || defined(HAVE_SS7)
20517 int y;
20518#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
20519
20520 if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
20522 }
20523
20526 }
20530
20534 }
20535
20536#ifdef HAVE_PRI
20537 memset(pris, 0, sizeof(pris));
20538 for (y = 0; y < NUM_SPANS; y++) {
20539 sig_pri_init_pri(&pris[y].pri);
20540 }
20541 pri_set_error(dahdi_pri_error);
20542 pri_set_message(dahdi_pri_message);
20543 ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
20544#ifdef HAVE_PRI_PROG_W_CAUSE
20545 ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
20546#endif
20547#if defined(HAVE_PRI_CCSS)
20548 if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
20549 || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
20552 }
20553#endif /* defined(HAVE_PRI_CCSS) */
20554 if (sig_pri_load(
20555#if defined(HAVE_PRI_CCSS)
20556 dahdi_pri_cc_type
20557#else
20558 NULL
20559#endif /* defined(HAVE_PRI_CCSS) */
20560 )) {
20563 }
20564#endif
20565#if defined(HAVE_SS7)
20566 memset(linksets, 0, sizeof(linksets));
20567 for (y = 0; y < NUM_SPANS; y++) {
20568 sig_ss7_init_linkset(&linksets[y].ss7);
20569 }
20570 ss7_set_error(dahdi_ss7_error);
20571 ss7_set_message(dahdi_ss7_message);
20572 ss7_set_hangup(sig_ss7_cb_hangup);
20573 ss7_set_notinservice(sig_ss7_cb_notinservice);
20574 ss7_set_call_null(sig_ss7_cb_call_null);
20575#endif /* defined(HAVE_SS7) */
20576 res = setup_dahdi(0);
20577 /* Make sure we can register our DAHDI channel type */
20578 if (res) {
20581 }
20583 ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
20586 }
20587#ifdef HAVE_PRI
20588 ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
20589#endif
20590#if defined(HAVE_SS7)
20591 ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
20592#endif /* defined(HAVE_SS7) */
20593#ifdef HAVE_OPENR2
20594 ast_cli_register_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
20595 ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
20596#endif
20597
20600
20602 memset(round_robin, 0, sizeof(round_robin));
20603 ast_manager_register_xml("DAHDITransfer", 0, action_transfer);
20605 ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
20608 ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
20609 ast_manager_register_xml("DAHDIShowStatus", 0, action_dahdishowstatus);
20611#if defined(HAVE_PRI)
20612 ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
20613 ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
20614 ast_manager_register_xml("PRIDebugFileSet", EVENT_FLAG_SYSTEM, action_pri_debug_file_set);
20615 ast_manager_register_xml("PRIDebugFileUnset", 0, action_pri_debug_file_unset);
20616#endif /* defined(HAVE_PRI) */
20617
20619
20620 return res;
20621}
20622
20623static int dahdi_sendtext(struct ast_channel *c, const char *text)
20624{
20625#define END_SILENCE_LEN 400
20626#define HEADER_MS 50
20627#define TRAILER_MS 5
20628#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
20629#define ASCII_BYTES_PER_CHAR 80
20630
20631 unsigned char *buf,*mybuf;
20632 struct dahdi_pvt *p = ast_channel_tech_pvt(c);
20633 struct pollfd fds[1];
20634 int size,res,fd,len,x;
20635 int bytes=0;
20636 int idx;
20637
20638 /*
20639 * Initial carrier (imaginary)
20640 *
20641 * Note: The following float variables are used by the
20642 * PUT_CLID_MARKMS and PUT_CLID() macros.
20643 */
20644 float cr = 1.0;
20645 float ci = 0.0;
20646 float scont = 0.0;
20647
20648 if (!text[0]) {
20649 return(0); /* if nothing to send, don't */
20650 }
20651 idx = dahdi_get_index(c, p, 0);
20652 if (idx < 0) {
20653 ast_log(LOG_WARNING, "Huh? I don't exist?\n");
20654 return -1;
20655 }
20656 if ((!p->tdd) && (!p->mate)) {
20657#if defined(HAVE_PRI)
20658#if defined(HAVE_PRI_DISPLAY_TEXT)
20659 ast_mutex_lock(&p->lock);
20661 sig_pri_sendtext(p->sig_pvt, text);
20662 }
20664#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
20665#endif /* defined(HAVE_PRI) */
20666 return(0); /* if not in TDD mode, just return */
20667 }
20668 if (p->mate)
20670 else
20671 buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
20672 if (!buf)
20673 return -1;
20674 mybuf = buf;
20675 if (p->mate) {
20676 /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */
20677 struct ast_format *codec = AST_LAW(p);
20678
20679 for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
20681 }
20682 /* Put actual message */
20683 for (x = 0; text[x]; x++) {
20684 PUT_CLID(text[x]);
20685 }
20686 for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
20688 }
20689 len = bytes;
20690 buf = mybuf;
20691 } else {
20692 len = tdd_generate(p->tdd, buf, text);
20693 if (len < 1) {
20694 ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
20695 ast_free(mybuf);
20696 return -1;
20697 }
20698 }
20699 memset(buf + len, 0x7f, END_SILENCE_LEN);
20701 fd = p->subs[idx].dfd;
20702 while (len) {
20703 if (ast_check_hangup(c)) {
20704 ast_free(mybuf);
20705 return -1;
20706 }
20707 size = len;
20708 if (size > READ_SIZE)
20709 size = READ_SIZE;
20710 fds[0].fd = fd;
20711 fds[0].events = POLLOUT | POLLPRI;
20712 fds[0].revents = 0;
20713 res = poll(fds, 1, -1);
20714 if (!res) {
20715 ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
20716 continue;
20717 }
20718 /* if got exception */
20719 if (fds[0].revents & POLLPRI) {
20720 ast_free(mybuf);
20721 return -1;
20722 }
20723 if (!(fds[0].revents & POLLOUT)) {
20724 ast_debug(1, "write fd not ready on channel %d\n", p->channel);
20725 continue;
20726 }
20727 res = write(fd, buf, size);
20728 if (res != size) {
20729 if (res == -1) {
20730 ast_free(mybuf);
20731 return -1;
20732 }
20733 ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
20734 break;
20735 }
20736 len -= size;
20737 buf += size;
20738 }
20739 ast_free(mybuf);
20740 return(0);
20741}
20742
20743
20744static int reload(void)
20745{
20746 int res = 0;
20747
20748 res = setup_dahdi(1);
20749 if (res) {
20750 ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
20751 return -1;
20752 }
20753 return 0;
20754}
20755
20756/* This is a workaround so that menuselect displays a proper description
20757 * AST_MODULE_INFO(, , "DAHDI Telephony"
20758 */
20759
20761 .support_level = AST_MODULE_SUPPORT_CORE,
20762 .load = load_module,
20763 .unload = unload_module,
20764 .reload = reload,
20765 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
20766 .requires = "ccss",
20767 .optional_modules = "res_smdi",
Common implementation-independent jitterbuffer stuff.
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
ADSI Support (built upon Caller*ID)
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
A-Law to Signed linear conversion.
#define AST_LIN2A(a)
Definition alaw.h:50
#define AST_ALAW(a)
Definition alaw.h:84
char digit
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
char * text
Definition app_queue.c:1791
struct sla_ringing_trunk * last
Definition app_sla.c:338
static int copy(char *infile, char *outfile)
Utility function to copy a file.
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition db.c:335
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition db.c:421
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition db.c:472
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define AST_FILE_MODE
Definition asterisk.h:32
#define PATH_MAX
Definition asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
Bridging API.
ast_transfer_result
Definition bridge.h:1159
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1161
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition bridge.c:4886
void dahdi_native_unload(void)
int dahdi_native_load(const struct ast_channel_tech *tech)
Native DAHDI bridging support.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define PUT_CLID(byte)
Definition callerid.h:412
#define CID_SIG_V23_JP
Definition callerid.h:63
int ast_callerid_callwaiting_full_generate(unsigned char *buf, const char *name, const char *number, const char *ddn, int redirecting, int pres, int qualifier, struct ast_format *codec)
Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
Definition callerid.c:1253
#define CID_TYPE_MDMF
Definition callerid.h:75
#define CID_UNKNOWN_NUMBER
Definition callerid.h:55
int ast_gen_cas(unsigned char *outbuf, int sas, int len, struct ast_format *codec)
Generate a CAS (CPE Alert Signal) tone for 'n' samples.
Definition callerid.c:271
#define CID_SIG_SMDI
Definition callerid.h:64
int ast_callerid_full_generate(unsigned char *buf, const char *name, const char *number, const char *ddn, int redirecting, int pres, int qualifier, int format, struct ast_format *codec)
Generate Caller-ID spill from the "callerid" field of asterisk (in e-mail address like format)
Definition callerid.c:1247
int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, struct ast_format *codec)
Read samples into the state machine.
Definition callerid.c:316
#define AST_PRES_USER_NUMBER_UNSCREENED
Definition callerid.h:426
#define AST_PRES_UNAVAILABLE
Definition callerid.h:434
int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct ast_format *codec, const char *name, const char *number, int flags)
Generate message waiting indicator.
Definition callerid.c:952
#define AST_PRES_RESTRICTED
Definition callerid.h:433
void callerid_free(struct callerid_state *cid)
This function frees callerid_state cid.
Definition callerid.c:833
void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting)
Extract info out of callerID state machine. Flags are listed above.
Definition callerid.c:189
#define MAX_CALLERID_SIZE
Definition callerid.h:50
const char * ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data)
Convert redirecting reason value to text code.
Definition callerid.c:1449
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition callerid.c:1101
int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
Definition callerid.c:1242
#define PUT_CLID_MARKMS
Definition callerid.h:397
#define CID_NOMSGWAITING
Definition callerid.h:57
#define CID_SIG_DTMF
Definition callerid.h:62
#define CID_PRIVATE_NUMBER
Definition callerid.h:53
struct callerid_state * callerid_new(int cid_signalling)
Create a callerID state machine.
Definition callerid.c:130
#define CID_MSGWAITING
Definition callerid.h:56
#define CID_SIG_V23
Definition callerid.h:61
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, struct ast_format *codec)
Read samples into the state machine.
Definition callerid.c:570
#define CID_MWI_TYPE_MDMF_FULL
Definition callerid.h:83
void callerid_get_dtmf(char *cidstring, char *number, int *flags)
Get and parse DTMF-based callerid.
Definition callerid.c:211
#define CID_START_RING
Definition callerid.h:66
#define CID_START_POLARITY
Definition callerid.h:67
#define CID_SIG_BELL
Definition callerid.h:60
#define CID_QUALIFIER
Definition callerid.h:58
void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags)
Extract info out of callerID state machine. Flags are listed above.
Definition callerid.c:205
#define CID_START_POLARITY_IN
Definition callerid.h:68
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition callerid.c:1292
#define CID_START_DTMF_NOALERT
Definition callerid.h:69
Internal Asterisk hangup causes.
#define AST_CAUSE_SWITCH_CONGESTION
Definition causes.h:123
#define AST_CAUSE_CONGESTION
Definition causes.h:153
#define AST_CAUSE_UNALLOCATED
Definition causes.h:98
#define AST_CAUSE_INTERWORKING
Definition causes.h:146
#define AST_CAUSE_PROTOCOL_ERROR
Definition causes.h:145
#define AST_CAUSE_DESTINATION_OUT_OF_ORDER
Definition causes.h:115
#define AST_CAUSE_NO_USER_RESPONSE
Definition causes.h:108
#define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION
Definition causes.h:120
#define AST_CAUSE_NOTDEFINED
Definition causes.h:155
#define AST_CAUSE_CALL_REJECTED
Definition causes.h:111
#define AST_CAUSE_NETWORK_OUT_OF_ORDER
Definition causes.h:121
#define AST_CAUSE_UNREGISTERED
Definition causes.h:154
#define AST_CAUSE_BUSY
Definition causes.h:149
#define AST_CAUSE_NO_ANSWER
Definition causes.h:109
#define AST_CAUSE_NORMAL_CLEARING
Definition causes.h:106
#define AST_CAUSE_USER_BUSY
Definition causes.h:107
Call Completion Supplementary Services API.
#define ast_cc_config_params_init()
Allocate and initialize an ast_cc_config_params structure.
Definition ccss.h:135
#define AST_CC_GENERIC_MONITOR_TYPE
Definition ccss.h:455
int ast_cc_monitor_register(const struct ast_cc_monitor_callbacks *callbacks)
Register a set of monitor callbacks with the core.
Definition ccss.c:1186
void ast_cc_config_params_destroy(struct ast_cc_config_params *params)
Free memory from CCSS configuration params.
Definition ccss.c:714
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:1247
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:876
@ 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:1222
enum ast_cc_monitor_policies ast_get_cc_monitor_policy(struct ast_cc_config_params *config)
Get the cc_monitor_policy.
Definition ccss.c:900
void ast_cc_agent_unregister(const struct ast_cc_agent_callbacks *callbacks)
Unregister a set of agent callbacks with the core.
Definition ccss.c:1265
int ast_cc_is_config_param(const char *const name)
Is this a CCSS configuration parameter?
Definition ccss.c:862
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:823
static PGresult * result
Definition cel_pgsql.c:84
static struct ao2_container * pvts
#define CALLPROGRESS_FAX_INCOMING
Definition chan_dahdi.c:815
static int dahdi_create_channel_range(int start, int end)
static int dahdi_confmute(struct dahdi_pvt *p, int muted)
static ast_mutex_t ss_thread_lock
Definition chan_dahdi.c:897
static int calc_energy(const unsigned char *buf, int len, struct ast_format *law)
#define CALLWAITING_SUPPRESS_SAMPLES
Definition chan_dahdi.c:935
static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
static void release_doomed_pris(void)
static struct dahdi_pvt * round_robin[64]
#define HANGUP
static void my_set_new_owner(void *pvt, struct ast_channel *new_owner)
static int restore_gains(struct dahdi_pvt *p)
static void publish_channel_alarm_clear(int channel)
static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index)
static char * dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void my_set_confirmanswer(void *pvt, int flag)
#define CIDCW_EXPIRE_SAMPLES
Definition chan_dahdi.c:936
static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
static int my_callwait(void *pvt)
static int restore_conference(struct dahdi_pvt *p)
static void publish_span_alarm_clear(int span)
static ast_mutex_t iflock
Protect the interface list (of dahdi_pvt's)
Definition chan_dahdi.c:880
static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
static void notify_message(char *mailbox, int thereornot)
Send MWI state change.
static struct dahdi_pvt * mkintf(int channel, const struct dahdi_chan_conf *conf, int reloading)
static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel)
static int unalloc_sub(struct dahdi_pvt *p, int x)
static int my_check_confirmanswer(void *pvt)
static const char *const events[]
static int reset_conf(struct dahdi_pvt *p)
static int my_is_dialing(void *pvt, enum analog_sub sub)
static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
static struct ast_manager_event_blob * dahdichannel_to_ami(struct stasis_message *msg)
static void my_cancel_cidspill(void *pvt)
static int numbufs
Definition chan_dahdi.c:865
static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
static int my_set_echocanceller(void *pvt, int enable)
static int dahdi_wink(struct dahdi_pvt *p, int index)
static char mwimonitornotify[PATH_MAX]
Definition chan_dahdi.c:855
static char * alarm2str(int alm)
static void my_hangup_polarityswitch(void *pvt)
static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
static int dahdi_ring_phone(struct dahdi_pvt *p)
static char * dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define CALLWAITING_REPEAT_SAMPLES
Definition chan_dahdi.c:934
static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx)
#define DEFAULT_RINGT
Definition chan_dahdi.c:938
#define CALLPROGRESS_FAX_OUTGOING
Definition chan_dahdi.c:814
static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
static int my_stop_cid_detect(void *pvt)
static int my_get_sub_fd(void *pvt, enum analog_sub sub)
static void my_set_needringing(void *pvt, int value)
static char * dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_jb_conf default_jbconf
Definition chan_dahdi.c:748
static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
Callback made when dial failed to get a channel out of dahdi_request().
static struct dahdi_pvt * find_channel_from_str(const char *channel)
static int __unload_module(void)
static void dahdi_softhangup_all(void)
static void dahdi_train_ec(struct dahdi_pvt *p)
static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
static enum analog_event dahdievent_to_analogevent(int event)
static int dahdi_digit_begin(struct ast_channel *ast, char digit)
static void my_unlock_private(void *pvt)
static int dahdichan_helper(struct ast_channel *chan, char *data, const char *value, char *buffer, size_t buflen)
#define HEADER_MS
#define TRANSFER
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
static void my_set_dialing(void *pvt, int is_dialing)
static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
static int mwisend_rpas
Definition chan_dahdi.c:857
static void publish_dnd_state(int channel, const char *status)
static int my_on_hook(void *pvt)
static int attempt_transfer(struct dahdi_pvt *p)
static int cidrings[NUM_CADENCE_MAX]
cidrings says in which pause to transmit the cid information, where the first pause is 1,...
Definition chan_dahdi.c:835
static void my_set_pulsedial(void *pvt, int flag)
static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
static char * dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dahdi_wait_event(int fd)
Avoid the silly dahdi_waitevent which ignores a bunch of events.
Definition chan_dahdi.c:916
static void publish_channel_alarm(int channel, const char *alarm_txt)
static int canmatch_featurecode(const char *pickupexten, const char *exten)
static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law)
struct analog_callback analog_callbacks
static void dahdi_destroy_channel_range(int start, int end)
static char * dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
static void my_set_alarm(void *pvt, int in_alarm)
static int num_restart_pending
Definition chan_dahdi.c:900
static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
static int my_get_event(void *pvt)
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
static int dahdi_devicestate(const char *data)
static int user_has_defined_cadences
Definition chan_dahdi.c:820
static int dahdi_callwait(struct ast_channel *ast)
static void wakeup_sub(struct dahdi_pvt *p, int a)
static void my_set_callwaiting(void *pvt, int callwaiting_enable)
static int distinctiveringaftercid
Definition chan_dahdi.c:863
static int my_is_off_hook(void *pvt)
char * name
#define END_SILENCE_LEN
static int mwi_send_init(struct dahdi_pvt *pvt)
static int dahdi_open(char *fn)
static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages.
static int my_check_waitingfordt(void *pvt)
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
static void publish_span_alarm(int span, const char *alarm_txt)
static int dahdichan_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void my_set_outgoing(void *pvt, int is_outgoing)
static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
static void my_set_inthreeway(void *pvt, enum analog_sub sub, int inthreeway)
static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
static int dahdi_hangup(struct ast_channel *ast)
static void * analog_ss_thread(void *data)
static int dahdi_sendtext(struct ast_channel *c, const char *text)
static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *chan)
static int dahdichan_read_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, char *buffer, size_t len)
static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
#define PROC_DAHDI_OPT_NOCHAN
static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_pattern *busy_cadence)
static int analogsub_to_dahdisub(enum analog_sub analogsub)
static void my_get_and_handle_alarms(void *pvt)
static void my_lock_private(void *pvt)
static int dahdi_answer(struct ast_channel *ast)
static const char tdesc[]
Definition chan_dahdi.c:782
static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
static int dahdi_restart(void)
static int action_transfer(struct mansession *s, const struct message *m)
static int bump_gains(struct dahdi_pvt *p)
static void * do_monitor(void *data)
static int save_conference(struct dahdi_pvt *p)
static char * dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_clear_alarms(struct dahdi_pvt *p)
static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
static char * dahdi_sig2str(int sig)
static int dahdi_set_hook(int fd, int hs)
static int my_stop_callwait(void *pvt)
static struct ast_channel * dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, ast_callid callid, int callid_created)
static int check_for_conference(struct dahdi_pvt *p)
static struct dahdi_ring_cadence AS_RP_cadence
Definition chan_dahdi.c:843
static int dahdichan_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
#define NUM_SPANS
Definition chan_dahdi.c:808
void dahdi_ec_enable(struct dahdi_pvt *p)
#define AST_LAW(p)
Definition chan_dahdi.c:772
static int dahdi_setlinear(int dfd, int linear)
static int restart_monitor(void)
static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
static int my_confmute(void *pvt, int mute)
#define READ_SIZE
Definition chan_dahdi.c:928
static void * mwi_thread(void *data)
#define CALLPROGRESS_FAX
Definition chan_dahdi.c:816
static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
static int sigtype_to_signalling(int sigtype)
static void my_decrease_ss_count(void)
static char * handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int has_voicemail(struct dahdi_pvt *p)
static void dahdi_iflist_extract(struct dahdi_pvt *pvt)
void dahdi_conf_update(struct dahdi_pvt *p)
static int alloc_sub(struct dahdi_pvt *p, int x)
static void my_start_polarityswitch(void *pvt)
static int digit_to_dtmfindex(char digit)
static int setup_dahdi(int reload)
static char * dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int action_dahdidndon(struct mansession *s, const struct message *m)
static int report_alarms
Definition chan_dahdi.c:872
#define GET_CHANNEL(p)
static int mwilevel
Definition chan_dahdi.c:867
static struct dahdi_pvt * iflist
#define NEED_MFDETECT(p)
Signaling types that need to use MF detection should be placed in this macro.
Definition chan_dahdi.c:776
static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
static int set_actual_txgain(int fd, float gain, float drc, int law)
static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
static int my_wait_event(void *pvt)
static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
static int analog_tone_to_dahditone(enum analog_tone tone)
static struct ast_str * create_channel_name(struct dahdi_pvt *i)
static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
#define TRAILER_MS
static int set_actual_rxgain(int fd, float gain, float drc, int law)
static int my_start(void *pvt)
static ast_mutex_t restart_lock
Definition chan_dahdi.c:898
static struct ast_frame * dahdi_handle_event(struct ast_channel *ast)
static char defaultcic[64]
Definition chan_dahdi.c:851
int alarm
static const char config[]
Definition chan_dahdi.c:803
static int action_dahdishowchannels(struct mansession *s, const struct message *m)
void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
static struct dahdi_pvt * find_next_iface_in_span(struct dahdi_pvt *cur)
static ast_cond_t ss_thread_complete
Definition chan_dahdi.c:896
static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
static void dahdi_iflist_insert(struct dahdi_pvt *pvt)
static struct ast_frame * dahdi_exception(struct ast_channel *ast)
static void my_answer_polarityswitch(void *pvt)
static struct ast_channel * dahdi_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
#define SMDI_MD_WAIT_TIMEOUT
Definition chan_dahdi.c:733
static int my_have_progressdetect(void *pvt)
static char * dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
#define CANPROGRESSDETECT(p)
Definition chan_dahdi.c:849
static char * dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
static int my_train_echocanceller(void *pvt)
static const char * event2str(int event)
#define CALLPROGRESS_PROGRESS
Definition chan_dahdi.c:813
static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
#define CHAN_IS_FXO_SIG(sig)
Definition chan_dahdi.c:780
static void my_set_polarity(void *pvt, int value)
void dahdi_ec_disable(struct dahdi_pvt *p)
static struct ast_frame * __dahdi_exception(struct ast_channel *ast)
static void handle_alarms(struct dahdi_pvt *p, int alms)
static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
static struct dahdi_chan_conf dahdi_chan_conf_default(void)
static struct dahdi_pvt * duplicate_pseudo(struct dahdi_pvt *src)
static void swap_subs(struct dahdi_pvt *p, int a, int b)
#define ISTRUNK(p)
Definition chan_dahdi.c:845
static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
static struct ast_channel * dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, ast_callid callid)
static int drc_sample(int sample, float drc)
static int dahdi_get_event(int fd)
Avoid the silly dahdi_getevent which ignores a bunch of events.
Definition chan_dahdi.c:907
static int ringt_base
Configured ring timeout base.
Definition chan_dahdi.c:945
void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
static ast_mutex_t monlock
Protect the monitoring thread, so only one process can kill or start it, and not when it's doing some...
Definition chan_dahdi.c:891
#define ASCII_BYTES_PER_CHAR
static void my_all_subchannels_hungup(void *pvt)
static int my_ring(void *pvt)
static int my_start_cid_detect(void *pvt, int cid_signalling)
static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
static struct dahdi_pvt * ifend
static char * dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int my_complete_conference_update(void *pvt, int needconference)
#define DEFAULT_DIALTONE_DETECT_TIMEOUT
Definition chan_dahdi.c:939
#define IS_FXO_SIG(p)
Whether a channel is FXO signaled.
Definition chan_dahdi.c:779
static int mwi_send_process_buffer(struct dahdi_pvt *pvt, int num_read)
#define HEADER_LEN
static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
static void my_increase_ss_count(void)
#define REPORT_CHANNEL_ALARMS
Definition chan_dahdi.c:870
static int has_pseudo
Definition chan_dahdi.c:822
static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
static int my_wink(void *pvt, enum analog_sub sub)
static struct ast_channel_tech dahdi_tech
static struct ast_jb_conf global_jbconf
Definition chan_dahdi.c:756
#define REQUIRE_FXO_SIG()
static int my_conf_add(void *pvt, enum analog_sub sub)
static int my_dsp_reset_and_flush_digits(void *pvt)
void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
#define PROC_DAHDI_OPT_NOWARN
#define MIN_MS_SINCE_FLASH
Definition chan_dahdi.c:937
static int my_has_voicemail(void *pvt)
static char progzone[10]
Definition chan_dahdi.c:860
static int load_module(void)
Load the module.
#define sig2str
static struct ast_custom_function dahdichan_function
static struct ast_frame * dahdi_read(struct ast_channel *ast)
#define FORMAT
static const char * my_get_orig_dialstring(void *pvt)
static int action_dahdirestart(struct mansession *s, const struct message *m)
static struct ast_custom_function polarity_function
static int get_alarms(struct dahdi_pvt *p)
static struct dahdi_pvt * determine_starting_point(const char *data, struct dahdi_starting_point *param)
#define gen_pvt_field_callback(type, field)
static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
static int send_cwcidspill(struct dahdi_pvt *p)
static int my_conf_del(void *pvt, enum analog_sub sub)
#define FORMAT2
static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX]
Definition chan_dahdi.c:824
static int action_dahdidndoff(struct mansession *s, const struct message *m)
static int unload_module(void)
static int reload(void)
static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
static struct ast_cli_entry dahdi_cli[]
#define POLARITY_IDLE
#define DEFAULT_CIDRINGS
Typically, how many rings before we should send Caller*ID.
Definition chan_dahdi.c:770
static int num_cadence
Definition chan_dahdi.c:819
static int dahdichan_write_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, const char *value)
static enum analog_sigtype dahdisig_to_analogsig(int sig)
static void dahdi_close(int fd)
static char defaultozz[64]
Definition chan_dahdi.c:852
void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
static int dtmfcid_level
Definition chan_dahdi.c:868
#define CHAN_PSEUDO
Definition chan_dahdi.c:811
static int my_off_hook(void *pvt)
const char *const subnames[]
static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
static int usedistinctiveringdetection
Definition chan_dahdi.c:862
static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int print_subchannel(struct dahdi_pvt *p, int subchan, char *buffer, size_t len)
static char * dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct dahdi_pvt * find_channel(int channel)
static void * my_get_sigpvt_bridged_channel(struct ast_channel *chan)
static int send_callerid(struct dahdi_pvt *p)
static int set_hwgain(int fd, float gain, int tx_direction)
static void my_set_waitingfordt(void *pvt, struct ast_channel *ast)
static void build_alarm_info(char *restrict alarmstr, struct dahdi_spaninfo *spaninfo)
static struct @116 alarms[]
static int my_check_for_conference(void *pvt)
static int mwi_send_process_event(struct dahdi_pvt *pvt, int event)
static int my_flash(void *pvt)
#define POLARITY_REV
static int ss_thread_count
Definition chan_dahdi.c:899
static const char *const lbostr[]
Definition chan_dahdi.c:735
int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
#define REPORT_SPAN_ALARMS
Definition chan_dahdi.c:871
static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
static void my_deadlock_avoidance_private(void *pvt)
static struct dahdi_pvt * handle_init_event(struct dahdi_pvt *i, int event)
static void destroy_channel(struct dahdi_pvt *cur, int now)
static void my_set_ringtimeout(void *pvt, int ringt)
static void monitor_pfds_clean(void *arg)
static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
static int ifcount
Definition chan_dahdi.c:883
#define NUM_CADENCE_MAX
Definition chan_dahdi.c:818
static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
static pthread_t monitor_thread
This is the thread for the monitor which checks for input on the channels which are not currently in ...
Definition chan_dahdi.c:895
static int action_transferhangup(struct mansession *s, const struct message *m)
#define CANBUSYDETECT(p)
Definition chan_dahdi.c:848
static int revert_fax_buffers(struct dahdi_pvt *p, struct ast_channel *ast)
static void destroy_all_channels(void)
static int action_dahdishowstatus(struct mansession *s, const struct message *m)
DAHDI internal API definitions.
#define SIG_FEATB
Definition chan_dahdi.h:787
#define SIG_FGC_CAMA
Definition chan_dahdi.h:790
#define SIG_SFWINK
Definition chan_dahdi.h:799
#define SIG_EMWINK
Definition chan_dahdi.h:784
#define SIG_MFCR2
Definition chan_dahdi.h:814
#define SIG_FXSLS
Definition chan_dahdi.h:792
#define MAX_SLAVES
Definition chan_dahdi.h:95
static int dahdi_sig_pri_lib_handles(int signaling)
Definition chan_dahdi.h:831
#define SIG_SF_FEATB
Definition chan_dahdi.h:802
#define SIG_FXSKS
Definition chan_dahdi.h:794
#define SIG_FXOGS
Definition chan_dahdi.h:796
#define SUB_REAL
Definition chan_dahdi.h:57
#define SIG_SF_FEATDMF
Definition chan_dahdi.h:801
static int dahdi_analog_lib_handles(int signalling, int radio, int oprmode)
Definition chan_dahdi.h:847
#define SUB_THREEWAY
Definition chan_dahdi.h:59
#define SUB_CALLWAIT
Definition chan_dahdi.h:58
#define SIG_PRI_LIB_HANDLE_CASES
Definition chan_dahdi.h:817
#define SIG_FXOKS
Definition chan_dahdi.h:797
#define SIG_FGC_CAMAMF
Definition chan_dahdi.h:791
#define SIG_FXSGS
Definition chan_dahdi.h:793
#define SIG_FEATDMF
Definition chan_dahdi.h:786
#define SIG_EM_E1
Definition chan_dahdi.h:803
#define SIG_SF_FEATD
Definition chan_dahdi.h:800
#define SIG_SS7
Definition chan_dahdi.h:811
#define SIG_BRI
Definition chan_dahdi.h:807
@ DAHDI_IFLIST_NONE
Definition chan_dahdi.h:117
@ DAHDI_IFLIST_MAIN
Definition chan_dahdi.h:118
#define SIG_FEATD
Definition chan_dahdi.h:785
#define SIG_BRI_PTMP
Definition chan_dahdi.h:808
#define SIG_FEATDMF_TA
Definition chan_dahdi.h:789
@ MWI_SEND_SA
Definition chan_dahdi.h:102
@ MWI_SEND_PAUSE
Definition chan_dahdi.h:104
@ MWI_SEND_SA_WAIT
Definition chan_dahdi.h:103
@ MWI_SEND_DONE
Definition chan_dahdi.h:107
@ MWI_SEND_SPILL
Definition chan_dahdi.h:105
@ MWI_SEND_CLEANUP
Definition chan_dahdi.h:106
#define SIG_FXOLS
Definition chan_dahdi.h:795
#define SIG_E911
Definition chan_dahdi.h:788
#define SIG_PRI
Definition chan_dahdi.h:806
#define SIG_EM
Definition chan_dahdi.h:783
#define SIG_SF
Definition chan_dahdi.h:798
#define dahdi_get_index(ast, p, nullok)
Definition chan_dahdi.h:888
static struct ast_timer * timer
Definition chan_iax2.c:401
static const char type[]
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3179
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:2888
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:1578
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:1631
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
#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:10744
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition channel.c:1808
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition channel.h:2932
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition channel.h:2983
@ AST_FLAG_END_DTMF_ONLY
Definition channel.h:1027
@ AST_FLAG_BLOCKING
Definition channel.h:1005
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:571
unsigned short ast_channel_transfercapability(const struct ast_channel *chan)
struct ast_namedgroups * ast_ref_namedgroups(struct ast_namedgroups *groups)
Definition channel.c:7774
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
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:10627
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:3008
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:1171
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:1994
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
#define ast_channel_trylock(chan)
Definition channel.h:2985
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:1296
@ 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:1986
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition channel.c:1625
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:7370
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:1213
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:2002
int ast_active_channels(void)
returns number of active/allocated channels
Definition channel.c:500
struct ast_namedgroups * ast_get_namedgroups(const char *s)
Create an ast_namedgroups set with group names from comma separated string.
Definition channel.c:7711
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:446
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:2498
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2462
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:4368
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1274
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition channel.c:1249
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:540
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:3019
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition channel.c:1678
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
Definition channel.c:2845
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:10762
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:2417
@ AST_SOFTHANGUP_EXPLICIT
Definition channel.h:1168
@ AST_SOFTHANGUP_DEV
Definition channel.h:1141
@ AST_SOFTHANGUP_APPUNLOAD
Definition channel.h:1163
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition channel.c:2449
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition channel.c:4382
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
struct ast_namedgroups * ast_unref_namedgroups(struct ast_namedgroups *groups)
Definition channel.c:7768
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:7458
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:3030
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:7654
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:1561
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2984
#define AST_MAX_EXTENSION
Definition channel.h:134
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
@ AST_STATE_RING
@ AST_STATE_DIALING_OFFHOOK
@ AST_STATE_RINGING
@ AST_STATE_PRERING
@ AST_STATE_DOWN
@ AST_STATE_OFFHOOK
@ AST_STATE_BUSY
@ AST_STATE_DIALING
@ AST_STATE_UP
@ AST_STATE_RESERVED
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition channel.c:7422
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
#define RESULT_SUCCESS
Definition cli.h:40
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define RESULT_FAILURE
Definition cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
static struct channel_usage channels
#define container_of(ptr, type, member)
short word
Device state management.
@ AST_DEVSTATE_CACHABLE
Definition devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
Tells Asterisk the State for Device is changed.
ast_device_state
Device States.
Definition devicestate.h:52
@ AST_DEVICE_INUSE
Definition devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition devicestate.h:53
@ AST_DEVICE_BUSY
Definition devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition devicestate.h:58
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
int ast_dsp_get_tcount(struct ast_dsp *dsp)
Get tcount (Threshold counter)
Definition dsp.c:2103
threshold
Definition dsp.h:73
#define DSP_FEATURE_WAITDIALTONE
Definition dsp.h:46
#define DSP_FEATURE_BUSY_DETECT
Definition dsp.h:27
#define DSP_TONE_STATE_DIALTONE
Definition dsp.h:56
void ast_dsp_digitreset(struct ast_dsp *dsp)
Reset DTMF detector.
Definition dsp.c:1995
#define DSP_DIGITMODE_MF
Definition dsp.h:32
#define DSP_DIGITMODE_MUTEMAX
Definition dsp.h:38
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:1989
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:1683
#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:45
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition dsp.c:2044
#define DSP_DIGITMODE_MUTECONF
Definition dsp.h:37
int ast_dsp_get_tstate(struct ast_dsp *dsp)
Get tstate (Tone State)
Definition dsp.c:2098
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:2093
#define DSP_TONE_STATE_RINGING
Definition dsp.h:55
void ast_dsp_set_busy_count(struct ast_dsp *dsp, int cadences)
Set number of required cadences for busy.
Definition dsp.c:1978
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition dsp.c:1953
#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:1943
#define DSP_DIGITMODE_RELAXDTMF
Definition dsp.h:39
int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone)
Set zone for doing progress detection.
Definition dsp.c:2079
char * bs
Definition eagi_proxy.c:73
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
char * address
Definition f2c.h:59
#define abs(x)
Definition f2c.h:195
long int flag
Definition f2c.h:83
#define max(a, b)
Definition f2c.h:198
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1320
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition file.c:1882
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition format.h:36
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
struct ast_format * ast_format_alaw
Built-in cached alaw format.
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
static const char name[]
Definition format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:1963
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition manager.c:637
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:1999
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:1953
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2007
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
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:151
#define AST_APP_ARG(name)
Define an application argument.
#define ast_app_separate_args(a, b, c, d)
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
Definition main/app.c:582
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_FILEUNCHANGED
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition extconf.c:3272
#define ast_variable_new(name, value, filename)
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
#define AST_FRAME_DTMF
#define AST_OPTION_RELAXDTMF
#define AST_OPTION_TONE_VERIFY
#define AST_OPTION_RXGAIN
#define AST_OPTION_DIGIT_DETECT
#define AST_OPTION_OPRMODE
#define ast_frfree(fr)
#define AST_OPTION_CC_AGENT_TYPE
#define AST_OPTION_TDD
#define AST_OPTION_FAX_DETECT
#define AST_OPTION_TXGAIN
#define AST_OPTION_ECHOCAN
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_CONTROL
@ AST_CONTROL_SRCUPDATE
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_RADIO_UNKEY
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_RADIO_KEY
@ AST_CONTROL_FLASH
@ AST_CONTROL_INCOMPLETE
@ AST_CONTROL_PVT_CAUSE_CODE
#define AST_OPTION_AUDIO_MODE
struct ast_frame ast_null_frame
Definition main/frame.c:79
void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
Use in conjunction with ast_callid_threadstorage_auto. Cleans up the references and if the callid was...
Definition logger.c:2367
#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:2345
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:2568
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
#define ast_verbose_callid(callid,...)
#define ast_verbose(...)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition json.c:332
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition json.h:87
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_MOVE_CURRENT(newhead, field)
Move the current list entry to another list.
#define AST_LIST_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Asterisk locking-related definitions:
#define DLA_LOCK(lock)
Definition lock.h:499
#define DLA_UNLOCK(lock)
Definition lock.h:497
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
#define AST_PTHREADT_NULL
Definition lock.h:73
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition lock.h:481
#define DEADLOCK_AVOIDANCE(lock)
Definition lock.h:486
#define AST_PTHREADT_STOP
Definition lock.h:74
#define ast_mutex_unlock(a)
Definition lock.h:197
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define ast_mutex_trylock(a)
Definition lock.h:198
pthread_cond_t ast_cond_t
Definition lock.h:185
#define ast_mutex_destroy(a)
Definition lock.h:195
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define ast_cond_signal(cond)
Definition lock.h:210
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
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:10251
#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:404
@ 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:7802
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition channel.c:7812
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:3315
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:2735
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:1563
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:2750
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:3268
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition pbx.c:5177
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:2755
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:5251
Call Pickup API.
int ast_pickup_call(struct ast_channel *chan)
Pickup a call.
Definition pickup.c:202
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
static struct @523 args
static int debug
Global debug status.
Definition res_xmpp.c:570
#define NULL
Definition resample.c:96
Say numbers and dates (maybe words one day too)
int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
int analog_available(struct analog_pvt *p)
Definition sig_analog.c:803
struct ast_frame * analog_exception(struct analog_pvt *p, struct ast_channel *ast)
int analog_dnd(struct analog_pvt *p, int flag)
int analog_callwaiting_deluxe(struct analog_pvt *p, int option)
int analog_config_complete(struct analog_pvt *p)
void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest, int timeout)
void analog_delete(struct analog_pvt *doomed)
Delete the analog private structure.
struct analog_pvt * analog_new(enum analog_sigtype signallingtype, void *private_data)
int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
enum analog_sigtype sigtype
Definition sig_analog.c:69
struct ast_channel * analog_request(struct analog_pvt *p, int *callwait, const struct ast_channel *requestor)
Definition sig_analog.c:780
void * analog_handle_init_event(struct analog_pvt *i, int event)
int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
Interface header for analog signaling module.
#define ANALOG_MAX_CID
Definition sig_analog.h:33
analog_dsp_digitmode
Definition sig_analog.h:114
@ ANALOG_DIGITMODE_DTMF
Definition sig_analog.h:115
@ ANALOG_DIGITMODE_MF
Definition sig_analog.h:116
#define ANALOG_INTER_DIGIT_TIMEOUT
Default time (ms) to detect following digits.
Definition sig_analog.h:40
#define ANALOG_MATCH_DIGIT_TIMEOUT
Default time (ms) to wait, in case of ambiguous match.
Definition sig_analog.h:42
@ ANALOG_DIALMODE_DTMF
Definition sig_analog.h:122
@ ANALOG_DIALMODE_PULSE
Definition sig_analog.h:121
@ ANALOG_DIALMODE_NONE
Definition sig_analog.h:123
@ ANALOG_DIALMODE_BOTH
Definition sig_analog.h:120
#define RING_PATTERNS
Definition sig_analog.h:35
analog_event
Definition sig_analog.h:79
@ ANALOG_EVENT_NONE
Definition sig_analog.h:80
@ ANALOG_EVENT_HOOKCOMPLETE
Definition sig_analog.h:89
@ ANALOG_EVENT_DTMFDOWN
Definition sig_analog.h:104
@ ANALOG_EVENT_RINGEROFF
Definition sig_analog.h:88
@ ANALOG_EVENT_PULSE_START
Definition sig_analog.h:90
@ ANALOG_EVENT_DTMFCID
Definition sig_analog.h:102
@ ANALOG_EVENT_TX_CED_DETECTED
Definition sig_analog.h:97
@ ANALOG_EVENT_NEONMWI_ACTIVE
Definition sig_analog.h:95
@ ANALOG_EVENT_RINGBEGIN
Definition sig_analog.h:92
@ ANALOG_EVENT_ONHOOK
Definition sig_analog.h:81
@ ANALOG_EVENT_EC_DISABLED
Definition sig_analog.h:93
@ ANALOG_EVENT_WINKFLASH
Definition sig_analog.h:83
@ ANALOG_EVENT_ERROR
Definition sig_analog.h:101
@ ANALOG_EVENT_PULSEDIGIT
Definition sig_analog.h:103
@ ANALOG_EVENT_RINGERON
Definition sig_analog.h:87
@ ANALOG_EVENT_RX_CED_DETECTED
Definition sig_analog.h:98
@ ANALOG_EVENT_ALARM
Definition sig_analog.h:84
@ ANALOG_EVENT_DIALCOMPLETE
Definition sig_analog.h:86
@ ANALOG_EVENT_EC_NLP_ENABLED
Definition sig_analog.h:100
@ ANALOG_EVENT_POLARITY
Definition sig_analog.h:91
@ ANALOG_EVENT_NEONMWI_INACTIVE
Definition sig_analog.h:96
@ ANALOG_EVENT_DTMFUP
Definition sig_analog.h:105
@ ANALOG_EVENT_EC_NLP_DISABLED
Definition sig_analog.h:99
@ ANALOG_EVENT_RINGOFFHOOK
Definition sig_analog.h:82
@ ANALOG_EVENT_REMOVED
Definition sig_analog.h:94
@ ANALOG_EVENT_NOALARM
Definition sig_analog.h:85
@ ANALOG_DIAL_OP_REPLACE
Definition sig_analog.h:134
analog_sub
Definition sig_analog.h:108
@ ANALOG_SUB_THREEWAY
Definition sig_analog.h:111
@ ANALOG_SUB_REAL
Definition sig_analog.h:109
@ ANALOG_SUB_CALLWAIT
Definition sig_analog.h:110
#define ANALOG_FIRST_DIGIT_TIMEOUT
Default time (ms) to detect first digit.
Definition sig_analog.h:38
analog_sigtype
Definition sig_analog.h:45
@ ANALOG_SIG_FEATD
Definition sig_analog.h:56
@ ANALOG_SIG_FEATDMF_TA
Definition sig_analog.h:66
@ ANALOG_SIG_FGC_CAMAMF
Definition sig_analog.h:60
@ ANALOG_SIG_FXOLS
Definition sig_analog.h:47
@ ANALOG_SIG_FEATDMF
Definition sig_analog.h:57
@ ANALOG_SIG_EM_E1
Definition sig_analog.h:55
@ ANALOG_SIG_EMWINK
Definition sig_analog.h:53
@ ANALOG_SIG_FXOKS
Definition sig_analog.h:48
@ ANALOG_SIG_SF
Definition sig_analog.h:63
@ ANALOG_SIG_FGC_CAMA
Definition sig_analog.h:59
@ ANALOG_SIG_FXSLS
Definition sig_analog.h:50
@ ANALOG_SIG_EM
Definition sig_analog.h:54
@ ANALOG_SIG_FXOGS
Definition sig_analog.h:49
@ ANALOG_SIG_NONE
Definition sig_analog.h:46
@ ANALOG_SIG_FXSGS
Definition sig_analog.h:52
@ ANALOG_SIG_SF_FEATDMF
Definition sig_analog.h:65
@ ANALOG_SIG_SFWINK
Definition sig_analog.h:62
@ ANALOG_SIG_FEATB
Definition sig_analog.h:61
@ ANALOG_SIG_SF_FEATD
Definition sig_analog.h:64
@ ANALOG_SIG_FXSKS
Definition sig_analog.h:51
analog_tone
Definition sig_analog.h:70
@ ANALOG_TONE_CONGESTION
Definition sig_analog.h:73
@ ANALOG_TONE_INFO
Definition sig_analog.h:76
@ ANALOG_TONE_DIALTONE
Definition sig_analog.h:74
@ ANALOG_TONE_DIALRECALL
Definition sig_analog.h:75
@ ANALOG_TONE_STUTTER
Definition sig_analog.h:72
@ ANALOG_TONE_RINGTONE
Definition sig_analog.h:71
@ ANALOG_CID_START_RING
Definition sig_analog.h:129
@ ANALOG_CID_START_DTMF_NOALERT
Definition sig_analog.h:130
@ ANALOG_CID_START_POLARITY
Definition sig_analog.h:127
@ ANALOG_CID_START_POLARITY_IN
Definition sig_analog.h:128
Interface header for PRI signaling module.
int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
void sig_pri_unload(void)
sig_pri_law
Definition sig_pri.h:67
@ SIG_PRI_DEFLAW
Definition sig_pri.h:68
@ SIG_PRI_ULAW
Definition sig_pri.h:69
@ SIG_PRI_ALAW
Definition sig_pri.h:70
#define SIG_PRI_DEBUG_NORMAL
Definition sig_pri.h:41
@ SIG_PRI_COLP_UPDATE
Definition sig_pri.h:441
@ SIG_PRI_COLP_CONNECT
Definition sig_pri.h:439
@ SIG_PRI_COLP_BLOCK
Definition sig_pri.h:437
int pri_send_callrerouting_facility_exec(struct sig_pri_chan *p, enum ast_channel_state chanstate, const char *destination, const char *original, const char *reason)
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id)
int sig_pri_cc_agent_status_req(struct ast_cc_agent *agent)
struct sig_pri_callback sig_pri_callbacks
int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
void sig_pri_extract_called_num_subaddr(struct sig_pri_chan *p, const char *rdest, char *called, size_t called_buff_size)
#define SIG_PRI_NUM_DCHANS
Definition sig_pri.h:239
int sig_pri_cc_agent_start_offer_timer(struct ast_cc_agent *agent)
int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
int sig_pri_cc_monitor_unsuspend(struct ast_cc_monitor *monitor)
int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rdest, int timeout, int layer1)
#define DAHDI_OVERLAPDIAL_OUTGOING
Definition sig_pri.h:252
int sig_pri_is_alarm_ignored(struct sig_pri_span *pri)
int sig_pri_cc_monitor_req_cc(struct ast_cc_monitor *monitor, int *available_timer_id)
int sig_pri_start_pri(struct sig_pri_span *pri)
int sig_pri_cc_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id)
void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri)
void sig_pri_cc_agent_req_rsp(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
int sig_pri_cc_monitor_suspend(struct ast_cc_monitor *monitor)
@ SIG_PRI_RESET_IDLE
The channel is not being RESTARTed.
Definition sig_pri.h:154
#define DAHDI_OVERLAPDIAL_BOTH
Definition sig_pri.h:254
void sig_pri_stop_pri(struct sig_pri_span *pri)
void sig_pri_cc_agent_destructor(struct ast_cc_agent *agent)
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri)
void sig_pri_init_pri(struct sig_pri_span *pri)
#define SIG_PRI_AOC_GRANT_D
Definition sig_pri.h:54
#define DAHDI_OVERLAPDIAL_NONE
Definition sig_pri.h:251
int sig_pri_cc_agent_start_monitoring(struct ast_cc_agent *agent)
#define DAHDI_CHAN_MAPPING_LOGICAL
Definition sig_pri.h:248
int sig_pri_cc_agent_init(struct ast_cc_agent *agent, struct sig_pri_chan *pvt_chan)
void sig_pri_chan_alarm_notify(struct sig_pri_chan *p, int noalarm)
int sig_pri_load(const char *cc_type_name)
@ SIG_PRI_CALL_LEVEL_PROCEEDING
Definition sig_pri.h:143
@ SIG_PRI_MOH_SIGNALING_MOH
Definition sig_pri.h:75
@ SIG_PRI_MOH_SIGNALING_NOTIFY
Definition sig_pri.h:77
int sig_pri_cc_agent_callee_available(struct ast_cc_agent *agent)
#define DAHDI_OVERLAPDIAL_INCOMING
Definition sig_pri.h:253
struct ast_channel * sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int transfercapability)
#define SIG_PRI_AOC_GRANT_E
Definition sig_pri.h:55
void sig_pri_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_pri_chan *pchan)
void sig_pri_cc_monitor_destructor(void *monitor_pvt)
void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
struct sig_pri_chan * sig_pri_chan_new(void *pvt_data, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup)
void pri_event_noalarm(struct sig_pri_span *pri, int index, int before_start_pri)
void sig_pri_cli_show_span(int fd, int *dchannels, struct sig_pri_span *pri)
void sig_pri_chan_delete(struct sig_pri_chan *doomed)
int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast)
#define SIG_PRI_AOC_GRANT_S
Definition sig_pri.h:53
sig_pri_tone
Definition sig_pri.h:57
@ SIG_PRI_TONE_RINGTONE
Definition sig_pri.h:58
@ SIG_PRI_TONE_INFO
Definition sig_pri.h:63
@ SIG_PRI_TONE_DIALTONE
Definition sig_pri.h:61
@ SIG_PRI_TONE_BUSY
Definition sig_pri.h:64
@ SIG_PRI_TONE_STUTTER
Definition sig_pri.h:59
@ SIG_PRI_TONE_CONGESTION
Definition sig_pri.h:60
@ SIG_PRI_TONE_DIALRECALL
Definition sig_pri.h:62
void pri_event_alarm(struct sig_pri_span *pri, int index, int before_start_pri)
int sig_pri_cc_agent_stop_offer_timer(struct ast_cc_agent *agent)
void sig_pri_cli_show_channels_header(int fd)
void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
int sig_pri_cc_agent_party_b_free(struct ast_cc_agent *agent)
int sig_pri_cc_monitor_status_rsp(struct ast_cc_monitor *monitor, enum ast_device_state devstate)
#define DAHDI_CHAN_MAPPING_PHYSICAL
Definition sig_pri.h:247
int sig_pri_cc_agent_stop_ringing(struct ast_cc_agent *agent)
int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char digit)
int pri_send_keypad_facility_exec(struct sig_pri_chan *p, const char *digits)
Interface header for SS7 signaling module.
void sig_ss7_cb_call_null(struct ss7 *ss7, struct isup_call *c, int lock)
void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
void sig_ss7_cli_show_channels_header(int fd)
struct ast_channel * sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int transfercapability)
void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7)
void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which)
#define LINKSET_FLAG_EXPLICITACM
Definition sig_ss7.h:68
#define LINKSET_FLAG_AUTOACM
Definition sig_ss7.h:72
int sig_ss7_reset_group(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, int range)
int sig_ss7_available(struct sig_ss7_chan *p)
void sig_ss7_cb_notinservice(struct ss7 *ss7, int cic, unsigned int dpc)
int sig_ss7_reset_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rdest)
void * ss7_linkset(void *data)
int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
#define SS7_BLOCKED_MAINTENANCE
Definition sig_ss7.h:74
int sig_ss7_group_blocking(struct sig_ss7_linkset *linkset, int do_block, int startcic, int endcic, unsigned char state[], int type)
int sig_ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
#define SIG_SS7_DEBUG
Definition sig_ss7.h:43
struct sig_ss7_callback sig_ss7_callbacks
void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm)
sig_ss7_tone
Definition sig_ss7.h:78
@ SIG_SS7_TONE_DIALRECALL
Definition sig_ss7.h:83
@ SIG_SS7_TONE_INFO
Definition sig_ss7.h:84
@ SIG_SS7_TONE_STUTTER
Definition sig_ss7.h:80
@ SIG_SS7_TONE_RINGTONE
Definition sig_ss7.h:79
@ SIG_SS7_TONE_CONGESTION
Definition sig_ss7.h:81
@ SIG_SS7_TONE_DIALTONE
Definition sig_ss7.h:82
@ SIG_SS7_TONE_BUSY
Definition sig_ss7.h:85
struct sig_ss7_chan * sig_ss7_chan_new(void *pvt_data, struct sig_ss7_linkset *ss7)
void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset)
int sig_ss7_cic_blocking(struct sig_ss7_linkset *linkset, int do_block, int cic)
#define LINKSET_FLAG_DEFAULTECHOCONTROL
Definition sig_ss7.h:71
sig_ss7_law
Definition sig_ss7.h:88
@ SIG_SS7_DEFLAW
Definition sig_ss7.h:89
@ SIG_SS7_ULAW
Definition sig_ss7.h:90
@ SIG_SS7_ALAW
Definition sig_ss7.h:91
#define LINKSET_FLAG_USEECHOCONTROL
Definition sig_ss7.h:70
void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
#define LINKSET_FLAG_INITIALHWBLO
Definition sig_ss7.h:69
int sig_ss7_cb_hangup(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)
#define SS7_NAI_DYNAMIC
Definition sig_ss7.h:66
int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode, int cur_slc)
int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan)
#define SS7_BLOCKED_HARDWARE
Definition sig_ss7.h:75
#define SIG_SS7_NUM_DCHANS
Definition sig_ss7.h:56
int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
int sig_ss7_find_cic_range(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
SMDI support for Asterisk.
#define SMDI_MAX_FILENAME_LEN
Definition smdi.h:42
struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
Definition res_smdi.c:569
struct ast_smdi_md_message *AST_OPTIONAL_API_NAME() ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
Get the next SMDI message from the queue.
Definition res_smdi.c:545
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name,...)
Boiler-plate messaging macro for defining local message types.
Definition stasis.h:1498
void stasis_subscription_cb_noop(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Stasis subscription callback function that does nothing.
Definition stasis.c:876
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id)
Retrieve an item from the cache for the ast_eid_default entity.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
#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:2250
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
int(*const play_tone)(void *pvt, enum analog_sub sub, enum analog_tone tone)
Definition sig_analog.h:182
int(*const start)(void *pvt)
Definition sig_analog.h:161
unsigned int immediate
Definition sig_analog.h:298
unsigned int immediatering
Definition sig_analog.h:299
unsigned int permcallwaiting
Definition sig_analog.h:301
unsigned int callwaitingdeluxepending
TRUE if a Call Waiting Deluxe action is currently pending.
Definition sig_analog.h:356
unsigned int canpark
Definition sig_analog.h:295
unsigned int dnd
Definition sig_analog.h:340
unsigned int dahditrcallerid
Definition sig_analog.h:296
char lastexten[AST_MAX_EXTENSION]
Definition sig_analog.h:364
int polarityonanswerdelay
Definition sig_analog.h:327
char cid_num[AST_MAX_EXTENSION]
Definition sig_analog.h:331
int redirecting_reason
Definition sig_analog.h:366
unsigned int permhidecallerid
Definition sig_analog.h:303
struct timeval flashtime
Definition sig_analog.h:374
unsigned int callwaitingcallerid
Definition sig_analog.h:312
unsigned int ani_wink_time
Definition sig_analog.h:289
enum analog_sigtype outsigmod
Definition sig_analog.h:323
unsigned int usedistinctiveringdetection
Definition sig_analog.h:311
unsigned int answeronpolarityswitch
Definition sig_analog.h:291
unsigned int threewaycalling
Definition sig_analog.h:306
unsigned int pulse
Definition sig_analog.h:305
int echotraining
Definition sig_analog.h:325
int msgstate
-1 = unknown, 0 = no messages, 1 = new messages available
Definition sig_analog.h:284
unsigned int hanguponpolarityswitch
Definition sig_analog.h:297
enum analog_dialmode permdialmode
Definition sig_analog.h:304
unsigned int callwaitingdeluxe
Definition sig_analog.h:302
char call_forward[AST_MAX_EXTENSION]
Definition sig_analog.h:379
enum analog_cid_start cid_start
Definition sig_analog.h:329
unsigned int callreturn
Definition sig_analog.h:293
struct ast_channel * owner
Definition sig_analog.h:277
unsigned int use_smdi
TRUE if SMDI (Simplified Message Desk Interface) is enabled.
Definition sig_analog.h:316
unsigned int call_qualifier
Definition sig_analog.h:358
unsigned int ani_timeout
Definition sig_analog.h:288
unsigned int lastnumredial
Definition sig_analog.h:300
int fxsoffhookstate
Definition sig_analog.h:282
unsigned int ani_info_digits
Definition sig_analog.h:287
enum analog_dialmode dialmode
Definition sig_analog.h:324
unsigned int cancallforward
Definition sig_analog.h:294
struct analog_subchannel subs[3]
Definition sig_analog.h:279
int cid_signalling
Definition sig_analog.h:326
unsigned int transfer
Definition sig_analog.h:308
unsigned int transfertobusy
Definition sig_analog.h:309
unsigned int inalarm
Definition sig_analog.h:344
char cid_name[AST_MAX_EXTENSION]
Definition sig_analog.h:332
unsigned int calledsubscriberheld
Definition sig_analog.h:292
char mohsuggest[MAX_MUSICCLASS]
Definition sig_analog.h:330
unsigned int use_callerid
Definition sig_analog.h:310
struct ast_channel * ss_astchan
Definition sig_analog.h:382
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition sig_analog.h:318
struct ast_party_caller caller
Definition sig_analog.h:365
struct ast_channel * owner
Definition sig_analog.h:264
Structure to pass both assignedid values to channel drivers.
Definition channel.h:606
Structure that contains information regarding a channel in a bridge.
struct ast_channel * chan
const char * type
Type of agent the callbacks belong to.
Definition ccss.h:857
Callbacks defined by CC monitors.
Definition ccss.h:542
const char * type
Type of monitor the callbacks belong to.
Definition ccss.h:549
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
struct ast_format_cap * capabilities
Definition channel.h:652
const char *const type
Definition channel.h:649
Main Channel structure associated with a channel.
ast_callid callid
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
struct ast_flags flags
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
int pattern[4]
Definition dsp.h:70
Configuration relating to call pickup.
Structure used to handle boolean flags.
Definition utils.h:220
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
struct ast_codec * codec
Pointer to the codec in use for this format.
Definition format.c:47
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
struct timeval delivery
enum ast_frame_type frametype
union ast_frame::@237 data
General jitterbuffer configuration.
Definition abstract_jb.h:70
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition abstract_jb.h:72
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition manager.h:504
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::@218 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...
char smdi_port[SMDI_MAX_FILENAME_LEN]
The serial port to listen for SMDI data on.
struct dahdi_params timing
int wanted_channels_end
Don't create channels above this number (infinity by default)
struct dahdi_pvt chan
int wanted_channels_start
Don't create channels below this number.
struct ringContextData ringContext[3]
Definition chan_dahdi.h:71
struct distRingData ringnum[3]
Definition chan_dahdi.h:70
unsigned int echocanon
TRUE if echo cancellation is turned on.
Definition chan_dahdi.h:272
char dialdest[256]
Delayed dialing for E911. Overlap digits for ISDN.
Definition chan_dahdi.h:719
unsigned int immediate
TRUE if the channel should be answered immediately without attempting to gather any digits.
Definition chan_dahdi.h:316
unsigned int immediatering
TRUE if audible ringback should be provided when immediate = yes.
Definition chan_dahdi.h:322
unsigned int threewaysilenthold
TRUE if a three way dial tone should time out to silence.
Definition chan_dahdi.h:377
enum DAHDI_IFLIST which_iflist
Definition chan_dahdi.h:168
unsigned int permcallwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition chan_dahdi.h:334
float cid_rxgain
Amount of gain to increase during caller id.
Definition chan_dahdi.h:158
float txdrc
Definition chan_dahdi.h:164
struct dahdi_distRings drings
Distinctive Ring data.
Definition chan_dahdi.h:491
struct ast_variable * vars
Channel variable list with associated values to set when a channel is created.
Definition chan_dahdi.h:590
char cid_subaddr[AST_MAX_EXTENSION]
Caller ID subaddress from an incoming call.
Definition chan_dahdi.h:543
unsigned int canpark
TRUE if support for call parking is enabled.
Definition chan_dahdi.h:243
unsigned int bufferoverrideinuse
Definition chan_dahdi.h:278
int law
Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition chan_dahdi.h:562
unsigned int hwtxgain_enabled
TRUE if hardware Tx gain set by Asterisk.
Definition chan_dahdi.h:475
unsigned int dnd
TRUE if Do-Not-Disturb is enabled, present only for non sig_analog.
Definition chan_dahdi.h:262
int faxbuf_policy
Definition chan_dahdi.h:142
unsigned int ignoredtmf
TRUE if DTMF detection is disabled.
Definition chan_dahdi.h:310
struct dahdi_dialoperation dop
DAHDI dial operation command struct for ioctl() call.
Definition chan_dahdi.h:702
struct timeval dtmfcid_delay
Definition chan_dahdi.h:597
unsigned int dahditrcallerid
TRUE if we should use the callerid from incoming call on dahdi transfer.
Definition chan_dahdi.h:412
struct dahdi_pvt * next
Definition chan_dahdi.h:169
unsigned int doreoriginate
Internal flag for if we should actually process a reorigination.
Definition chan_dahdi.h:293
unsigned char * cidspill
Analog caller ID waveform sample buffer.
Definition chan_dahdi.h:603
struct tdd_state * tdd
Definition chan_dahdi.h:708
int waitfordialtonetemp
Transient variable. Same as waitfordialtone, but temporarily set for a specific call,...
Definition chan_dahdi.h:666
int cidlen
Length of the cidspill buffer containing samples.
Definition chan_dahdi.h:607
int polarityonanswerdelay
Minimal time period (ms) between the answer polarity switch and hangup polarity switch.
Definition chan_dahdi.h:733
int busycount
Number of times to see "busy" tone before hanging up.
Definition chan_dahdi.h:647
char cid_num[AST_MAX_EXTENSION]
Caller ID number from an incoming call.
Definition chan_dahdi.h:532
int ringt
Ring timeout timer??
Definition chan_dahdi.h:609
struct ast_mwi_subscriber * mwi_event_sub
Opaque event subscription parameters for message waiting indication support.
Definition chan_dahdi.h:717
ast_group_t group
Bitmapped groups this belongs to.
Definition chan_dahdi.h:558
int sendcalleridafter
Send caller ID on FXS after this many rings. Set to 1 for US.
Definition chan_dahdi.h:740
struct dahdi_pvt * oprpeer
Definition chan_dahdi.h:152
unsigned int permhidecallerid
TRUE if the outgoing caller ID is blocked/restricted/hidden.
Definition chan_dahdi.h:343
unsigned int mwisendactive
TRUE if a MWI message sending thread is active.
Definition chan_dahdi.h:437
char * origcid_name
Definition chan_dahdi.h:545
struct mwisend_info mwisend_data
Definition chan_dahdi.h:486
int cid_suppress_expire
Definition chan_dahdi.h:601
struct timeval flashtime
Definition chan_dahdi.h:698
int interdigit_timeout
Time (ms) to detect following digits (in an analog phone)
Definition chan_dahdi.h:691
unsigned int mwimonitor_rpas
TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
Definition chan_dahdi.h:433
struct dahdi_pvt * master
Definition chan_dahdi.h:135
unsigned int confirmanswer
TRUE if to wait for a DTMF digit to confirm answer.
Definition chan_dahdi.h:245
unsigned int restartpending
Definition chan_dahdi.h:361
unsigned int mwimonitoractive
TRUE if an MWI monitor thread is currently active.
Definition chan_dahdi.h:435
unsigned int outgoing
TRUE if we originated the call leg.
Definition chan_dahdi.h:328
unsigned int faxdetect_timeout
The number of seconds into call to disable fax detection. (0 = disabled)
Definition chan_dahdi.h:681
int whichwink
Definition chan_dahdi.h:703
float rxdrc
Definition chan_dahdi.h:165
unsigned int callwaitingcallerid
TRUE if send caller ID for Call Waiting.
Definition chan_dahdi.h:231
char * origcid_num
Definition chan_dahdi.h:544
unsigned int manages_span_alarms
TRUE if the channel alarms will be managed also as Span ones.
Definition chan_dahdi.h:471
unsigned int ani_wink_time
INTEGER, length of time to wait before sending ANI wink in ms.
Definition chan_dahdi.h:200
int waitfordialtone
Number of milliseconds to wait for dialtone.
Definition chan_dahdi.h:662
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition chan_dahdi.h:457
unsigned int adsi
TRUE if ADSI (Analog Display Services Interface) available.
Definition chan_dahdi.h:178
int outsigmod
Definition chan_dahdi.h:150
unsigned int usedistinctiveringdetection
TRUE if distinctive rings are to be detected.
Definition chan_dahdi.h:407
unsigned int answeronpolarityswitch
TRUE if we can use a polarity reversal to mark when an outgoing call is answered by the remote party.
Definition chan_dahdi.h:184
unsigned int threewaycalling
TRUE if three way calling is enabled.
Definition chan_dahdi.h:372
struct dahdi_subchannel subs[3]
Definition chan_dahdi.h:131
int distinctivering
Definition chan_dahdi.h:725
struct dahdi_confinfo saveconf
Definition chan_dahdi.h:132
unsigned int use_callingpres
TRUE if we will use the calling presentation setting from the Asterisk channel for outgoing calls.
Definition chan_dahdi.h:401
int dtmfrelax
Definition chan_dahdi.h:726
unsigned int pulse
TRUE if we will pulse dial.
Definition chan_dahdi.h:358
int dialtone_scanning_time_elapsed
Definition chan_dahdi.h:676
unsigned int priexclusive
TRUE if PRI B channels are always exclusively selected.
Definition chan_dahdi.h:353
char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Voice mailbox location.
Definition chan_dahdi.h:715
float hwrxgain
Hardware Rx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:154
int echotraining
Echo training time. 0 = disabled.
Definition chan_dahdi.h:640
char callwait_num[AST_MAX_EXTENSION]
Call waiting number.
Definition chan_dahdi.h:547
float hwtxgain
Hardware Tx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:156
int waitfordialtoneduration
Transient variable. Stored off waitfordialtone duration at runtime.
Definition chan_dahdi.h:670
int dsp_features
DSP feature flags: DSP_FEATURE_xxx.
Definition chan_dahdi.h:744
unsigned int callwaiting
TRUE if busy extensions will hear the call-waiting tone and can use hook-flash to switch between call...
Definition chan_dahdi.h:226
char exten[AST_MAX_EXTENSION]
Extension to use in the dialplan.
Definition chan_dahdi.h:508
int callprogress
Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
Definition chan_dahdi.h:657
int callwaitcas
TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
Definition chan_dahdi.h:628
time_t guardtime
Definition chan_dahdi.h:593
struct timeval polaritydelaytv
Start delay time if polarityonanswerdelay is nonzero.
Definition chan_dahdi.h:735
unsigned int hanguponpolarityswitch
TRUE if the call will be considered "hung up" on a polarity reversal.
Definition chan_dahdi.h:285
enum analog_dialmode permdialmode
Definition chan_dahdi.h:149
char dnid[AST_MAX_EXTENSION]
Dialed Number Identifier.
Definition chan_dahdi.h:553
char dialstring[AST_CHANNEL_NAME]
Definition chan_dahdi.h:778
unsigned int callwaitingdeluxe
TRUE if Call Waiting Deluxe options should be available.
Definition chan_dahdi.h:338
char call_forward[AST_MAX_EXTENSION]
Accumulated call forwarding number.
Definition chan_dahdi.h:710
char description[32]
A description for the channel configuration.
Definition chan_dahdi.h:502
unsigned int firstradio
TRUE if over a radio and dahdi_read() has been called.
Definition chan_dahdi.h:280
unsigned int remotelyblocked
Bitmask for the channel being remotely blocked. 1 maintenance, 2 blocked in hardware.
Definition chan_dahdi.h:466
unsigned int hidecallerid
TRUE if the outgoing caller ID is blocked/hidden.
Definition chan_dahdi.h:302
unsigned int echobreak
XXX BOOLEAN Purpose???
Definition chan_dahdi.h:264
struct dahdi_pvt::@117 echocancel
Echo cancel parameters.
struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS]
Definition chan_dahdi.h:634
int faxbuf_no
Definition chan_dahdi.h:141
unsigned int callreturn
TRUE if call return is enabled. (*69, if your dialplan doesn't catch this first)
Definition chan_dahdi.h:219
struct ast_namedgroups * named_pickupgroups
Named pickup groups this belongs to.
Definition chan_dahdi.h:585
struct ast_channel * owner
Definition chan_dahdi.h:127
char rdnis[AST_MAX_EXTENSION]
Redirecting Directory Number Information Service (RDNIS) number.
Definition chan_dahdi.h:551
unsigned int faxhandled
TRUE if a fax tone has already been handled.
Definition chan_dahdi.h:274
unsigned int use_smdi
TRUE if SMDI (Simplified Message Desk Interface) is enabled.
Definition chan_dahdi.h:485
struct callerid_state * cs
Definition chan_dahdi.h:126
int cid_ani2
Automatic Number Identification code from PRI.
Definition chan_dahdi.h:530
struct ast_namedgroups * named_callgroups
Named call groups this belongs to.
Definition chan_dahdi.h:580
int callwaitrings
Number of call waiting rings.
Definition chan_dahdi.h:630
unsigned int mwimonitor_neon
TRUE if the FXO port monitors for neon type MWI indications from the other end.
Definition chan_dahdi.h:422
unsigned int dialednone
TRUE if analog type line dialed no digits in Dial()
Definition chan_dahdi.h:253
unsigned int hwrxgain_enabled
TRUE if hardware Rx gain set by Asterisk.
Definition chan_dahdi.h:473
int law_default
Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW.
Definition chan_dahdi.h:560
int fake_event
Holding place for event injected from outside normal operation.
Definition chan_dahdi.h:728
unsigned int didtdd
Definition chan_dahdi.h:251
char echorest[20]
Filled with 'w'. XXX Purpose??
Definition chan_dahdi.h:642
struct dahdi_pvt * slaves[MAX_SLAVES]
Definition chan_dahdi.h:134
void * sig_pvt
Definition chan_dahdi.h:770
unsigned int ani_timeout
INTEGER, length of ANI failure timeout in ms.
Definition chan_dahdi.h:195
int dtmfcid_holdoff_state
Definition chan_dahdi.h:596
unsigned int lastnumredial
TRUE if last number redial enabled.
Definition chan_dahdi.h:448
unsigned int mwioverride_active
TRUE if a manual MWI override is active for a channel.
Definition chan_dahdi.h:439
unsigned int mwimonitor_fsk
TRUE if the FXO port monitors for fsk type MWI indications from the other end.
Definition chan_dahdi.h:427
int ringt_base
Ring timeout base.
Definition chan_dahdi.h:614
int cid_start
Definition chan_dahdi.h:595
unsigned int destroy
TRUE if the channel is to be destroyed on hangup. (Used by pseudo channels.)
Definition chan_dahdi.h:250
unsigned int restrictcid
TRUE if caller ID is restricted.
Definition chan_dahdi.h:367
char defcontext[AST_MAX_CONTEXT]
Default distinctive ring context.
Definition chan_dahdi.h:506
unsigned int priindication_oob
TRUE if PRI congestion/busy indications are sent out-of-band.
Definition chan_dahdi.h:348
unsigned int ani_info_digits
INTEGER, number of ANI INFO digits on a CAMA trunk. older switches use 1 INFO digit,...
Definition chan_dahdi.h:190
unsigned int busydetect
TRUE if busy detection is enabled. (Listens for the beep-beep busy pattern.)
Definition chan_dahdi.h:206
unsigned int hidecalleridname
TRUE if hide just the name not the number for legacy PBX use.
Definition chan_dahdi.h:308
struct timeval waitingfordt
Definition chan_dahdi.h:697
struct ast_dsp * dsp
Opaque DSP configuration structure.
Definition chan_dahdi.h:700
struct dahdi_pvt * prev
Definition chan_dahdi.h:170
ast_group_t pickupgroup
Bitmapped pickup groups this belongs to.
Definition chan_dahdi.h:575
int callingpres
Definition chan_dahdi.h:598
unsigned int reoriginate
TRUE if FXS (FXO-signalled) channel should reoriginate for user to make a new call.
Definition chan_dahdi.h:289
int buf_policy
Definition chan_dahdi.h:140
int cidpos
Position in the cidspill buffer to send out next.
Definition chan_dahdi.h:605
char context[AST_MAX_CONTEXT]
The configured context for incoming calls.
Definition chan_dahdi.h:497
unsigned int cancallforward
TRUE if support for call forwarding enabled. Dial *72 to enable call forwarding. Dial *73 to disable ...
Definition chan_dahdi.h:238
int radio
Nonzero if the signaling type is sent over a radio.
Definition chan_dahdi.h:148
char parkinglot[AST_MAX_EXTENSION]
Definition chan_dahdi.h:524
int cidcwexpire
Definition chan_dahdi.h:600
unsigned int hardwaredtmf
TRUE if DTMF detection needs to be done by hardware.
Definition chan_dahdi.h:295
int callwaitingrepeat
Definition chan_dahdi.h:599
char begindigit
DTMF digit in progress. 0 when no digit in progress.
Definition chan_dahdi.h:767
struct ast_cc_config_params * cc_params
Definition chan_dahdi.h:771
unsigned int mate
TRUE if TDD in MATE mode.
Definition chan_dahdi.h:326
float txgain
Software Tx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:162
int firstdigit_timeout
Time (ms) to detect first digit (in an analog phone)
Definition chan_dahdi.h:686
struct dahdi_echocanparams head
Definition chan_dahdi.h:633
unsigned int echocanbridged
TRUE if echo cancellation enabled when bridged.
Definition chan_dahdi.h:270
int cid_signalling
Definition chan_dahdi.h:594
char finaldial[64]
Second part of SIG_FEATDMF_TA wink operation.
Definition chan_dahdi.h:705
unsigned int transfer
TRUE if call transfer is enabled.
Definition chan_dahdi.h:386
unsigned int transfertobusy
TRUE if allowed to flash-transfer to busy channels.
Definition chan_dahdi.h:417
unsigned int inalarm
TRUE if in an alarm condition.
Definition chan_dahdi.h:324
char cid_name[AST_MAX_EXTENSION]
Caller ID name from an incoming call.
Definition chan_dahdi.h:541
ast_mutex_t lock
Definition chan_dahdi.h:125
unsigned int inservice
TRUE if channel is out of reset and ready.
Definition chan_dahdi.h:446
char language[MAX_LANGUAGE]
Language configured for calls.
Definition chan_dahdi.h:513
unsigned int digital
TRUE if the transfer capability of the call is digital.
Definition chan_dahdi.h:260
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition chan_dahdi.h:706
unsigned int mwioverride_disposition
Manual MWI disposition (on/off)
Definition chan_dahdi.h:441
struct ast_dsp_busy_pattern busy_cadence
Busy cadence pattern description.
Definition chan_dahdi.h:652
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition chan_dahdi.h:621
unsigned int pulsedial
TRUE if a pulsed digit was detected. (Pulse dial phone detected)
Definition chan_dahdi.h:360
unsigned int calledsubscriberheld
TRUE if Called Subscriber held is enabled. This allows a single incoming call to hold a DAHDI channel...
Definition chan_dahdi.h:213
int muting
TRUE if confrence is muted.
Definition chan_dahdi.h:769
char cid_tag[AST_MAX_EXTENSION]
Caller ID tag from incoming call.
Definition chan_dahdi.h:537
int matchdigit_timeout
Time (ms) to wait, in case of ambiguous match (in an analog phone)
Definition chan_dahdi.h:696
char mohsuggest[MAX_MUSICCLASS]
Suggested music-on-hold class for peer channel to use for calls.
Definition chan_dahdi.h:523
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition chan_dahdi.h:394
float rxgain
Software Rx gain set by chan_dahdi.conf.
Definition chan_dahdi.h:160
int polarity
Current line interface polarity. POLARITY_IDLE, POLARITY_REV.
Definition chan_dahdi.h:742
ast_group_t callgroup
Bitmapped call groups this belongs to.
Definition chan_dahdi.h:570
unsigned int dialing
TRUE if in the process of dialing digits or sending something.
Definition chan_dahdi.h:258
unsigned int usefaxbuffers
Definition chan_dahdi.h:276
char callwait_name[AST_MAX_EXTENSION]
Call waiting name.
Definition chan_dahdi.h:549
char mohinterpret[MAX_MUSICCLASS]
The configured music-on-hold class to use for calls.
Definition chan_dahdi.h:518
int dialtone_detect
Number of frames to watch for dialtone in incoming calls.
Definition chan_dahdi.h:675
struct ast_smdi_interface * smdi_iface
The SMDI interface to get SMDI messages from.
Definition chan_dahdi.h:488
int propconfno
Definition chan_dahdi.h:565
int inconference
Definition chan_dahdi.h:136
int cid_ton
Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise.
Definition chan_dahdi.h:539
unsigned int needanswer
Definition chan_dahdi.h:86
unsigned int needringing
Definition chan_dahdi.h:83
unsigned int linear
Definition chan_dahdi.h:90
unsigned int needhold
Definition chan_dahdi.h:88
unsigned int needunhold
Definition chan_dahdi.h:89
struct ast_frame f
Definition chan_dahdi.h:82
unsigned int inthreeway
Definition chan_dahdi.h:91
struct ast_channel * owner
Definition chan_dahdi.h:79
struct dahdi_confinfo curconf
Definition chan_dahdi.h:92
unsigned int needflash
Definition chan_dahdi.h:87
unsigned int needbusy
Definition chan_dahdi.h:84
short buffer[AST_FRIENDLY_OFFSET/2+READ_SIZE]
Definition chan_dahdi.h:81
unsigned int needcongestion
Definition chan_dahdi.h:85
int ring[3]
Definition chan_dahdi.h:63
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:314
struct dahdi_pvt * pvt
unsigned char buf[READ_SIZE]
mwisend_states mwisend_current
Definition chan_dahdi.h:112
struct timeval pause
Definition chan_dahdi.h:111
Number structure.
struct ast_channel * peer
char contextData[AST_MAX_CONTEXT]
Definition chan_dahdi.h:67
void(*const handle_dchan_exception)(struct sig_pri_span *pri, int index)
Definition sig_pri.h:202
unsigned int immediate
Definition sig_pri.h:282
struct sig_pri_span * pri
Definition sig_pri.h:355
void * chan_pvt
Definition sig_pri.h:374
enum sig_pri_reset_state resetting
Channel reset/restart state.
Definition sig_pri.h:361
unsigned int allocated
TRUE when this channel is allocated.
Definition sig_pri.h:339
unsigned int use_callingpres
Definition sig_pri.h:286
unsigned int priexclusive
Definition sig_pri.h:283
unsigned int hidecallerid
Definition sig_pri.h:280
unsigned int priindication_oob
Definition sig_pri.h:284
unsigned int hidecalleridname
Definition sig_pri.h:281
char context[AST_MAX_CONTEXT]
Definition sig_pri.h:287
unsigned int inalarm
Definition sig_pri.h:324
unsigned int no_b_channel
TRUE if this interface has no B channel. (call hold and call waiting)
Definition sig_pri.h:343
unsigned int use_callerid
Definition sig_pri.h:285
char mohinterpret[MAX_MUSICCLASS]
Definition sig_pri.h:288
q931_call * call
Definition sig_pri.h:356
struct sig_pri_chan * pvts[SIG_PRI_MAX_CHANNELS]
Definition sig_pri.h:614
struct pri * pri
Definition sig_pri.h:602
char idleext[AST_MAX_EXTENSION]
Definition sig_pri.h:550
int switchtype
Definition sig_pri.h:556
int minunused
Definition sig_pri.h:553
int fds[SIG_PRI_NUM_DCHANS]
Definition sig_pri.h:457
int trunkgroup
Definition sig_pri.h:558
pthread_t master
Definition sig_pri.h:615
int congestion_devstate
Congestion device state of the span.
Definition sig_pri.h:627
void * no_b_chan_end
Definition sig_pri.h:612
void * no_b_chan_iflist
Definition sig_pri.h:607
ast_mutex_t lock
Definition sig_pri.h:616
char idledial[AST_MAX_EXTENSION]
Definition sig_pri.h:552
void(*const lock_private)(void *pvt)
Definition sig_ss7.h:157
unsigned int immediate
Definition sig_ss7.h:221
void * chan_pvt
Definition sig_ss7.h:190
unsigned int locallyblocked
Bitmask for the channel being locally blocked.
Definition sig_ss7.h:228
unsigned int dpc
Definition sig_ss7.h:202
unsigned int use_callingpres
TRUE if we will use the calling presentation setting from the Asterisk channel for outgoing calls.
Definition sig_ss7.h:220
struct isup_call * ss7call
Opaque libss7 call control structure.
Definition sig_ss7.h:195
unsigned int remotelyblocked
Bitmask for the channel being remotely blocked.
Definition sig_ss7.h:235
unsigned int hidecallerid
TRUE if the outgoing caller ID is blocked/hidden.
Definition sig_ss7.h:213
struct ast_channel * owner
Definition sig_ss7.h:192
char context[AST_MAX_CONTEXT]
Definition sig_ss7.h:237
unsigned int inalarm
TRUE if channel is associated with a link that is down.
Definition sig_ss7.h:288
unsigned int inservice
TRUE if channel is in service.
Definition sig_ss7.h:290
int stripmsd
Number of most significant digits/characters to strip from the dialed number.
Definition sig_ss7.h:209
unsigned int use_callerid
TRUE if caller ID is used on this channel.
Definition sig_ss7.h:215
char mohinterpret[MAX_MUSICCLASS]
Definition sig_ss7.h:238
int fds[SIG_SS7_NUM_DCHANS]
Definition sig_ss7.h:323
enum sig_ss7_linkset::@148 state
pthread_t master
Definition sig_ss7.h:319
struct ss7 * ss7
Definition sig_ss7.h:321
ast_mutex_t lock
Definition sig_ss7.h:320
struct sig_ss7_chan * pvts[SIG_SS7_MAX_CHANNELS]
Definition sig_ss7.h:322
struct sla_ringing_trunk * next
Definition app_sla.c:314
const char * name
int value
Definition syslog.c:37
TTY/TDD Generation support.
#define TDD_BYTES_PER_CHAR
Definition tdd.h:27
int tdd_generate(struct tdd_state *tdd, unsigned char *buf, const char *string)
Definition tdd.c:296
struct tdd_state * tdd_new(void)
Definition tdd.c:103
void tdd_free(struct tdd_state *tdd)
Definition tdd.c:218
int ast_tdd_gen_ecdisa(unsigned char *outbuf, int len)
Definition tdd.c:148
int tdd_feed(struct tdd_state *tdd, unsigned char *ubuf, int samples)
Definition tdd.c:161
Handy terminal functions for vt* terms.
#define COLOR_MAGENTA
Definition term.h:60
#define COLOR_BLACK
Definition term.h:50
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition term.c:235
#define COLOR_GREEN
Definition term.h:54
static struct test_options options
static struct test_val b
static struct test_val a
static struct test_val c
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2315
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition time.h:235
General Asterisk channel transcoding definitions.
#define IS_DIGITAL(cap)
Definition transcap.h:45
#define AST_TRANS_CAP_DIGITAL
Definition transcap.h:36
u-Law to Signed linear conversion
#define AST_MULAW(a)
Definition ulaw.h:85
#define AST_LIN2MU(a)
Definition ulaw.h:49
FILE * out
Definition utils/frame.c:33
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ast_pthread_create(a, b, c, d)
Definition utils.h:624
#define ast_pthread_create_background(a, b, c, d)
Definition utils.h:632
#define ast_clear_flag(p, flag)
Definition utils.h:78
long int ast_random(void)
Definition utils.c:2346
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:628
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ARRAY_LEN(a)
Definition utils.h:706