[asterisk-commits] rmudgett: trunk r340367 - in /trunk: ./ channels/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Oct 11 16:06:59 CDT 2011
Author: rmudgett
Date: Tue Oct 11 16:06:55 2011
New Revision: 340367
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=340367
Log:
Add protection for SS7 channel allocation and better glare handling.
* Added a CLI "ss7 show channels" command that might prove useful for
future debugging.
* Made the incoming SS7 channel event check and gripe message uniform.
* Made sure that the DNID string for an incoming call is always
initialized.
(issue ASTERISK-17966)
Reported by: Kenneth Van Velthoven
Patches:
jira_asterisk_17966_v1.8_glare.patch (license #5621) patch uploaded by rmudgett
........
Merged revisions 340365 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 340366 from http://svn.asterisk.org/svn/asterisk/branches/10
Modified:
trunk/ (props changed)
trunk/channels/chan_dahdi.c
trunk/channels/sig_ss7.c
trunk/channels/sig_ss7.h
Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-10-merged' - no diff available.
Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=340367&r1=340366&r2=340367
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Tue Oct 11 16:06:55 2011
@@ -16248,9 +16248,11 @@
ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
} else {
if (!strcasecmp(a->argv[3], "on")) {
+ linksets[span - 1].ss7.debug = 1;
ss7_set_debug(linksets[span-1].ss7.ss7, SIG_SS7_DEBUG);
ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
} else {
+ linksets[span - 1].ss7.debug = 0;
ss7_set_debug(linksets[span-1].ss7.ss7, 0);
ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
}
@@ -16509,6 +16511,35 @@
#endif /* defined(HAVE_SS7) */
#if defined(HAVE_SS7)
+static char *handle_ss7_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int linkset;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ss7 show channels";
+ e->usage =
+ "Usage: ss7 show channels\n"
+ " Displays SS7 channel information at a glance.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ sig_ss7_cli_show_channels_header(a->fd);
+ for (linkset = 0; linkset < NUM_SPANS; ++linkset) {
+ if (linksets[linkset].ss7.ss7) {
+ sig_ss7_cli_show_channels(a->fd, &linksets[linkset].ss7);
+ }
+ }
+ return CLI_SUCCESS;
+}
+#endif /* defined(HAVE_SS7) */
+
+#if defined(HAVE_SS7)
static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
switch (cmd) {
@@ -16536,6 +16567,7 @@
AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
+ AST_CLI_DEFINE(handle_ss7_show_channels, "Displays SS7 channel information"),
AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
};
#endif /* defined(HAVE_SS7) */
Modified: trunk/channels/sig_ss7.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_ss7.c?view=diff&rev=340367&r1=340366&r2=340367
==============================================================================
--- trunk/channels/sig_ss7.c (original)
+++ trunk/channels/sig_ss7.c Tue Oct 11 16:06:55 2011
@@ -37,11 +37,35 @@
#include "asterisk/pbx.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
+#include "asterisk/cli.h"
#include "asterisk/transcap.h"
#include "sig_ss7.h"
/* ------------------------------------------------------------------- */
+
+static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level)
+{
+ switch (level) {
+ case SIG_SS7_CALL_LEVEL_IDLE:
+ return "Idle";
+ case SIG_SS7_CALL_LEVEL_ALLOCATED:
+ return "Allocated";
+ case SIG_SS7_CALL_LEVEL_CONTINUITY:
+ return "Continuity";
+ case SIG_SS7_CALL_LEVEL_SETUP:
+ return "Setup";
+ case SIG_SS7_CALL_LEVEL_PROCEEDING:
+ return "Proceeding";
+ case SIG_SS7_CALL_LEVEL_ALERTING:
+ return "Alerting";
+ case SIG_SS7_CALL_LEVEL_CONNECT:
+ return "Connect";
+ case SIG_SS7_CALL_LEVEL_GLARE:
+ return "Glare";
+ }
+ return "Unknown";
+}
#define SIG_SS7_DEADLOCK_AVOIDANCE(p) \
do { \
@@ -247,7 +271,7 @@
* \brief Obtain the sig_ss7 owner channel lock if the owner exists.
* \since 1.8
*
- * \param ss7 sig_ss7 SS7 control structure.
+ * \param ss7 SS7 linkset control structure.
* \param chanpos Channel position in the span.
*
* \note Assumes the ss7->lock is already obtained.
@@ -278,7 +302,7 @@
* \brief Queue the given frame onto the owner channel.
* \since 1.8
*
- * \param ss7 sig_ss7 SS7 control structure.
+ * \param ss7 SS7 linkset control structure.
* \param chanpos Channel position in the span.
* \param frame Frame to queue onto the owner channel.
*
@@ -301,7 +325,7 @@
* \brief Queue a control frame of the specified subclass onto the owner channel.
* \since 1.8
*
- * \param ss7 sig_ss7 SS7 control structure.
+ * \param ss7 SS7 linkset control structure.
* \param chanpos Channel position in the span.
* \param subclass Control frame subclass to queue onto the owner channel.
*
@@ -323,6 +347,17 @@
sig_ss7_queue_frame(ss7, chanpos, &f);
}
+/*!
+ * \internal
+ * \brief Find the channel position by CIC/DPC.
+ *
+ * \param linkset SS7 linkset control structure.
+ * \param cic Circuit Identification Code
+ * \param dpc Destination Point Code
+ *
+ * \retval chanpos on success.
+ * \retval -1 on error.
+ */
static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
{
int i;
@@ -334,6 +369,31 @@
}
}
return winner;
+}
+
+/*!
+ * \internal
+ * \brief Find the channel position by CIC/DPC and gripe if not found.
+ *
+ * \param linkset SS7 linkset control structure.
+ * \param cic Circuit Identification Code
+ * \param dpc Destination Point Code
+ * \param msg_name Message type name that failed.
+ *
+ * \retval chanpos on success.
+ * \retval -1 on error.
+ */
+static int ss7_find_cic_gripe(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, const char *msg_name)
+{
+ int chanpos;
+
+ chanpos = ss7_find_cic(linkset, cic, dpc);
+ if (chanpos < 0) {
+ ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d.\n",
+ linkset->span, msg_name, cic, dpc);
+ return -1;
+ }
+ return chanpos;
}
static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
@@ -386,6 +446,7 @@
{
int i;
+ /* XXX the use of state here seems questionable about matching up with the linkset channels */
for (i = 0; i < linkset->numchans; i++) {
if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
if (state) {
@@ -617,8 +678,6 @@
struct sig_ss7_chan *p;
int chanpos;
struct pollfd pollers[SIG_SS7_NUM_DCHANS];
- int cic;
- unsigned int dpc;
int nextms = 0;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
@@ -685,6 +744,11 @@
}
while ((e = ss7_check_event(ss7))) {
+ if (linkset->debug) {
+ ast_verbose("Linkset %d: Processing event: %s\n",
+ linkset->span, ss7_event2str(e->e));
+ }
+
switch (e->e) {
case SS7_EVENT_UP:
if (linkset->state != LINKSET_STATE_UP) {
@@ -710,9 +774,8 @@
ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
break;
case ISUP_EVENT_CPG:
- chanpos = ss7_find_cic(linkset, e->cpg.cic, e->cpg.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->cpg.cic, e->cpg.opc, "CPG");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
break;
}
p = linkset->pvts[chanpos];
@@ -753,17 +816,15 @@
break;
case ISUP_EVENT_RSC:
ast_verbose("Resetting CIC %d\n", e->rsc.cic);
- chanpos = ss7_find_cic(linkset, e->rsc.cic, e->rsc.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->rsc.cic, e->rsc.opc, "RSC");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
sig_ss7_set_inservice(p, 1);
sig_ss7_set_remotelyblocked(p, 0);
- dpc = p->dpc;
- isup_set_call_dpc(e->rsc.call, dpc);
+ isup_set_call_dpc(e->rsc.call, p->dpc);
sig_ss7_lock_owner(linkset, chanpos);
p->ss7call = NULL;
if (p->owner) {
@@ -775,9 +836,8 @@
break;
case ISUP_EVENT_GRS:
ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
- chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->grs.startcic, e->grs.opc, "GRS");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
break;
}
p = linkset->pvts[chanpos];
@@ -796,29 +856,53 @@
break;
case ISUP_EVENT_IAM:
ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
- chanpos = ss7_find_cic(linkset, e->iam.cic, e->iam.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
isup_rel(ss7, e->iam.call, -1);
break;
}
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
- if (p->owner) {
- if (p->ss7call == e->iam.call) {
- sig_ss7_unlock_private(p);
- ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
- break;
- } else {
- sig_ss7_unlock_private(p);
- ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
- break;
+ sig_ss7_lock_owner(linkset, chanpos);
+ if (p->call_level != SIG_SS7_CALL_LEVEL_IDLE) {
+ /*
+ * Detected glare/dual-seizure
+ *
+ * Always abort both calls since we can't implement the dual
+ * seizure procedures due to our channel assignment architecture
+ * and the fact that we cannot tell libss7 to discard its call
+ * structure to ignore the incoming IAM.
+ */
+ ast_debug(1,
+ "Linkset %d: SS7 IAM glare on CIC/DPC %d/%d. Dropping both calls.\n",
+ linkset->span, e->iam.cic, e->iam.opc);
+ if (p->call_level == SIG_SS7_CALL_LEVEL_ALLOCATED) {
+ /*
+ * We have not sent our IAM yet and we never will at this point.
+ */
+ p->alreadyhungup = 1;
+ isup_rel(ss7, e->iam.call, -1);
}
- }
-
- dpc = p->dpc;
+ p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
+ if (p->owner) {
+ p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ ast_channel_unlock(p->owner);
+ }
+ sig_ss7_unlock_private(p);
+ break;
+ }
+ /*
+ * The channel should not have an owner at this point since we
+ * are in the process of creating an owner for it.
+ */
+ ast_assert(!p->owner);
+
+ /* Mark channel as in use so no outgoing call will steal it. */
+ p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
p->ss7call = e->iam.call;
- isup_set_call_dpc(p->ss7call, dpc);
+
+ isup_set_call_dpc(p->ss7call, p->dpc);
if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
@@ -830,8 +914,10 @@
if (!ast_strlen_zero(e->iam.called_party_num)) {
ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset,
e->iam.called_party_num, e->iam.called_nai);
- sig_ss7_set_dnid(p, p->exten);
- }
+ } else {
+ p->exten[0] = '\0';
+ }
+ sig_ss7_set_dnid(p, p->exten);
if (p->immediate) {
p->exten[0] = 's';
@@ -874,9 +960,11 @@
if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
if (e->iam.cot_check_required) {
+ p->call_level = SIG_SS7_CALL_LEVEL_CONTINUITY;
sig_ss7_loopback(p, 1);
- } else
+ } else {
ss7_start_call(p, linkset);
+ }
} else {
ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
p->alreadyhungup = 1;
@@ -885,9 +973,8 @@
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_COT:
- chanpos = ss7_find_cic(linkset, e->cot.cic, e->cot.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->cot.cic, e->cot.opc, "COT");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
isup_rel(ss7, e->cot.call, -1);
break;
}
@@ -902,9 +989,8 @@
break;
case ISUP_EVENT_CCR:
ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
- chanpos = ss7_find_cic(linkset, e->ccr.cic, e->ccr.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->ccr.cic, e->ccr.opc, "CCR");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
break;
}
@@ -918,9 +1004,8 @@
break;
case ISUP_EVENT_CVT:
ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
- chanpos = ss7_find_cic(linkset, e->cvt.cic, e->cvt.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->cvt.cic, e->cvt.opc, "CVT");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic);
break;
}
@@ -933,9 +1018,10 @@
isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
break;
case ISUP_EVENT_REL:
- chanpos = ss7_find_cic(linkset, e->rel.cic, e->rel.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->rel.cic, e->rel.opc, "REL");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
+ /* Continue hanging up the call anyway. */
+ isup_rlc(ss7, e->rel.call);
break;
}
p = linkset->pvts[chanpos];
@@ -945,8 +1031,6 @@
p->owner->hangupcause = e->rel.cause;
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->owner);
- } else {
- ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
}
/* End the loopback if we have one */
@@ -958,12 +1042,12 @@
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_ACM:
- chanpos = ss7_find_cic(linkset, e->acm.cic, e->acm.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->acm.cic, e->acm.opc, "ACM");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
isup_rel(ss7, e->acm.call, -1);
break;
- } else {
+ }
+ {
p = linkset->pvts[chanpos];
ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
@@ -994,9 +1078,8 @@
}
break;
case ISUP_EVENT_CGB:
- chanpos = ss7_find_cic(linkset, e->cgb.startcic, e->cgb.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->cgb.startcic, e->cgb.opc, "CGB");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
break;
}
p = linkset->pvts[chanpos];
@@ -1004,9 +1087,8 @@
isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
break;
case ISUP_EVENT_CGU:
- chanpos = ss7_find_cic(linkset, e->cgu.startcic, e->cgu.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->cgu.startcic, e->cgu.opc, "CGU");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
break;
}
p = linkset->pvts[chanpos];
@@ -1014,9 +1096,8 @@
isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
break;
case ISUP_EVENT_UCIC:
- chanpos = ss7_find_cic(linkset, e->ucic.cic, e->ucic.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->ucic.cic, e->ucic.opc, "UCIC");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
break;
}
p = linkset->pvts[chanpos];
@@ -1027,9 +1108,8 @@
sig_ss7_unlock_private(p);/* doesn't require a SS7 acknowledgement */
break;
case ISUP_EVENT_BLO:
- chanpos = ss7_find_cic(linkset, e->blo.cic, e->blo.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->blo.cic, e->blo.opc, "BLO");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
break;
}
p = linkset->pvts[chanpos];
@@ -1040,9 +1120,8 @@
isup_bla(linkset->ss7, e->blo.cic, p->dpc);
break;
case ISUP_EVENT_BLA:
- chanpos = ss7_find_cic(linkset, e->bla.cic, e->bla.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->bla.cic, e->bla.opc, "BLA");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
break;
}
ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
@@ -1052,9 +1131,8 @@
sig_ss7_unlock_private(p);
break;
case ISUP_EVENT_UBL:
- chanpos = ss7_find_cic(linkset, e->ubl.cic, e->ubl.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->ubl.cic, e->ubl.opc, "UBL");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
break;
}
p = linkset->pvts[chanpos];
@@ -1065,9 +1143,8 @@
isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
break;
case ISUP_EVENT_UBA:
- chanpos = ss7_find_cic(linkset, e->uba.cic, e->uba.opc);
+ chanpos = ss7_find_cic_gripe(linkset, e->uba.cic, e->uba.opc, "UBA");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
break;
}
p = linkset->pvts[chanpos];
@@ -1078,17 +1155,21 @@
break;
case ISUP_EVENT_CON:
case ISUP_EVENT_ANM:
- if (e->e == ISUP_EVENT_CON)
- cic = e->con.cic;
- else
- cic = e->anm.cic;
-
- chanpos = ss7_find_cic(linkset, cic, (e->e == ISUP_EVENT_ANM) ? e->anm.opc : e->con.opc);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
- isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
- break;
+ if (e->e == ISUP_EVENT_CON) {
+ chanpos = ss7_find_cic_gripe(linkset, e->con.cic, e->con.opc, "CON");
+ if (chanpos < 0) {
+ isup_rel(ss7, e->con.call, -1);
+ break;
+ }
} else {
+ chanpos = ss7_find_cic_gripe(linkset, e->anm.cic, e->anm.opc, "ANM");
+ if (chanpos < 0) {
+ isup_rel(ss7, e->anm.call, -1);
+ break;
+ }
+ }
+
+ {
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
@@ -1106,30 +1187,43 @@
}
break;
case ISUP_EVENT_RLC:
- chanpos = ss7_find_cic(linkset, e->rlc.cic, e->rlc.opc);
+ /* XXX Call ptr should be passed up from libss7! */
+ chanpos = ss7_find_cic_gripe(linkset, e->rlc.cic, e->rlc.opc, "RLC");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
- break;
- } else {
+ break;
+ }
+ {
p = linkset->pvts[chanpos];
sig_ss7_lock_private(p);
- if (p->alreadyhungup)
+ if (p->alreadyhungup) {
+ if (!p->owner) {
+ p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+ }
p->ss7call = NULL;
- else
- ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL. Ignoring.\n");
+ }
sig_ss7_unlock_private(p);
}
break;
case ISUP_EVENT_FAA:
- chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
+ /*!
+ * \todo The handling of the SS7 FAA message is not good and I
+ * don't know enough to handle it correctly.
+ */
+ chanpos = ss7_find_cic_gripe(linkset, e->faa.cic, e->faa.opc, "FAA");
if (chanpos < 0) {
- ast_log(LOG_WARNING, "FAA on unconfigured CIC %d\n", e->faa.cic);
- break;
- } else {
+ isup_rel(linkset->ss7, e->faa.call, -1);
+ break;
+ }
+ {
+ /* XXX FAR and FAA used for something dealing with transfers? */
p = linkset->pvts[chanpos];
ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
sig_ss7_lock_private(p);
if (p->alreadyhungup){
+ if (!p->owner) {
+ p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+ }
+ /* XXX We seem to be leaking the isup call structure here. */
p->ss7call = NULL;
ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR. Ignoring.\n");
}
@@ -1247,6 +1341,24 @@
}
/*!
+ * \internal
+ * \brief Determine if a private channel structure is available.
+ *
+ * \param pvt Channel to determine if available.
+ *
+ * \return TRUE if the channel is available.
+ */
+static int sig_ss7_is_chan_available(struct sig_ss7_chan *pvt)
+{
+ if (!pvt->inalarm && !pvt->owner && !pvt->ss7call
+ && pvt->call_level == SIG_SS7_CALL_LEVEL_IDLE
+ && !pvt->locallyblocked && !pvt->remotelyblocked) {
+ return 1;
+ }
+ return 0;
+}
+
+/*!
* \brief Determine if the specified channel is available for an outgoing call.
* \since 1.8
*
@@ -1256,17 +1368,22 @@
*/
int sig_ss7_available(struct sig_ss7_chan *p)
{
+ int available;
+
if (!p->ss7) {
/* Something is wrong here. A SS7 channel without the ss7 pointer? */
return 0;
}
- if (!p->inalarm && !p->owner && !p->ss7call
- && !p->locallyblocked && !p->remotelyblocked) {
- return 1;
- }
-
- return 0;
+ /* Only have to deal with the linkset lock. */
+ ast_mutex_lock(&p->ss7->lock);
+ available = sig_ss7_is_chan_available(p);
+ if (available) {
+ p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
+ }
+ ast_mutex_unlock(&p->ss7->lock);
+
+ return available;
}
static unsigned char cid_pres2ss7pres(int cid_pres)
@@ -1333,6 +1450,12 @@
ss7_grab(p, p->ss7);
+ if (p->call_level != SIG_SS7_CALL_LEVEL_ALLOCATED) {
+ /* Call collision before sending IAM. Abort call. */
+ ss7_rel(p->ss7);
+ return -1;
+ }
+
p->ss7call = isup_new_call(p->ss7->ss7);
if (!p->ss7call) {
ss7_rel(p->ss7);
@@ -1447,14 +1570,14 @@
p->owner = NULL;
sig_ss7_set_dialing(p, 0);
- p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
p->outgoing = 0;
p->progress = 0;
p->rlt = 0;
p->exten[0] = '\0';
/* Perform low level hangup if no owner left */
+ ss7_grab(p, p->ss7);
+ p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
if (p->ss7call) {
- ss7_grab(p, p->ss7);
if (!p->alreadyhungup) {
const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
int icause = ast->hangupcause ? ast->hangupcause : -1;
@@ -1466,11 +1589,9 @@
}
isup_rel(p->ss7->ss7, p->ss7call, icause);
p->alreadyhungup = 1;
- } else {
- ast_log(LOG_WARNING, "Trying to hangup twice!\n");
- }
- ss7_rel(p->ss7);
- }
+ }
+ }
+ ss7_rel(p->ss7);
return res;
}
@@ -1537,17 +1658,19 @@
res = sig_ss7_play_tone(p, SIG_SS7_TONE_BUSY);
break;
case AST_CONTROL_RINGING:
+ ss7_grab(p, p->ss7);
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
- if (p->ss7 && p->ss7->ss7) {
- ss7_grab(p, p->ss7);
- if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
- p->rlt = 1;
- if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */
- isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
- ss7_rel(p->ss7);
+ if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
+ p->rlt = 1;
}
- }
+
+ /* No need to send CPG if call will be RELEASE */
+ if (p->rlt != 1) {
+ isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
+ }
+ }
+ ss7_rel(p->ss7);
res = sig_ss7_play_tone(p, SIG_SS7_TONE_RINGTONE);
@@ -1557,37 +1680,34 @@
break;
case AST_CONTROL_PROCEEDING:
ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
+ ss7_grab(p, p->ss7);
/* This IF sends the FAR for an answered ALEG call */
if (chan->_state == AST_STATE_UP && (p->rlt != 1)){
- ss7_grab(p, p->ss7);
if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
p->rlt = 1;
}
- ss7_rel(p->ss7);
}
if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && !p->outgoing) {
p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
- if (p->ss7 && p->ss7->ss7) {
- ss7_grab(p, p->ss7);
- isup_acm(p->ss7->ss7, p->ss7call);
- ss7_rel(p->ss7);
- }
- }
+ isup_acm(p->ss7->ss7, p->ss7call);
+ }
+ ss7_rel(p->ss7);
/* don't continue in ast_indicate */
res = 0;
break;
case AST_CONTROL_PROGRESS:
ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
+ ss7_grab(p, p->ss7);
if (!p->progress && p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
p->progress = 1;/* No need to send inband-information progress again. */
- if (p->ss7 && p->ss7->ss7) {
- ss7_grab(p, p->ss7);
- isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
- ss7_rel(p->ss7);
- /* enable echo canceler here on SS7 calls */
- sig_ss7_set_echocanceller(p, 1);
- }
+ isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
+ ss7_rel(p->ss7);
+
+ /* enable echo canceler here on SS7 calls */
+ sig_ss7_set_echocanceller(p, 1);
+ } else {
+ ss7_rel(p->ss7);
}
/* don't continue in ast_indicate */
res = 0;
@@ -1639,6 +1759,11 @@
ast = sig_ss7_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
if (!ast) {
p->outgoing = 0;
+
+ /* Release the allocated channel. Only have to deal with the linkset lock. */
+ ast_mutex_lock(&p->ss7->lock);
+ p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
+ ast_mutex_unlock(&p->ss7->lock);
}
return ast;
}
@@ -1654,6 +1779,51 @@
void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
{
ast_free(doomed);
+}
+
+#define SIG_SS7_SC_HEADER "%-4s %4s %-4s %-3s %-3s %-10s %-4s %s\n"
+#define SIG_SS7_SC_LINE "%4d %4d %-4s %-3s %-3s %-10s %-4s %s"
+void sig_ss7_cli_show_channels_header(int fd)
+{
+ ast_cli(fd, SIG_SS7_SC_HEADER, "link", "", "Chan", "Lcl", "Rem", "Call", "SS7", "Channel");
+ ast_cli(fd, SIG_SS7_SC_HEADER, "set", "Chan", "Idle", "Blk", "Blk", "Level", "Call", "Name");
+}
+
+void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset)
+{
+ char line[256];
+ int idx;
+ struct sig_ss7_chan *pvt;
+
+ ast_mutex_lock(&linkset->lock);
+ for (idx = 0; idx < linkset->numchans; ++idx) {
+ if (!linkset->pvts[idx]) {
+ continue;
+ }
+ pvt = linkset->pvts[idx];
+ sig_ss7_lock_private(pvt);
+ sig_ss7_lock_owner(linkset, idx);
+
+ snprintf(line, sizeof(line), SIG_SS7_SC_LINE,
+ linkset->span,
+ pvt->channel,
+ sig_ss7_is_chan_available(pvt) ? "Yes" : "No",
+ pvt->locallyblocked ? "Yes" : "No",
+ pvt->remotelyblocked ? "Yes" : "No",
+ sig_ss7_call_level2str(pvt->call_level),
+ pvt->ss7call ? "Yes" : "No",
+ pvt->owner ? pvt->owner->name : "");
+
+ if (pvt->owner) {
+ ast_channel_unlock(pvt->owner);
+ }
+ sig_ss7_unlock_private(pvt);
+
+ ast_mutex_unlock(&linkset->lock);
+ ast_cli(fd, "%s\n", line);
+ ast_mutex_lock(&linkset->lock);
+ }
+ ast_mutex_unlock(&linkset->lock);
}
/*!
@@ -1687,7 +1857,7 @@
* \brief Initialize the SS7 linkset control.
* \since 1.8
*
- * \param ss7 sig_ss7 SS7 control structure.
+ * \param ss7 SS7 linkset control structure.
*
* \return Nothing
*/
Modified: trunk/channels/sig_ss7.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_ss7.h?view=diff&rev=340367&r1=340366&r2=340367
==============================================================================
--- trunk/channels/sig_ss7.h (original)
+++ trunk/channels/sig_ss7.h Tue Oct 11 16:06:55 2011
@@ -88,14 +88,38 @@
enum sig_ss7_call_level {
/*! Call does not exist. */
SIG_SS7_CALL_LEVEL_IDLE,
- /*! Call is present but has no response yet. (SETUP) */
+ /*!
+ * Call is allocated to the channel.
+ * We have not sent or responded to IAM yet.
+ */
+ SIG_SS7_CALL_LEVEL_ALLOCATED,
+ /*!
+ * Call is performing continuity check after receiving IAM.
+ * We are waiting for COT to proceed further.
+ */
+ SIG_SS7_CALL_LEVEL_CONTINUITY,
+ /*!
+ * Call is present.
+ * We have not seen a response or sent further call progress to an IAM yet.
+ */
SIG_SS7_CALL_LEVEL_SETUP,
- /*! Call routing is happening. (PROCEEDING) */
+ /*!
+ * Call routing is happening.
+ * We have sent or received ACM.
+ */
SIG_SS7_CALL_LEVEL_PROCEEDING,
- /*! Called party is being alerted of the call. (ALERTING) */
+ /*!
+ * Called party is being alerted of the call.
+ * We have sent or received CPG(ALERTING)/ACM(ALERTING).
+ */
SIG_SS7_CALL_LEVEL_ALERTING,
- /*! Call is connected/answered. (CONNECT) */
+ /*!
+ * Call is connected/answered.
+ * We have sent or received CON/ANM.
+ */
SIG_SS7_CALL_LEVEL_CONNECT,
+ /*! Call has collided with incoming call. */
+ SIG_SS7_CALL_LEVEL_GLARE,
};
struct sig_ss7_linkset;
@@ -232,6 +256,7 @@
int linkstate[SIG_SS7_NUM_DCHANS];
int numchans;
int span; /*!< span number put into user output messages */
+ int debug; /*!< set to true if to dump SS7 event info */
enum {
LINKSET_STATE_DOWN = 0,
LINKSET_STATE_UP
@@ -267,6 +292,9 @@
struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_callback *callback, struct sig_ss7_linkset *ss7);
void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7);
+void sig_ss7_cli_show_channels_header(int fd);
+void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset);
+
/* ------------------------------------------------------------------- */
More information about the asterisk-commits
mailing list