Newer
Older
* \since 1.8
*
* \param p Channel private control structure.
*
* \return Nothing
*/
static void sig_pri_open_media(struct sig_pri_chan *p)
{
if (p->no_b_channel) {
return;
}
if (sig_pri_callbacks.open_media) {
sig_pri_callbacks.open_media(p->chan_pvt);
/*!
* \internal
* \brief Post an AMI B channel association event.
* \since 1.8
*
* \param p Channel private control structure.
*
* \note Assumes the private and owner are locked.
*
* \return Nothing
*/
static void sig_pri_ami_channel_event(struct sig_pri_chan *p)
{
if (sig_pri_callbacks.ami_channel_event) {
sig_pri_callbacks.ami_channel_event(p->chan_pvt, p->owner);
struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability)
struct ast_channel *ast;
ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
sig_pri_set_outgoing(p, 1);
ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
sig_pri_set_outgoing(p, 0);
int pri_is_up(struct sig_pri_span *pri)
{
int x;
Richard Mudgett
committed
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if (pri->dchanavail[x] == DCHAN_AVAILABLE)
return 1;
}
return 0;
}
static const char *pri_order(int level)
{
switch (level) {
case 0:
return "Primary";
case 1:
return "Secondary";
case 2:
return "Tertiary";
case 3:
return "Quaternary";
default:
return "<Unknown>";
}
/* Returns index of the active dchan */
static int pri_active_dchan_index(struct sig_pri_span *pri)
Richard Mudgett
committed
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if ((pri->dchans[x] == pri->pri))
ast_log(LOG_WARNING, "No active dchan found!\n");
return -1;
static void pri_find_dchan(struct sig_pri_span *pri)
{
struct pri *old;
int oldslot = -1;
int newslot = -1;
int idx;
old = pri->pri;
for (idx = 0; idx < SIG_PRI_NUM_DCHANS; ++idx) {
if (!pri->dchans[idx]) {
/* No more D channels defined on the span. */
break;
}
if (pri->dchans[idx] == old) {
oldslot = idx;
}
if (newslot < 0 && pri->dchanavail[idx] == DCHAN_AVAILABLE) {
newslot = idx;
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
/* At this point, idx is a count of how many D-channels are defined on the span. */
if (1 < idx) {
/* We have several D-channels defined on the span. (NFAS PRI setup) */
if (newslot < 0) {
/* No D-channels available. Default to the primary D-channel. */
newslot = 0;
if (!pri->no_d_channels) {
pri->no_d_channels = 1;
if (old && oldslot != newslot) {
ast_log(LOG_WARNING,
"Span %d: No D-channels up! Switching selected D-channel from %s to %s.\n",
pri->span, pri_order(oldslot), pri_order(newslot));
} else {
ast_log(LOG_WARNING, "Span %d: No D-channels up!\n", pri->span);
}
}
} else {
pri->no_d_channels = 0;
}
if (old && oldslot != newslot) {
ast_log(LOG_NOTICE,
"Switching selected D-channel from %s (fd %d) to %s (fd %d)!\n",
pri_order(oldslot), pri->fds[oldslot],
pri_order(newslot), pri->fds[newslot]);
if (newslot < 0) {
/* The only D-channel is not up. */
newslot = 0;
if (!pri->no_d_channels) {
pri->no_d_channels = 1;
/*
* This is annoying to see on non-persistent layer 2
* connections. Let's not complain in that case.
*/
if (pri->sig != SIG_BRI_PTMP) {
ast_log(LOG_WARNING, "Span %d: D-channel is down!\n", pri->span);
}
}
} else {
pri->no_d_channels = 0;
}
}
pri->pri = pri->dchans[newslot];
}
/*!
* \internal
* \brief Determine if a private channel structure is in use.
* \since 1.8
*
* \param pvt Channel to determine if in use.
*
* \return TRUE if the channel is in use.
*/
static int sig_pri_is_chan_in_use(struct sig_pri_chan *pvt)
{
return pvt->owner || pvt->call || pvt->allocated || pvt->inalarm
|| pvt->resetting != SIG_PRI_RESET_IDLE;
}
/*!
* \brief Determine if a private channel structure is available.
* \since 1.8
*
* \param pvt Channel to determine if available.
*
* \return TRUE if the channel is available.
*/
int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
{
return !sig_pri_is_chan_in_use(pvt)
#if defined(HAVE_PRI_SERVICE_MESSAGES)
/* And not out-of-service */
&& !pvt->service_status
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
;
}
/*!
* \internal
* \brief Obtain the sig_pri owner channel lock if the owner exists.
* \since 1.8
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void sig_pri_lock_owner(struct sig_pri_span *pri, int chanpos)
{
for (;;) {
if (!pri->pvts[chanpos]->owner) {
/* There is no owner lock to get. */
}
if (!ast_channel_trylock(pri->pvts[chanpos]->owner)) {
/* We got the lock */
break;
}
Richard Mudgett
committed
/* Avoid deadlock */
sig_pri_unlock_private(pri->pvts[chanpos]);
DEADLOCK_AVOIDANCE(&pri->lock);
sig_pri_lock_private(pri->pvts[chanpos]);
/*!
* \internal
* \brief Queue the given frame onto the owner channel.
* \since 1.8
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param frame Frame to queue onto the owner channel.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void pri_queue_frame(struct sig_pri_span *pri, int chanpos, struct ast_frame *frame)
{
sig_pri_lock_owner(pri, chanpos);
if (pri->pvts[chanpos]->owner) {
ast_queue_frame(pri->pvts[chanpos]->owner, frame);
ast_channel_unlock(pri->pvts[chanpos]->owner);
}
}
/*!
* \internal
* \brief Queue a control frame of the specified subclass onto the owner channel.
* \since 1.8
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param subclass Control frame subclass to queue onto the owner channel.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
{
struct ast_frame f = {AST_FRAME_CONTROL, };
struct sig_pri_chan *p = pri->pvts[chanpos];
if (sig_pri_callbacks.queue_control) {
sig_pri_callbacks.queue_control(p->chan_pvt, subclass);
}
f.subclass.integer = subclass;
/*!
* \internal
* \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
* \since 11
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param cause String describing the cause to be placed into the frame.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void pri_queue_pvt_cause_data(struct sig_pri_span *pri, int chanpos, const char *cause, int ast_cause)
{
struct ast_channel *chan;
struct ast_control_pvt_cause_code *cause_code;
sig_pri_lock_owner(pri, chanpos);
chan = pri->pvts[chanpos]->owner;
if (chan) {
int datalen = sizeof(*cause_code) + strlen(cause);
cause_code = ast_alloca(datalen);
ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
ast_copy_string(cause_code->code, cause, datalen + 1 - sizeof(*cause_code));
ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
ast_channel_hangupcause_hash_set(chan, cause_code, datalen);
ast_channel_unlock(chan);
}
}
Richard Mudgett
committed
/*!
* \internal
* \brief Find the channel associated with the libpri call.
Richard Mudgett
committed
*
* \param pri PRI span control structure.
Richard Mudgett
committed
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
* \param call LibPRI opaque call pointer to find.
*
* \note Assumes the pri->lock is already obtained.
*
* \retval array-index into private pointer array on success.
* \retval -1 on error.
*/
static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
{
int idx;
if (!call) {
/* Cannot find a call without a call. */
return -1;
}
for (idx = 0; idx < pri->numchans; ++idx) {
if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
/* Found the principle */
return idx;
}
}
return -1;
}
/*!
* \internal
* \brief Kill the call.
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
*
* \param pri PRI span control structure.
* \param call LibPRI opaque call pointer to find.
* \param cause Reason call was killed.
*
* \note Assumes the pvt->pri->lock is already obtained.
*
* \return Nothing
*/
static void sig_pri_kill_call(struct sig_pri_span *pri, q931_call *call, int cause)
{
int chanpos;
chanpos = pri_find_principle_by_call(pri, call);
if (chanpos < 0) {
pri_hangup(pri->pri, call, cause);
return;
}
sig_pri_lock_private(pri->pvts[chanpos]);
if (!pri->pvts[chanpos]->owner) {
pri_hangup(pri->pri, call, cause);
pri->pvts[chanpos]->call = NULL;
sig_pri_unlock_private(pri->pvts[chanpos]);
sig_pri_span_devstate_changed(pri);
return;
}
ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, cause);
pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
sig_pri_unlock_private(pri->pvts[chanpos]);
}
/*!
* \internal
* \brief Find the private structure for the libpri call.
*
* \param pri PRI span control structure.
* \param channel LibPRI encoded channel ID.
* \param call LibPRI opaque call pointer.
*
* \note Assumes the pri->lock is already obtained.
*
* \retval array-index into private pointer array on success.
* \retval -1 on error.
*/
static int pri_find_principle(struct sig_pri_span *pri, int channel, q931_call *call)
{
int x;
Richard Mudgett
committed
int span;
int principle;
Richard Mudgett
committed
if (channel < 0) {
/* Channel is not picked yet. */
return -1;
}
prioffset = PRI_CHANNEL(channel);
if (!prioffset || (channel & PRI_HELD_CALL)) {
Richard Mudgett
committed
/* Find the call waiting call or held call. */
return pri_find_principle_by_call(pri, call);
Richard Mudgett
committed
}
Richard Mudgett
committed
span = PRI_SPAN(channel);
if (!(channel & PRI_EXPLICIT)) {
int index;
index = pri_active_dchan_index(pri);
if (index == -1) {
return -1;
Richard Mudgett
committed
}
span = pri->dchan_logical_span[index];
}
Richard Mudgett
committed
principle = -1;
for (x = 0; x < pri->numchans; x++) {
Richard Mudgett
committed
if (pri->pvts[x]
&& pri->pvts[x]->prioffset == prioffset
Richard Mudgett
committed
&& pri->pvts[x]->logicalspan == span
&& !pri->pvts[x]->no_b_channel) {
principle = x;
break;
}
}
return principle;
}
/*!
* \internal
* \brief Fixup the private structure associated with the libpri call.
*
* \param pri PRI span control structure.
* \param principle Array-index into private array to move call to if not already there.
* \param call LibPRI opaque call pointer to find if need to move call.
*
* \note Assumes the pri->lock is already obtained.
*
* \retval principle on success.
* \retval -1 on error.
*/
static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_call *call)
{
int x;
Richard Mudgett
committed
if (principle < 0 || pri->numchans <= principle) {
/* Out of rannge */
return -1;
}
if (!call) {
/* No call */
return principle;
}
Richard Mudgett
committed
if (pri->pvts[principle] && pri->pvts[principle]->call == call) {
/* Call is already on the specified principle. */
return principle;
Richard Mudgett
committed
}
/* Find the old principle location. */
for (x = 0; x < pri->numchans; x++) {
Richard Mudgett
committed
struct sig_pri_chan *new_chan;
struct sig_pri_chan *old_chan;
if (!pri->pvts[x] || pri->pvts[x]->call != call) {
continue;
Richard Mudgett
committed
}
Richard Mudgett
committed
/* Found our call */
new_chan = pri->pvts[principle];
old_chan = pri->pvts[x];
/* Get locks to safely move to the new private structure. */
sig_pri_lock_private(old_chan);
sig_pri_lock_owner(pri, x);
sig_pri_lock_private(new_chan);
ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
old_chan->owner ? ast_channel_name(old_chan->owner) : "",
Richard Mudgett
committed
old_chan->channel, new_chan->channel);
if (!sig_pri_is_chan_available(new_chan)) {
Richard Mudgett
committed
ast_log(LOG_WARNING,
"Can't move call (%s) from channel %d to %d. It is already in use.\n",
old_chan->owner ? ast_channel_name(old_chan->owner) : "",
old_chan->channel, new_chan->channel);
sig_pri_unlock_private(new_chan);
if (old_chan->owner) {
ast_channel_unlock(old_chan->owner);
}
sig_pri_unlock_private(old_chan);
Richard Mudgett
committed
return -1;
}
Richard Mudgett
committed
sig_pri_fixup_chans(old_chan, new_chan);
/* Fix it all up now */
new_chan->owner = old_chan->owner;
old_chan->owner = NULL;
new_chan->call = old_chan->call;
old_chan->call = NULL;
/* Transfer flags from the old channel. */
#if defined(HAVE_PRI_AOC_EVENTS)
new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
new_chan->holding_aoce = old_chan->holding_aoce;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
Richard Mudgett
committed
new_chan->alreadyhungup = old_chan->alreadyhungup;
new_chan->isidlecall = old_chan->isidlecall;
new_chan->progress = old_chan->progress;
new_chan->allocated = old_chan->allocated;
Richard Mudgett
committed
new_chan->outgoing = old_chan->outgoing;
new_chan->digital = old_chan->digital;
#if defined(HAVE_PRI_CALL_WAITING)
new_chan->is_call_waiting = old_chan->is_call_waiting;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
old_chan->aoc_s_request_invoke_id_valid = 0;
old_chan->waiting_for_aoce = 0;
Richard Mudgett
committed
old_chan->alreadyhungup = 0;
old_chan->isidlecall = 0;
old_chan->progress = 0;
Richard Mudgett
committed
old_chan->outgoing = 0;
old_chan->digital = 0;
#if defined(HAVE_PRI_CALL_WAITING)
old_chan->is_call_waiting = 0;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
Richard Mudgett
committed
/* More stuff to transfer to the new channel. */
new_chan->call_level = old_chan->call_level;
old_chan->call_level = SIG_PRI_CALL_LEVEL_IDLE;
Richard Mudgett
committed
#if defined(HAVE_PRI_REVERSE_CHARGE)
new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
#endif /* defined(HAVE_PRI_REVERSE_CHARGE) */
#if defined(HAVE_PRI_SETUP_KEYPAD)
strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
strcpy(new_chan->deferred_digits, old_chan->deferred_digits);
Richard Mudgett
committed
strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
new_chan->moh_state = old_chan->moh_state;
old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
#if defined(HAVE_PRI_AOC_EVENTS)
new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
new_chan->aoc_e = old_chan->aoc_e;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
strcpy(new_chan->user_tag, old_chan->user_tag);
Richard Mudgett
committed
if (new_chan->no_b_channel) {
/* Copy the real channel configuration to the no B channel interface. */
new_chan->hidecallerid = old_chan->hidecallerid;
new_chan->hidecalleridname = old_chan->hidecalleridname;
new_chan->immediate = old_chan->immediate;
new_chan->priexclusive = old_chan->priexclusive;
new_chan->priindication_oob = old_chan->priindication_oob;
new_chan->use_callerid = old_chan->use_callerid;
new_chan->use_callingpres = old_chan->use_callingpres;
new_chan->stripmsd = old_chan->stripmsd;
strcpy(new_chan->context, old_chan->context);
strcpy(new_chan->mohinterpret, old_chan->mohinterpret);
/* Become a member of the old channel span/trunk-group. */
new_chan->logicalspan = old_chan->logicalspan;
new_chan->mastertrunkgroup = old_chan->mastertrunkgroup;
} else if (old_chan->no_b_channel) {
/*
* We are transitioning from a held/call-waiting channel to a
* real channel so we need to make sure that the media path is
* open. (Needed especially if the channel is natively
* bridged.)
*/
sig_pri_open_media(new_chan);
}
if (new_chan->owner) {
sig_pri_ami_channel_event(new_chan);
}
sig_pri_unlock_private(old_chan);
if (new_chan->owner) {
ast_channel_unlock(new_chan->owner);
sig_pri_unlock_private(new_chan);
Richard Mudgett
committed
return principle;
ast_verb(3, "Call specified, but not found.\n");
return -1;
}
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
/*!
* \internal
* \brief Find and fixup the private structure associated with the libpri call.
*
* \param pri PRI span control structure.
* \param channel LibPRI encoded channel ID.
* \param call LibPRI opaque call pointer.
*
* \details
* This is a combination of pri_find_principle() and pri_fixup_principle()
* to reduce code redundancy and to make handling several PRI_EVENT_xxx's
* consistent for the current architecture.
*
* \note Assumes the pri->lock is already obtained.
*
* \retval array-index into private pointer array on success.
* \retval -1 on error.
*/
static int pri_find_fixup_principle(struct sig_pri_span *pri, int channel, q931_call *call)
{
int chanpos;
chanpos = pri_find_principle(pri, channel, call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is unconfigured.\n",
pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
sig_pri_kill_call(pri, call, PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST);
return -1;
}
chanpos = pri_fixup_principle(pri, chanpos, call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is not available.\n",
pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
/*
* Using Q.931 section 5.2.3.1 b) as the reason for picking
* PRI_CAUSE_CHANNEL_UNACCEPTABLE. Receiving a
* PRI_CAUSE_REQUESTED_CHAN_UNAVAIL would cause us to restart
* that channel (which is not specified by Q.931) and kill some
* other call which would be bad.
*/
sig_pri_kill_call(pri, call, PRI_CAUSE_CHANNEL_UNACCEPTABLE);
return -1;
}
return chanpos;
}
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
static char * redirectingreason2str(int redirectingreason)
{
switch (redirectingreason) {
case 0:
return "UNKNOWN";
case 1:
return "BUSY";
case 2:
return "NO_REPLY";
case 0xF:
return "UNCONDITIONAL";
default:
return "NOREDIRECT";
}
}
static char *dialplan2str(int dialplan)
{
if (dialplan == -1) {
return("Dynamically set dialplan in ISDN");
}
return (pri_plan2str(dialplan));
}
/*!
* \internal
* \brief Apply numbering plan prefix to the given number.
*
* \param buf Buffer to put number into.
* \param size Size of given buffer.
* \param pri PRI span control structure.
* \param number Number to apply numbering plan.
* \param plan Numbering plan to apply.
*
* \return Nothing
*/
static void apply_plan_to_number(char *buf, size_t size, const struct sig_pri_span *pri, const char *number, int plan)
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
{
switch (plan) {
case PRI_INTERNATIONAL_ISDN: /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
snprintf(buf, size, "%s%s", pri->internationalprefix, number);
break;
case PRI_NATIONAL_ISDN: /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
snprintf(buf, size, "%s%s", pri->nationalprefix, number);
break;
case PRI_LOCAL_ISDN: /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
snprintf(buf, size, "%s%s", pri->localprefix, number);
break;
case PRI_PRIVATE: /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
snprintf(buf, size, "%s%s", pri->privateprefix, number);
break;
case PRI_UNKNOWN: /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
snprintf(buf, size, "%s%s", pri->unknownprefix, number);
break;
default: /* other Q.931 dialplan => don't twiddle with callingnum */
snprintf(buf, size, "%s", number);
break;
}
}
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
/*!
* \internal
* \brief Apply numbering plan prefix to the given number if the number exists.
*
* \param buf Buffer to put number into.
* \param size Size of given buffer.
* \param pri PRI span control structure.
* \param number Number to apply numbering plan.
* \param plan Numbering plan to apply.
*
* \return Nothing
*/
static void apply_plan_to_existing_number(char *buf, size_t size, const struct sig_pri_span *pri, const char *number, int plan)
{
/* Make sure a number exists so the prefix isn't placed on an empty string. */
if (ast_strlen_zero(number)) {
if (size) {
*buf = '\0';
}
return;
}
apply_plan_to_number(buf, size, pri, number, plan);
}
/*!
* \internal
* \brief Restart the next channel we think is idle on the span.
*
* \param pri PRI span control structure.
*
* \note Assumes the pri->lock is already obtained.
*
* \return Nothing
*/
static void pri_check_restart(struct sig_pri_span *pri)
#if defined(HAVE_PRI_SERVICE_MESSAGES)
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
if (!pri->pvts[pri->resetpos]
Richard Mudgett
committed
|| pri->pvts[pri->resetpos]->no_b_channel
|| sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
continue;
}
#if defined(HAVE_PRI_SERVICE_MESSAGES)
why = pri->pvts[pri->resetpos]->service_status;
if (why) {
ast_log(LOG_NOTICE,
"Span %d: channel %d out-of-service (reason: %s), not sending RESTART\n",
pri->span, pri->pvts[pri->resetpos]->channel,
(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
continue;
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
break;
}
if (pri->resetpos < pri->numchans) {
/* Mark the channel as resetting and restart it */
pri->pvts[pri->resetpos]->resetting = SIG_PRI_RESET_ACTIVE;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
} else {
pri->resetting = 0;
time(&pri->lastreset);
sig_pri_span_devstate_changed(pri);
}
}
#if defined(HAVE_PRI_CALL_WAITING)
/*!
* \internal
* \brief Init the private channel configuration using the span controller.
* \since 1.8
*
* \param pvt Channel to init the configuration.
* \param pri PRI span control structure.
*
* \note Assumes the pri->lock is already obtained.
*
* \return Nothing
*/
static void sig_pri_init_config(struct sig_pri_chan *pvt, struct sig_pri_span *pri)
{
pvt->stripmsd = pri->ch_cfg.stripmsd;
pvt->hidecallerid = pri->ch_cfg.hidecallerid;
pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
pvt->immediate = pri->ch_cfg.immediate;
pvt->priexclusive = pri->ch_cfg.priexclusive;
pvt->priindication_oob = pri->ch_cfg.priindication_oob;
pvt->use_callerid = pri->ch_cfg.use_callerid;
pvt->use_callingpres = pri->ch_cfg.use_callingpres;
ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
if (sig_pri_callbacks.init_config) {
sig_pri_callbacks.init_config(pvt->chan_pvt, pri);
}
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
/*!
* \internal
* \brief Find an empty B-channel interface to use.
*
* \param pri PRI span control structure.
* \param backwards TRUE if the search starts from higher channels.
*
* \note Assumes the pri->lock is already obtained.
*
* \retval array-index into private pointer array on success.
* \retval -1 on error.
*/
static int pri_find_empty_chan(struct sig_pri_span *pri, int backwards)
{
int x;
if (backwards)
x = pri->numchans;
else
x = 0;
for (;;) {
if (backwards && (x < 0))
break;
if (!backwards && (x >= pri->numchans))
break;
Richard Mudgett
committed
if (pri->pvts[x]
&& !pri->pvts[x]->no_b_channel
&& sig_pri_is_chan_available(pri->pvts[x])) {
ast_debug(1, "Found empty available channel %d/%d\n",
pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
return x;
}
if (backwards)
x--;
else
x++;
}
return -1;
}
Richard Mudgett
committed
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief Find or create an empty no-B-channel interface to use.
Kevin P. Fleming
committed
* \since 1.8
Richard Mudgett
committed
*
* \param pri PRI span control structure.
Richard Mudgett
committed
*
* \note Assumes the pri->lock is already obtained.
*
* \retval array-index into private pointer array on success.
* \retval -1 on error.
*/
static int pri_find_empty_nobch(struct sig_pri_span *pri)
Richard Mudgett
committed
{
int idx;
for (idx = 0; idx < pri->numchans; ++idx) {
if (pri->pvts[idx]
&& pri->pvts[idx]->no_b_channel
&& sig_pri_is_chan_available(pri->pvts[idx])) {
Richard Mudgett
committed
ast_debug(1, "Found empty available no B channel interface\n");
return idx;
}
}
/* Need to create a new interface. */
if (sig_pri_callbacks.new_nobch_intf) {
idx = sig_pri_callbacks.new_nobch_intf(pri);
Richard Mudgett
committed
} else {
idx = -1;
}
return idx;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
static void *do_idle_thread(void *v_pvt)
struct sig_pri_chan *pvt = v_pvt;
struct ast_channel *chan = pvt->owner;
struct ast_frame *f;
char ex[80];
/* Wait up to 30 seconds for an answer */
int timeout_ms = 30000;
int ms;
struct timeval start;
struct ast_callid *callid;
if ((callid = ast_channel_callid(chan))) {
ast_callid_threadassoc_add(callid);
callid = ast_callid_unref(callid);
}
ast_verb(3, "Initiating idle call on channel %s\n", ast_channel_name(chan));
snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
if (ast_call(chan, ex, 0)) {
ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", ast_channel_name(chan), ex);
ast_hangup(chan);
return NULL;
}
start = ast_tvnow();
while ((ms = ast_remaining_ms(start, timeout_ms))) {
if (ast_waitfor(chan, ms) <= 0) {
break;
}
f = ast_read(chan);
if (!f) {
/* Got hangup */
break;
}
if (f->frametype == AST_FRAME_CONTROL) {
switch (f->subclass.integer) {
case AST_CONTROL_ANSWER:
/* Launch the PBX */
ast_channel_exten_set(chan, pvt->pri->idleext);
ast_channel_context_set(chan, pvt->pri->idlecontext);
ast_channel_priority_set(chan, 1);
ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", ast_channel_name(chan), ast_channel_exten(chan), ast_channel_context(chan));
ast_pbx_run(chan);
/* It's already hungup, return immediately */
return NULL;
case AST_CONTROL_BUSY:
ast_verb(4, "Idle channel '%s' busy, waiting...\n", ast_channel_name(chan));
break;
case AST_CONTROL_CONGESTION:
ast_verb(4, "Idle channel '%s' congested, waiting...\n", ast_channel_name(chan));
break;
};
}
ast_frfree(f);
}
/* Hangup the channel since nothing happend */
ast_hangup(chan);
return NULL;
}
static void *pri_ss_thread(void *data)
{
struct sig_pri_chan *p = data;
struct ast_channel *chan = p->owner;
char exten[AST_MAX_EXTENSION];
int res;
int len;
int timeout;
if (!chan) {
/* We lost the owner before we could get started. */
return NULL;
}
if ((callid = ast_channel_callid(chan))) {
ast_callid_threadassoc_add(callid);
ast_callid_unref(callid);
}
/*
* In the bizarre case where the channel has become a zombie before we
* even get started here, abort safely.
*/
if (!ast_channel_tech_pvt(chan)) {
ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", ast_channel_name(chan));
ast_hangup(chan);
return NULL;
}
ast_verb(3, "Starting simple switch on '%s'\n", ast_channel_name(chan));
sig_pri_dsp_reset_and_flush_digits(p);
/* Now loop looking for an extension */
ast_copy_string(exten, p->exten, sizeof(exten));
len = strlen(exten);
res = 0;
while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
if (len && !ast_ignore_pattern(ast_channel_context(chan), exten))
sig_pri_play_tone(p, -1);
else
sig_pri_play_tone(p, SIG_PRI_TONE_DIALTONE);
if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num))
timeout = pri_matchdigittimeout;
else
timeout = pri_gendigittimeout;
res = ast_waitfordigit(chan, timeout);
if (res < 0) {
ast_debug(1, "waitfordigit returned < 0...\n");
ast_hangup(chan);
return NULL;
} else if (res) {
exten[len++] = res;
exten[len] = '\0';
} else
break;
}
/* if no extension was received ('unspecified') on overlap call, use the 's' extension */
if (ast_strlen_zero(exten)) {
ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
exten[0] = 's';
exten[1] = '\0';