[svn-commits] rmudgett: trunk r340367 - in /trunk: ./ channels/

SVN commits to the Digium repositories svn-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 svn-commits mailing list