[asterisk-commits] rmudgett: trunk r312579 - in /trunk: ./ channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 4 11:18:08 CDT 2011


Author: rmudgett
Date: Mon Apr  4 11:17:58 2011
New Revision: 312579

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=312579
Log:
Merged revisions 312575 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r312575 | rmudgett | 2011-04-04 11:10:50 -0500 (Mon, 04 Apr 2011) | 52 lines
  
  Merged revisions 312574 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2
  
  ................
    r312574 | rmudgett | 2011-04-04 11:00:02 -0500 (Mon, 04 Apr 2011) | 45 lines
    
    Merged revisions 312573 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r312573 | rmudgett | 2011-04-04 10:49:30 -0500 (Mon, 04 Apr 2011) | 38 lines
      
      Issues with ISDN calls changing B channels during call negotiations.
      
      The handling of the PROCEEDING message was not using the correct call
      structure if the B channel was changed.  (The same for PROGRESS.) The call
      was also not hungup if the new B channel is not provisioned or is busy.
      
      * Made all call connection messages (SETUP_ACKNOWLEDGE, PROCEEDING,
      PROGRESS, ALERTING, CONNECT, CONNECT_ACKNOWLEDGE) ensure that they are
      using the correct structure and B channel.  If there is any problem with
      the operations then the call is now hungup with an appropriate cause code.
      
      * Made miscellaneous messages (INFORMATION, FACILITY, NOTIFY) find the
      correct structure by looking for the call and not using the channel ID.
      NOTIFY is an exception with versions of libpri before v1.4.11 because a
      call pointer is not available for Asterisk to use.
      
      * Made all hangup messages (DISCONNECT, RELEASE, RELEASE_COMPLETE) find
      the correct structure by looking for the call and not using the channel
      ID.
      
      (closes issue #18313)
      Reported by: destiny6628
      Tested by: rmudgett
      JIRA SWP-2620
      
      (closes issue #18231)
      Reported by: destiny6628
      Tested by: rmudgett
      JIRA SWP-2924
      
      (closes issue #18488)
      Reported by: jpokorny
      JIRA SWP-2929
      
      JIRA AST-437 (The issues fixed here are most likely causing this JIRA issue.)
      JIRA DAHDI-406
      JIRA LIBPRI-33 (Stuck resetting flag likely fixed)
    ........
  ................
................

Modified:
    trunk/   (props changed)
    trunk/channels/chan_dahdi.c
    trunk/channels/sig_pri.c
    trunk/channels/sig_pri.h

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.8-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=312579&r1=312578&r2=312579
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Mon Apr  4 11:17:58 2011
@@ -3238,12 +3238,7 @@
 		if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
 			/* This is a B channel interface. */
 			++num_b_chans;
-			if (pri->pvts[idx]->owner
-#if defined(HAVE_PRI_SERVICE_MESSAGES)
-				/* Out-of-service B channels are "in-use". */
-				|| pri->pvts[idx]->service_status
-#endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
-				) {
+			if (!sig_pri_is_chan_available(pri->pvts[idx])) {
 				++in_use;
 			}
 			if (!pri->pvts[idx]->inalarm) {
@@ -6458,11 +6453,9 @@
 	p->cidspill = NULL;
 
 	ast_mutex_unlock(&p->lock);
-	ast_module_unref(ast_module_info->self);
 	ast_verb(3, "Hungup '%s'\n", ast->name);
 
 	ast_mutex_lock(&iflock);
-
 	if (p->restartpending) {
 		num_restart_pending--;
 	}
@@ -6471,6 +6464,8 @@
 		destroy_channel(p, 0);
 	}
 	ast_mutex_unlock(&iflock);
+
+	ast_module_unref(ast_module_info->self);
 	return 0;
 }
 
@@ -8771,14 +8766,27 @@
 
 static struct ast_frame *dahdi_read(struct ast_channel *ast)
 {
-	struct dahdi_pvt *p = ast->tech_pvt;
+	struct dahdi_pvt *p;
 	int res;
 	int idx;
 	void *readbuf;
 	struct ast_frame *f;
 
+	/*
+	 * For analog channels, we must do deadlock avoidance because
+	 * analog ports can have more than one Asterisk channel using
+	 * the same private structure.
+	 */
+	p = ast->tech_pvt;
 	while (ast_mutex_trylock(&p->lock)) {
 		CHANNEL_DEADLOCK_AVOIDANCE(ast);
+
+		/*
+		 * For PRI channels, we must refresh the private pointer because
+		 * the call could move to another B channel while the Asterisk
+		 * channel is unlocked.
+		 */
+		p = ast->tech_pvt;
 	}
 
 	idx = dahdi_get_index(ast, p, 0);
@@ -11317,7 +11325,9 @@
 		switch (i->sig) {
 #if defined(HAVE_PRI)
 		case SIG_PRI_LIB_HANDLE_CASES:
+			ast_mutex_lock(&i->lock);
 			sig_pri_chan_alarm_notify(i->sig_pvt, 1);
+			ast_mutex_unlock(&i->lock);
 			break;
 #endif	/* defined(HAVE_PRI) */
 #if defined(HAVE_SS7)
@@ -11335,7 +11345,9 @@
 		switch (i->sig) {
 #if defined(HAVE_PRI)
 		case SIG_PRI_LIB_HANDLE_CASES:
+			ast_mutex_lock(&i->lock);
 			sig_pri_chan_alarm_notify(i->sig_pvt, 0);
+			ast_mutex_unlock(&i->lock);
 			break;
 #endif	/* defined(HAVE_PRI) */
 #if defined(HAVE_SS7)
@@ -12745,7 +12757,9 @@
 				switch (tmp->sig) {
 #ifdef HAVE_PRI
 				case SIG_PRI_LIB_HANDLE_CASES:
+					ast_mutex_lock(&tmp->lock);
 					sig_pri_chan_alarm_notify(tmp->sig_pvt, si.alarms);
+					ast_mutex_unlock(&tmp->lock);
 					break;
 #endif
 #if defined(HAVE_SS7)
@@ -13489,6 +13503,14 @@
 				tmp = analog_request(p->sig_pvt, &callwait, requestor);
 #ifdef HAVE_PRI
 			} else if (dahdi_sig_pri_lib_handles(p->sig)) {
+				/*
+				 * We already have the B channel reserved for this call.  We
+				 * just need to make sure that dahdi_hangup() has completed
+				 * cleaning up before continuing.
+				 */
+				ast_mutex_lock(&p->lock);
+				ast_mutex_unlock(&p->lock);
+
 				sig_pri_extract_called_num_subaddr(p->sig_pvt, data, p->dnid,
 					sizeof(p->dnid));
 				tmp = sig_pri_request(p->sig_pvt, SIG_PRI_DEFLAW, requestor, transcapdigital);
@@ -13503,18 +13525,23 @@
 			if (!tmp) {
 				p->outgoing = 0;
 #if defined(HAVE_PRI)
-#if defined(HAVE_PRI_CALL_WAITING)
 				switch (p->sig) {
 				case SIG_PRI_LIB_HANDLE_CASES:
+#if defined(HAVE_PRI_CALL_WAITING)
 					if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
 						((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
 						ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
 					}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+					/*
+					 * This should be the last thing to clear when we are done with
+					 * the channel.
+					 */
+					((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
 					break;
 				default:
 					break;
 				}
-#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 #endif	/* defined(HAVE_PRI) */
 			} else {
 				snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", (char *) data);
@@ -15194,6 +15221,9 @@
 					ast_cli(a->fd, "Resetting ");
 				if (chan->call)
 					ast_cli(a->fd, "Call ");
+				if (chan->allocated) {
+					ast_cli(a->fd, "Allocated ");
+				}
 				ast_cli(a->fd, "\n");
 				if (tmp->logicalspan)
 					ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=312579&r1=312578&r2=312579
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Mon Apr  4 11:17:58 2011
@@ -55,6 +55,21 @@
 
 /* define this to send PRI user-user information elements */
 #undef SUPPORT_USERUSER
+
+/*!
+ * Define to make always pick a channel if allowed.  Useful for
+ * testing channel shifting.
+ */
+//#define ALWAYS_PICK_CHANNEL	1
+
+/*!
+ * Define to force a RESTART on a channel that returns a cause
+ * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
+ * is because of a stuck channel on the peer and the channel is
+ * always the next channel we pick for an outgoing call then
+ * this can help.
+ */
+#define FORCE_RESTART_UNAVAIL_CHANS		1
 
 #if defined(HAVE_PRI_CCSS)
 struct sig_pri_cc_agent_prv {
@@ -1039,6 +1054,38 @@
 
 /*!
  * \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->resetting || pvt->inalarm;
+}
+
+/*!
+ * \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
  *
@@ -1146,6 +1193,41 @@
 		}
 	}
 	return -1;
+}
+
+/*!
+ * \internal
+ * \brief Kill the call.
+ * \since 1.10
+ *
+ * \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;
+	}
+	pri->pvts[chanpos]->owner->hangupcause = cause;
+	pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
+	sig_pri_unlock_private(pri->pvts[chanpos]);
 }
 
 /*!
@@ -1255,7 +1337,7 @@
 		ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
 			old_chan->owner ? old_chan->owner->name : "",
 			old_chan->channel, new_chan->channel);
-		if (new_chan->owner) {
+		if (!sig_pri_is_chan_available(new_chan)) {
 			ast_log(LOG_WARNING,
 				"Can't move call (%s) from channel %d to %d.  It is already in use.\n",
 				old_chan->owner ? old_chan->owner->name : "",
@@ -1286,6 +1368,7 @@
 		new_chan->alreadyhungup = old_chan->alreadyhungup;
 		new_chan->isidlecall = old_chan->isidlecall;
 		new_chan->progress = old_chan->progress;
+		new_chan->allocated = old_chan->allocated;
 		new_chan->outgoing = old_chan->outgoing;
 		new_chan->digital = old_chan->digital;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1300,6 +1383,7 @@
 		old_chan->alreadyhungup = 0;
 		old_chan->isidlecall = 0;
 		old_chan->progress = 0;
+		old_chan->allocated = 0;
 		old_chan->outgoing = 0;
 		old_chan->digital = 0;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1367,6 +1451,52 @@
 	return -1;
 }
 
+/*!
+ * \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;
+}
+
 static char * redirectingreason2str(int redirectingreason)
 {
 	switch (redirectingreason) {
@@ -1415,39 +1545,49 @@
 	}
 }
 
-/*! \note Assumes the pri->lock is already obtained. */
-static int pri_check_restart(struct sig_pri_span *pri)
+/*!
+ * \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)
-tryanotherpos:
+	unsigned why;
 #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
-	do {
-		pri->resetpos++;
-	} while (pri->resetpos < pri->numchans
-		&& (!pri->pvts[pri->resetpos]
+
+	for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
+		if (!pri->pvts[pri->resetpos]
 			|| pri->pvts[pri->resetpos]->no_b_channel
-			|| pri->pvts[pri->resetpos]->call
-			|| pri->pvts[pri->resetpos]->resetting));
-	if (pri->resetpos < pri->numchans) {
+			|| sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
+			continue;
+		}
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
-		unsigned why;
-
 		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");
-			goto tryanotherpos;
+			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 = 1;
 		pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
 	} else {
 		pri->resetting = 0;
 		time(&pri->lastreset);
-	}
-	return 0;
+		sig_pri_span_devstate_changed(pri);
+	}
 }
 
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1482,6 +1622,18 @@
 }
 #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;
@@ -1496,8 +1648,7 @@
 			break;
 		if (pri->pvts[x]
 			&& !pri->pvts[x]->no_b_channel
-			&& !pri->pvts[x]->inalarm
-			&& !pri->pvts[x]->owner) {
+			&& 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;
@@ -1530,8 +1681,7 @@
 	for (idx = 0; idx < pri->numchans; ++idx) {
 		if (pri->pvts[idx]
 			&& pri->pvts[idx]->no_b_channel
-			&& !pri->pvts[idx]->inalarm
-			&& !pri->pvts[idx]->owner) {
+			&& sig_pri_is_chan_available(pri->pvts[idx])) {
 			ast_debug(1, "Found empty available no B channel interface\n");
 			return idx;
 		}
@@ -1717,6 +1867,9 @@
 		p->exten[0] = '\0';
 		/* Since we send release complete here, we won't get one */
 		p->call = NULL;
+		ast_mutex_lock(&p->pri->lock);
+		sig_pri_span_devstate_changed(p->pri);
+		ast_mutex_unlock(&p->pri->lock);
 	}
 	return NULL;
 }
@@ -4183,42 +4336,6 @@
 	}
 }
 
-#if defined(HAVE_PRI_CALL_HOLD)
-/*!
- * \internal
- * \brief Kill the call.
- * \since 1.10
- *
- * \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]);
-		return;
-	}
-	pri->pvts[chanpos]->owner->hangupcause = cause;
-	pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-	sig_pri_unlock_private(pri->pvts[chanpos]);
-}
-#endif	/* defined(HAVE_PRI_CALL_HOLD) */
-
 /*!
  * \internal
  * \brief Convert the MOH state to string.
@@ -4899,35 +5016,32 @@
 	struct ast_channel *bridged;
 	struct ast_channel *owner;
 
-	chanpos_old = pri_find_principle(pri, ev->hold.channel, ev->hold.call);
+	chanpos_old = pri_find_principle_by_call(pri, ev->hold.call);
 	if (chanpos_old < 0) {
-		ast_log(LOG_WARNING,
-			"Received HOLD on unconfigured channel %d/%d span %d\n",
-			PRI_SPAN(ev->hold.channel), PRI_CHANNEL(ev->hold.channel), pri->span);
+		ast_log(LOG_WARNING, "Span %d: Received HOLD for unknown call.\n", pri->span);
 		return -1;
 	}
 	if (pri->pvts[chanpos_old]->no_b_channel) {
 		/* Call is already on hold or is call waiting call. */
 		return -1;
 	}
+
+	chanpos_new = -1;
 
 	sig_pri_lock_private(pri->pvts[chanpos_old]);
 	sig_pri_lock_owner(pri, chanpos_old);
 	owner = pri->pvts[chanpos_old]->owner;
 	if (!owner) {
-		retval = -1;
 		goto done_with_private;
 	}
 	bridged = ast_bridged_channel(owner);
 	if (!bridged) {
 		/* Cannot hold a call that is not bridged. */
-		retval = -1;
 		goto done_with_owner;
 	}
 	chanpos_new = pri_find_empty_nobch(pri);
 	if (chanpos_new < 0) {
 		/* No hold channel available. */
-		retval = -1;
 		goto done_with_owner;
 	}
 	sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.channel, ev->hold.subcmds,
@@ -4937,17 +5051,21 @@
 	if (chanpos_new < 0) {
 		/* Should never happen. */
 		pri_queue_control(pri, chanpos_old, AST_CONTROL_UNHOLD);
-		retval = -1;
 	} else {
 		sig_pri_ami_hold_event(owner, 1);
-		sig_pri_span_devstate_changed(pri);
-		retval = 0;
 	}
 
 done_with_owner:;
 	ast_channel_unlock(owner);
 done_with_private:;
 	sig_pri_unlock_private(pri->pvts[chanpos_old]);
+
+	if (chanpos_new < 0) {
+		retval = -1;
+	} else {
+		sig_pri_span_devstate_changed(pri);
+		retval = 0;
+	}
 
 	return retval;
 }
@@ -4996,6 +5114,7 @@
 	sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
 		SIG_PRI_MOH_EVENT_HOLD_ACK);
 	sig_pri_unlock_private(pri->pvts[chanpos]);
+	sig_pri_span_devstate_changed(pri);
 }
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5020,6 +5139,7 @@
 	if (chanpos < 0) {
 		ast_log(LOG_WARNING, "Span %d: Could not find principle for HOLD_REJECT\n",
 			pri->span);
+		sig_pri_kill_call(pri, ev->hold_rej.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
 		return;
 	}
 	chanpos = pri_fixup_principle(pri, chanpos, ev->hold_rej.call);
@@ -5058,9 +5178,14 @@
 {
 	int chanpos;
 
-	if (!(ev->retrieve.channel & PRI_HELD_CALL)
-		|| pri_find_principle(pri, ev->retrieve.channel, ev->retrieve.call) < 0) {
+	if (!(ev->retrieve.channel & PRI_HELD_CALL)) {
 		/* The call is not currently held. */
+		pri_retrieve_rej(pri->pri, ev->retrieve.call,
+			PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+		return;
+	}
+	if (pri_find_principle_by_call(pri, ev->retrieve.call) < 0) {
+		ast_log(LOG_WARNING, "Span %d: Received RETRIEVE for unknown call.\n", pri->span);
 		pri_retrieve_rej(pri->pri, ev->retrieve.call,
 			PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
 		return;
@@ -5071,10 +5196,10 @@
 		chanpos = pri_find_principle(pri,
 			ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
 		if (ev->retrieve.flexible
-			&& (chanpos < 0 || pri->pvts[chanpos]->owner)) {
+			&& (chanpos < 0 || !sig_pri_is_chan_available(pri->pvts[chanpos]))) {
 			/*
 			 * Channel selection is flexible and the requested channel
-			 * is bad or already in use.  Pick another channel.
+			 * is bad or not available.  Pick another channel.
 			 */
 			chanpos = pri_find_empty_chan(pri, 1);
 		}
@@ -5127,16 +5252,9 @@
 {
 	int chanpos;
 
-	chanpos = pri_find_principle(pri, ev->retrieve_ack.channel, ev->retrieve_ack.call);
+	chanpos = pri_find_fixup_principle(pri, ev->retrieve_ack.channel,
+		ev->retrieve_ack.call);
 	if (chanpos < 0) {
-		ast_log(LOG_WARNING,
-			"Span %d: Could not find principle for RETRIEVE_ACKNOWLEDGE\n", pri->span);
-		return;
-	}
-	chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve_ack.call);
-	if (chanpos < 0) {
-		/* Very bad news.  The channel is already in use. */
-		sig_pri_kill_call(pri, ev->retrieve_ack.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
 		return;
 	}
 
@@ -5146,6 +5264,7 @@
 	sig_pri_moh_fsm_event(pri->pvts[chanpos]->owner, pri->pvts[chanpos],
 		SIG_PRI_MOH_EVENT_RETRIEVE_ACK);
 	sig_pri_unlock_private(pri->pvts[chanpos]);
+	sig_pri_span_devstate_changed(pri);
 }
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -5170,6 +5289,7 @@
 	if (chanpos < 0) {
 		ast_log(LOG_WARNING, "Span %d: Could not find principle for RETRIEVE_REJECT\n",
 			pri->span);
+		sig_pri_kill_call(pri, ev->retrieve_rej.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
 		return;
 	}
 	chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve_rej.call);
@@ -5218,6 +5338,7 @@
 	int nextidle = -1;
 	int haveidles;
 	int activeidles;
+	unsigned int len;
 
 	gettimeofday(&lastidle, NULL);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
@@ -5252,8 +5373,12 @@
 		ast_mutex_lock(&pri->lock);
 		if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->sig != SIG_BRI_PTMP) && (pri->resetinterval > 0)) {
 			if (pri->resetting && pri_is_up(pri)) {
-				if (pri->resetpos < 0)
+				if (pri->resetpos < 0) {
 					pri_check_restart(pri);
+					if (pri->resetting) {
+						sig_pri_span_devstate_changed(pri);
+					}
+				}
 			} else {
 				if (!pri->resetting	&& (t - pri->lastreset) >= pri->resetinterval) {
 					pri->resetting = 1;
@@ -5267,32 +5392,50 @@
 			haveidles = 0;
 			activeidles = 0;
 			for (x = pri->numchans; x >= 0; x--) {
-				if (pri->pvts[x]
-					&& !pri->pvts[x]->owner
-					&& !pri->pvts[x]->call
-					&& !pri->pvts[x]->no_b_channel) {
-					if (haveidles < pri->minunused) {
-						haveidles++;
-					} else if (!pri->pvts[x]->resetting) {
-						nextidle = x;
-						break;
+				if (pri->pvts[x] && !pri->pvts[x]->no_b_channel) {
+					if (sig_pri_is_chan_available(pri->pvts[x])) {
+						if (haveidles < pri->minunused) {
+							haveidles++;
+						} else {
+							nextidle = x;
+							break;
+						}
+					} else if (pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
+						activeidles++;
 					}
-				} else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
-					activeidles++;
+				}
 			}
 			if (nextidle > -1) {
 				if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
 					/* Don't create a new idle call more than once per second */
 					snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
+					pri->pvts[nextidle]->allocated = 1;
+					/*
+					 * Release the PRI lock while we create the channel so other
+					 * threads can send D channel messages.
+					 */
+					ast_mutex_unlock(&pri->lock);
+					/*
+					 * We already have the B channel reserved for this call.  We
+					 * just need to make sure that sig_pri_hangup() has completed
+					 * cleaning up before continuing.
+					 */
+					sig_pri_lock_private(pri->pvts[nextidle]);
+					sig_pri_unlock_private(pri->pvts[nextidle]);
 					idle = sig_pri_request(pri->pvts[nextidle], AST_FORMAT_ULAW, NULL, 0);
+					ast_mutex_lock(&pri->lock);
 					if (idle) {
 						pri->pvts[nextidle]->isidlecall = 1;
 						if (ast_pthread_create_background(&p, NULL, do_idle_thread, pri->pvts[nextidle])) {
 							ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
+							ast_mutex_unlock(&pri->lock);
 							ast_hangup(idle);
+							ast_mutex_lock(&pri->lock);
 						}
-					} else
+					} else {
+						pri->pvts[nextidle]->allocated = 0;
 						ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
+					}
 					gettimeofday(&lastidle, NULL);
 				}
 			} else if ((haveidles < pri->minunused) &&
@@ -5415,11 +5558,12 @@
 					pri->lastreset -= pri->resetinterval;
 					pri->lastreset += 5;
 				}
+				/* Take the channels from inalarm condition */
 				pri->resetting = 0;
-				/* Take the channels from inalarm condition */
 				for (i = 0; i < pri->numchans; i++) {
 					if (pri->pvts[i]) {
 						sig_pri_set_alarm(pri->pvts[i], 0);
+						pri->pvts[i]->resetting = 0;
 					}
 				}
 				sig_pri_span_devstate_changed(pri);
@@ -5427,41 +5571,41 @@
 			case PRI_EVENT_DCHAN_DOWN:
 				pri_find_dchan(pri);
 				if (!pri_is_up(pri)) {
-					pri->resetting = 0;
 					if (pri->sig == SIG_BRI_PTMP) {
 						/* For PTMP connections with non persistent layer 2 we want
 						 * to *not* declare inalarm unless there actually is an alarm */
 						break;
 					}
 					/* Hangup active channels and put them in alarm mode */
+					pri->resetting = 0;
 					for (i = 0; i < pri->numchans; i++) {
 						struct sig_pri_chan *p = pri->pvts[i];
+
 						if (p) {
-							if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
-								/* T309 is not enabled : hangup calls when alarm occurs */
+							if (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
+								/* T309 is not enabled : destroy calls when alarm occurs */
 								if (p->call) {
-									if (p->pri && p->pri->pri) {
-										pri_hangup(p->pri->pri, p->call, -1);
-										pri_destroycall(p->pri->pri, p->call);
-										p->call = NULL;
-									} else
-										ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
+									pri_destroycall(p->pri->pri, p->call);
+									p->call = NULL;
 								}
 								if (p->owner)
 									p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 							}
 							sig_pri_set_alarm(p, 1);
+							p->resetting = 0;
 						}
 					}
 					sig_pri_span_devstate_changed(pri);
 				}
 				break;
 			case PRI_EVENT_RESTART:
-				if (e->restart.channel > -1) {
+				if (e->restart.channel > -1 && PRI_CHANNEL(e->ring.channel) != 0xFF) {
 					chanpos = pri_find_principle(pri, e->restart.channel, NULL);
 					if (chanpos < 0)
-						ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
-							PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+						ast_log(LOG_WARNING,
+							"Span %d: Restart requested on odd/unavailable channel number %d/%d\n",
+							pri->span, PRI_SPAN(e->restart.channel),
+							PRI_CHANNEL(e->restart.channel));
 					else {
 						int skipit = 0;
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
@@ -5470,16 +5614,18 @@
 						why = pri->pvts[chanpos]->service_status;
 						if (why) {
 							ast_log(LOG_NOTICE,
-								"span '%d' channel '%d' out-of-service (reason: %s), ignoring RESTART\n",
-								pri->span, PRI_CHANNEL(e->restart.channel),
+								"Span %d: Channel %d/%d out-of-service (reason: %s), ignoring RESTART\n",
+								pri->span, PRI_SPAN(e->restart.channel),
+								PRI_CHANNEL(e->restart.channel),
 								(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
 							skipit = 1;
 						}
 #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
 						sig_pri_lock_private(pri->pvts[chanpos]);
 						if (!skipit) {
-							ast_verb(3, "B-channel %d/%d restarted on span %d\n",
-								PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+							ast_verb(3, "Span %d: Channel %d/%d restarted\n", pri->span,
+								PRI_SPAN(e->restart.channel),
+								PRI_CHANNEL(e->restart.channel));
 							if (pri->pvts[chanpos]->call) {
 								pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
 								pri->pvts[chanpos]->call = NULL;
@@ -5504,6 +5650,7 @@
 							sig_pri_unlock_private(pri->pvts[x]);
 						}
 				}
+				sig_pri_span_devstate_changed(pri);
 				break;
 			case PRI_EVENT_KEYPAD_DIGIT:
 				if (sig_pri_is_cis_call(e->digit.channel)) {
@@ -5511,33 +5658,29 @@
 						e->digit.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->digit.channel, e->digit.call);
+				chanpos = pri_find_principle_by_call(pri, e->digit.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
-					if (chanpos > -1) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.channel,
-							e->digit.subcmds, e->digit.call);
-						/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
-						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
-							&& pri->pvts[chanpos]->call == e->digit.call
-							&& pri->pvts[chanpos]->owner) {
-							/* how to do that */
-							int digitlen = strlen(e->digit.digits);
-							int i;
-
-							for (i = 0; i < digitlen; i++) {
-								struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->digit.digits[i], };
-
-								pri_queue_frame(pri, chanpos, &f);
-							}
-						}
-						sig_pri_unlock_private(pri->pvts[chanpos]);
+					ast_log(LOG_WARNING,
+						"Span %d: Received keypad digits for unknown call.\n", pri->span);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.channel,
+					e->digit.subcmds, e->digit.call);
+				/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
+				if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+					&& pri->pvts[chanpos]->owner) {
+					/* how to do that */
+					int digitlen = strlen(e->digit.digits);
+					int i;
+
+					for (i = 0; i < digitlen; i++) {
+						struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->digit.digits[i], };
+
+						pri_queue_frame(pri, chanpos, &f);
 					}
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 
 			case PRI_EVENT_INFO_RECEIVED:
@@ -5546,33 +5689,29 @@
 						e->ring.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
+				chanpos = pri_find_principle_by_call(pri, e->ring.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
-					if (chanpos > -1) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
-							e->ring.subcmds, e->ring.call);
-						/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
-						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
-							&& pri->pvts[chanpos]->call == e->ring.call
-							&& pri->pvts[chanpos]->owner) {
-							/* how to do that */
-							int digitlen = strlen(e->ring.callednum);
-							int i;
-
-							for (i = 0; i < digitlen; i++) {
-								struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->ring.callednum[i], };
-
-								pri_queue_frame(pri, chanpos, &f);
-							}
-						}
-						sig_pri_unlock_private(pri->pvts[chanpos]);
+					ast_log(LOG_WARNING,
+						"Span %d: Received INFORMATION for unknown call.\n", pri->span);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+					e->ring.subcmds, e->ring.call);
+				/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
+				if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+					&& pri->pvts[chanpos]->owner) {
+					/* how to do that */
+					int digitlen = strlen(e->ring.callednum);
+					int i;
+
+					for (i = 0; i < digitlen; i++) {
+						struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->ring.callednum[i], };
+
+						pri_queue_frame(pri, chanpos, &f);
 					}
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
 			case PRI_EVENT_SERVICE:
@@ -5645,6 +5784,15 @@
 						e->ring.call);
 					break;
 				}
+				chanpos = pri_find_principle_by_call(pri, e->ring.call);
+				if (-1 < chanpos) {
+					/* Libpri has already filtered out duplicate SETUPs. */
+					ast_log(LOG_WARNING,
+						"Span %d: Got SETUP with duplicate call ptr.  Dropping call.\n",
+						pri->span);
+					pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
+					break;
+				}
 				if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
 					/* Any channel requested. */
 					chanpos = pri_find_empty_chan(pri, 1);
@@ -5671,373 +5819,400 @@
 				} else {
 					/* A channel is specified. */
 					chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
-				}
-				/* if no channel specified find one empty */
+					if (chanpos < 0) {
+						ast_log(LOG_WARNING,
+							"Span %d: SETUP on unconfigured channel %d/%d\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+					} else if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+						/* This is where we handle initial glare */
+						ast_debug(1,
+							"Span %d: SETUP requested unavailable channel %d/%d.  Attempting to renegotiate.\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+						chanpos = -1;
+					}
+#if defined(ALWAYS_PICK_CHANNEL)
+					if (e->ring.flexible) {
+						chanpos = -1;
+					}
+#endif	/* defined(ALWAYS_PICK_CHANNEL) */
+					if (chanpos < 0 && e->ring.flexible) {
+						/* We can try to pick another channel. */
+						chanpos = pri_find_empty_chan(pri, 1);
+					}
+				}
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+					if (e->ring.flexible) {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+					} else {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+					}
+					break;
+				}
+
+				sig_pri_lock_private(pri->pvts[chanpos]);
+
+				/* Mark channel as in use so noone else will steal it. */
+				pri->pvts[chanpos]->call = e->ring.call;
+
+				/* Use plancallingnum as a scratch buffer since it is initialized next. */
+				apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
+					e->ring.redirectingnum, e->ring.callingplanrdnis);
+				sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
+
+				/* Setup caller-id info */
+				apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+				pri->pvts[chanpos]->cid_ani2 = 0;
+				if (pri->pvts[chanpos]->use_callerid) {
+					ast_shrink_phone_number(plancallingnum);
+					ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
+#ifdef PRI_ANI
+					if (!ast_strlen_zero(e->ring.callingani)) {
+						apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
+						ast_shrink_phone_number(plancallingani);
+						ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
+					} else {
+						pri->pvts[chanpos]->cid_ani[0] = '\0';
+					}
+#endif
+					pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+#if defined(HAVE_PRI_SUBADDR)
+					if (e->ring.calling.subaddress.valid) {
+						struct ast_party_subaddress calling_subaddress;
+
+						ast_party_subaddress_init(&calling_subaddress);
+						sig_pri_set_subaddress(&calling_subaddress,
+							&e->ring.calling.subaddress);
+						if (calling_subaddress.str) {
+							ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
+								calling_subaddress.str,
+								sizeof(pri->pvts[chanpos]->cid_subaddr));
+						}
+						ast_party_subaddress_free(&calling_subaddress);
+					}
+#endif /* defined(HAVE_PRI_SUBADDR) */
+					ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
+					pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
+					pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+					if (e->ring.ani2 >= 0) {
+						pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+					}
 				} else {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					if (pri->pvts[chanpos]->owner) {
-						if (pri->pvts[chanpos]->call == e->ring.call) {
-							ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
-								PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-							sig_pri_unlock_private(pri->pvts[chanpos]);
+					pri->pvts[chanpos]->cid_num[0] = '\0';
+					pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+					pri->pvts[chanpos]->cid_ani[0] = '\0';
+					pri->pvts[chanpos]->cid_name[0] = '\0';
+					pri->pvts[chanpos]->cid_ton = 0;
+					pri->pvts[chanpos]->callingpres = 0;
+				}
+
+				/* Setup the user tag for party id's from this device for this call. */
+				if (pri->append_msn_to_user_tag) {
+					snprintf(pri->pvts[chanpos]->user_tag,
+						sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
+						pri->initial_user_tag,
+						pri->nodetype == PRI_NETWORK
+							? plancallingnum : e->ring.callednum);
+				} else {
+					ast_copy_string(pri->pvts[chanpos]->user_tag,
+						pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
+				}
+
+				sig_pri_set_caller_id(pri->pvts[chanpos]);
+
+				/* Set DNID on all incoming calls -- even immediate */
+				sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
+
+				/* If immediate=yes go to s|1 */
+				if (pri->pvts[chanpos]->immediate) {
+					ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* Get called number */
+				else if (!ast_strlen_zero(e->ring.callednum)) {
+					ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+				} else if (pri->overlapdial)
+					pri->pvts[chanpos]->exten[0] = '\0';
+				else {
+					/* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* No number yet, but received "sending complete"? */
+				if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
+					ast_verb(3, "Going to extension s|1 because of Complete received\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+
+				/* Make sure extension exists (or in overlap dial mode, can exist) */
+				if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||

[... 2104 lines stripped ...]



More information about the asterisk-commits mailing list