diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 3f1d9e0518961d0d77d310ebe616919e3a3b65c8..e1c4a26bc8816d62b92c21d104855577cb6e4f38 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -3238,12 +3238,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
 		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 @@ hangup_out:
 	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 @@ hangup_out:
 		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_exception(struct ast_channel *ast)
 
 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 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 		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 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 		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 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				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 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
 				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 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
 			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 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
 					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);
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index f36a7e2f0795e06ab46ab356c6eabeb08426cf4e..1df3972f4450bf6be6ff785bf7f52adeb0e6b49e 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -56,6 +56,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 {
 	/*! Asterisk span D channel control structure. */
@@ -1037,6 +1052,38 @@ static int pri_find_dchan(struct sig_pri_span *pri)
 	return 0;
 }
 
+/*!
+ * \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.
@@ -1148,6 +1195,41 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
 	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]);
+}
+
 /*!
  * \internal
  * \brief Find the private structure for the libpri call.
@@ -1255,7 +1337,7 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 		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 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 		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 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 		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 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 	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 @@ static void apply_plan_to_number(char *buf, size_t size, const struct sig_pri_sp
 	}
 }
 
-/*! \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);
+		sig_pri_span_devstate_changed(pri);
 	}
-	return 0;
 }
 
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1482,6 +1622,18 @@ static void sig_pri_init_config(struct sig_pri_chan *pvt, struct sig_pri_span *p
 }
 #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 @@ static int pri_find_empty_chan(struct sig_pri_span *pri, int backwards)
 			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 @@ static int pri_find_empty_nobch(struct sig_pri_span *pri)
 	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 @@ static void *pri_ss_thread(void *data)
 		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 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
 	}
 }
 
-#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,11 +5016,9 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
 	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) {
@@ -4911,23 +5026,22 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
 		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,11 +5051,8 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
 	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:;
@@ -4949,6 +5060,13 @@ done_with_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;
 }
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
@@ -4996,6 +5114,7 @@ static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
 	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 @@ static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
 	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,23 +5178,28 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 {
 	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;
+	}
 	if (PRI_CHANNEL(ev->retrieve.channel) == 0xFF) {
 		chanpos = pri_find_empty_chan(pri, 1);
 	} else {
 		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 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 {
 	int chanpos;
 
-	chanpos = pri_find_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);
+	chanpos = pri_find_fixup_principle(pri, ev->retrieve_ack.channel,
+		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 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 	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 @@ static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
 	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 @@ static void *pri_dchannel(void *vpri)
 	int nextidle = -1;
 	int haveidles;
 	int activeidles;
+	unsigned int len;
 
 	gettimeofday(&lastidle, NULL);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
@@ -5252,8 +5373,12 @@ static void *pri_dchannel(void *vpri)
 		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 @@ static void *pri_dchannel(void *vpri)
 			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 @@ static void *pri_dchannel(void *vpri)
 					pri->lastreset -= pri->resetinterval;
 					pri->lastreset += 5;
 				}
-				pri->resetting = 0;
 				/* Take the channels from inalarm condition */
+				pri->resetting = 0;
 				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 @@ static void *pri_dchannel(void *vpri)
 			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 @@ static void *pri_dchannel(void *vpri)
 						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 @@ static void *pri_dchannel(void *vpri)
 							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 @@ static void *pri_dchannel(void *vpri)
 						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 @@ static void *pri_dchannel(void *vpri)
 						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 @@ static void *pri_dchannel(void *vpri)
 						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 @@ static void *pri_dchannel(void *vpri)
 				} else {
 					/* A channel is specified. */
 					chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
+					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 no channel specified find one empty */
 				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);
-				} 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]);
-							break;
-						} else {
-							/* This is where we handle initial glare */
-							ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiating channel.\n",
-							PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-							sig_pri_unlock_private(pri->pvts[chanpos]);
-							chanpos = -1;
-						}
+					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);
 					}
-					if (chanpos > -1)
-						sig_pri_unlock_private(pri->pvts[chanpos]);
+					break;
 				}
-				if ((chanpos < 0) && (e->ring.flexible))
-					chanpos = pri_find_empty_chan(pri, 1);
-				if (chanpos > -1) {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					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));
+
+				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';
-						}
+					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';
+					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);
+					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 {
-						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;
+					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 {
+					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));
-					}
+				/* 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]);
+				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);
+				/* 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';
-					}
+				/* 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)) ||
-						ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
-						/* Setup law */
-						if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
-							/* Just announce proceeding */
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
-							pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
-						} else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
-							pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-						} else {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
-							pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-						}
+				/* 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)) ||
+					ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+					/* Setup law */
+					if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+						/* Just announce proceeding */
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
+						pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+					} else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+						pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+					} else {
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
+						pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+					}
 
-						/* Start PBX */
-						if (!e->ring.complete
-							&& (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
-							&& ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
-							/*
-							 * Release the PRI lock while we create the channel
-							 * so other threads can send D channel messages.
-							 */
-							ast_mutex_unlock(&pri->lock);
-							c = sig_pri_new_ast_channel(pri->pvts[chanpos],
-								AST_STATE_RESERVED,
-								(e->ring.layer1 == PRI_LAYER_1_ALAW)
-									? SIG_PRI_ALAW : SIG_PRI_ULAW,
-								e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
-							ast_mutex_lock(&pri->lock);
-							if (c) {
+					/* Start PBX */
+					if (!e->ring.complete
+						&& (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+						&& ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+						/*
+						 * Release the PRI lock while we create the channel so other
+						 * threads can send D channel messages.  We must also release
+						 * the private lock to prevent deadlock while creating the
+						 * channel.
+						 */
+						sig_pri_unlock_private(pri->pvts[chanpos]);
+						ast_mutex_unlock(&pri->lock);
+						c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+							AST_STATE_RESERVED,
+							(e->ring.layer1 == PRI_LAYER_1_ALAW)
+								? SIG_PRI_ALAW : SIG_PRI_ULAW,
+							e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
+						ast_mutex_lock(&pri->lock);
+						sig_pri_lock_private(pri->pvts[chanpos]);
+						if (c) {
 #if defined(HAVE_PRI_SUBADDR)
-								if (e->ring.calling.subaddress.valid) {
-									/* Set Calling Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->caller.id.subaddress,
-										&e->ring.calling.subaddress);
-									if (!e->ring.calling.subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.calling.subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
-											(char *) e->ring.calling.subaddress.data);
-									}
-									ast_channel_unlock(c);
+							if (e->ring.calling.subaddress.valid) {
+								/* Set Calling Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->caller.id.subaddress,
+									&e->ring.calling.subaddress);
+								if (!e->ring.calling.subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.calling.subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+										(char *) e->ring.calling.subaddress.data);
 								}
-								if (e->ring.called_subaddress.valid) {
-									/* Set Called Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->dialed.subaddress,
-										&e->ring.called_subaddress);
-									if (!e->ring.called_subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.called_subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
-											(char *) e->ring.called_subaddress.data);
-									}
-									ast_channel_unlock(c);
+								ast_channel_unlock(c);
+							}
+							if (e->ring.called_subaddress.valid) {
+								/* Set Called Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->dialed.subaddress,
+									&e->ring.called_subaddress);
+								if (!e->ring.called_subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.called_subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+										(char *) e->ring.called_subaddress.data);
 								}
+								ast_channel_unlock(c);
+							}
 #else
-								if (!ast_strlen_zero(e->ring.callingsubaddr)) {
-									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
-								}
+							if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+							}
 #endif /* !defined(HAVE_PRI_SUBADDR) */
-								if (e->ring.ani2 >= 0) {
-									snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
-									pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-								}
+							if (e->ring.ani2 >= 0) {
+								snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+								pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+							}
 
 #ifdef SUPPORT_USERUSER
-								if (!ast_strlen_zero(e->ring.useruserinfo)) {
-									pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
-								}
+							if (!ast_strlen_zero(e->ring.useruserinfo)) {
+								pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+							}
 #endif
 
-								snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
-								pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
-								if (e->ring.redirectingreason >= 0) {
-									/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
-									pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-								}
+							snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+							pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+							if (e->ring.redirectingreason >= 0) {
+								/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
+								pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+							}
 #if defined(HAVE_PRI_REVERSE_CHARGE)
-								pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+							pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
 #endif
 #if defined(HAVE_PRI_SETUP_KEYPAD)
-								ast_copy_string(pri->pvts[chanpos]->keypad_digits,
-									e->ring.keypad_digits,
-									sizeof(pri->pvts[chanpos]->keypad_digits));
+							ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+								e->ring.keypad_digits,
+								sizeof(pri->pvts[chanpos]->keypad_digits));
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
 
-								sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
-									e->ring.subcmds, e->ring.call);
+							sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+								e->ring.subcmds, e->ring.call);
 
-								if (!pri->pvts[chanpos]->digital
-									&& !pri->pvts[chanpos]->no_b_channel) {
-									/*
-									 * Call has a channel.
-									 * Indicate that we are providing dialtone.
-									 */
-									pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
+							if (!pri->pvts[chanpos]->digital
+								&& !pri->pvts[chanpos]->no_b_channel) {
+								/*
+								 * Call has a channel.
+								 * Indicate that we are providing dialtone.
+								 */
+								pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
 #ifdef HAVE_PRI_PROG_W_CAUSE
-									pri_progress_with_cause(pri->pri, e->ring.call,
-										PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
+								pri_progress_with_cause(pri->pri, e->ring.call,
+									PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
 #else
-									pri_progress(pri->pri, e->ring.call,
-										PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+								pri_progress(pri->pri, e->ring.call,
+									PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
 #endif
-								}
 							}
-							if (c && !ast_pthread_create_detached(&threadid, NULL, pri_ss_thread, pri->pvts[chanpos])) {
-								ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
-									plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
-									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+						}
+						if (c && !ast_pthread_create_detached(&threadid, NULL, pri_ss_thread, pri->pvts[chanpos])) {
+							ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+								plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+						} else {
+							ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							if (c) {
+								/* Avoid deadlock while destroying channel */
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								ast_mutex_unlock(&pri->lock);
+								ast_hangup(c);
+								ast_mutex_lock(&pri->lock);
 							} else {
-								ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
-									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-								if (c)
-									ast_hangup(c);
-								else {
-									pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-									pri->pvts[chanpos]->call = NULL;
-								}
+								pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+								pri->pvts[chanpos]->call = NULL;
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								sig_pri_span_devstate_changed(pri);
 							}
-						} else {
+							break;
+						}
+					} else {
+						/*
+						 * Release the PRI lock while we create the channel so other
+						 * threads can send D channel messages.  We must also release
+						 * the private lock to prevent deadlock while creating the
+						 * channel.
+						 */
+						sig_pri_unlock_private(pri->pvts[chanpos]);
+						ast_mutex_unlock(&pri->lock);
+						c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+							AST_STATE_RING,
+							(e->ring.layer1 == PRI_LAYER_1_ALAW)
+								? SIG_PRI_ALAW : SIG_PRI_ULAW, e->ring.ctype,
+							pri->pvts[chanpos]->exten, NULL);
+						ast_mutex_lock(&pri->lock);
+						sig_pri_lock_private(pri->pvts[chanpos]);
+						if (c) {
 							/*
-							 * Release the PRI lock while we create the channel
-							 * so other threads can send D channel messages.
+							 * It is reasonably safe to set the following
+							 * channel variables while the PRI and DAHDI private
+							 * structures are locked.  The PBX has not been
+							 * started yet and it is unlikely that any other task
+							 * will do anything with the channel we have just
+							 * created.
 							 */
-							ast_mutex_unlock(&pri->lock);
-							c = sig_pri_new_ast_channel(pri->pvts[chanpos],
-								AST_STATE_RING,
-								(e->ring.layer1 == PRI_LAYER_1_ALAW)
-									? SIG_PRI_ALAW : SIG_PRI_ULAW, e->ring.ctype,
-								pri->pvts[chanpos]->exten, NULL);
-							ast_mutex_lock(&pri->lock);
-							if (c) {
-								/*
-								 * It is reasonably safe to set the following
-								 * channel variables while the PRI and DAHDI private
-								 * structures are locked.  The PBX has not been
-								 * started yet and it is unlikely that any other task
-								 * will do anything with the channel we have just
-								 * created.
-								 */
 #if defined(HAVE_PRI_SUBADDR)
-								if (e->ring.calling.subaddress.valid) {
-									/* Set Calling Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->caller.id.subaddress,
-										&e->ring.calling.subaddress);
-									if (!e->ring.calling.subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.calling.subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
-											(char *) e->ring.calling.subaddress.data);
-									}
-									ast_channel_unlock(c);
+							if (e->ring.calling.subaddress.valid) {
+								/* Set Calling Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->caller.id.subaddress,
+									&e->ring.calling.subaddress);
+								if (!e->ring.calling.subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.calling.subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+										(char *) e->ring.calling.subaddress.data);
 								}
-								if (e->ring.called_subaddress.valid) {
-									/* Set Called Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->dialed.subaddress,
-										&e->ring.called_subaddress);
-									if (!e->ring.called_subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.called_subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
-											(char *) e->ring.called_subaddress.data);
-									}
-									ast_channel_unlock(c);
+								ast_channel_unlock(c);
+							}
+							if (e->ring.called_subaddress.valid) {
+								/* Set Called Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->dialed.subaddress,
+									&e->ring.called_subaddress);
+								if (!e->ring.called_subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.called_subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+										(char *) e->ring.called_subaddress.data);
 								}
+								ast_channel_unlock(c);
+							}
 #else
-								if (!ast_strlen_zero(e->ring.callingsubaddr)) {
-									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
-								}
+							if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+							}
 #endif /* !defined(HAVE_PRI_SUBADDR) */
-								if (e->ring.ani2 >= 0) {
-									snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
-									pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-								}
+							if (e->ring.ani2 >= 0) {
+								snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+								pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+							}
 
 #ifdef SUPPORT_USERUSER
-								if (!ast_strlen_zero(e->ring.useruserinfo)) {
-									pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
-								}
+							if (!ast_strlen_zero(e->ring.useruserinfo)) {
+								pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+							}
 #endif
 
-								if (e->ring.redirectingreason >= 0) {
-									/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
-									pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-								}
+							if (e->ring.redirectingreason >= 0) {
+								/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
+								pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+							}
 #if defined(HAVE_PRI_REVERSE_CHARGE)
-								pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+							pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
 #endif
 #if defined(HAVE_PRI_SETUP_KEYPAD)
-								ast_copy_string(pri->pvts[chanpos]->keypad_digits,
-									e->ring.keypad_digits,
-									sizeof(pri->pvts[chanpos]->keypad_digits));
+							ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+								e->ring.keypad_digits,
+								sizeof(pri->pvts[chanpos]->keypad_digits));
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
 
-								snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
-								pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+							snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+							pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
 
-								sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
-									e->ring.subcmds, e->ring.call);
+							sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+								e->ring.subcmds, e->ring.call);
 
-							}
-							if (c && !ast_pbx_start(c)) {
-								ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
-									plancallingnum, pri->pvts[chanpos]->exten,
-									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-								sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
+						}
+						if (c && !ast_pbx_start(c)) {
+							ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+								plancallingnum, pri->pvts[chanpos]->exten,
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
+						} else {
+							ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							if (c) {
+								/* Avoid deadlock while destroying channel */
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								ast_mutex_unlock(&pri->lock);
+								ast_hangup(c);
+								ast_mutex_lock(&pri->lock);
 							} else {
-								ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
-									pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
-								if (c) {
-									ast_hangup(c);
-								} else {
-									pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
-									pri->pvts[chanpos]->call = NULL;
-								}
+								pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+								pri->pvts[chanpos]->call = NULL;
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								sig_pri_span_devstate_changed(pri);
 							}
+							break;
 						}
-					} else {
-						ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
-							pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
-							pri->pvts[chanpos]->prioffset, pri->span);
-						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
-						pri->pvts[chanpos]->call = NULL;
-						pri->pvts[chanpos]->exten[0] = '\0';
 					}
-					sig_pri_unlock_private(pri->pvts[chanpos]);
 				} else {
-					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);
+					ast_verb(3,
+						"Span %d: Extension %s@%s does not exist.  Rejecting call from '%s'.\n",
+						pri->span, pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context,
+						pri->pvts[chanpos]->cid_num);
+					pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
+					pri->pvts[chanpos]->call = NULL;
+					pri->pvts[chanpos]->exten[0] = '\0';
+					sig_pri_unlock_private(pri->pvts[chanpos]);
+					sig_pri_span_devstate_changed(pri);
+					break;
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_RINGING:
 				if (sig_pri_is_cis_call(e->ringing.channel)) {
@@ -6045,55 +6220,47 @@ static void *pri_dchannel(void *vpri)
 						e->ringing.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->ringing.channel, e->ringing.call);
+				chanpos = pri_find_fixup_principle(pri, e->ringing.channel,
+					e->ringing.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
-					if (chanpos < 0) {
-						ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n",
-							PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
-					} else {
-						sig_pri_lock_private(pri->pvts[chanpos]);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
 
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.channel,
-							e->ringing.subcmds, e->ringing.call);
-						sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
-						sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
-						pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
-						if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_ALERTING) {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_ALERTING;
-						}
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.channel,
+					e->ringing.subcmds, e->ringing.call);
+				sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
+				sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
+				pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
+				if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_ALERTING) {
+					pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_ALERTING;
+				}
 
-						if (
+				if (
 #ifdef PRI_PROGRESS_MASK
-							e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE
+					e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE
 #else
-							e->ringing.progress == 8
+					e->ringing.progress == 8
 #endif
-							) {
-							sig_pri_open_media(pri->pvts[chanpos]);
-						}
-
+					) {
+					sig_pri_open_media(pri->pvts[chanpos]);
+				}
 
 #ifdef SUPPORT_USERUSER
-						if (!ast_strlen_zero(e->ringing.useruserinfo)) {
-							struct ast_channel *owner;
-
-							sig_pri_lock_owner(pri, chanpos);
-							owner = pri->pvts[chanpos]->owner;
-							if (owner) {
-								pbx_builtin_setvar_helper(owner, "USERUSERINFO",
-									e->ringing.useruserinfo);
-								ast_channel_unlock(owner);
-							}
-						}
-#endif
+				if (!ast_strlen_zero(e->ringing.useruserinfo)) {
+					struct ast_channel *owner;
 
-						sig_pri_unlock_private(pri->pvts[chanpos]);
+					sig_pri_lock_owner(pri, chanpos);
+					owner = pri->pvts[chanpos]->owner;
+					if (owner) {
+						pbx_builtin_setvar_helper(owner, "USERUSERINFO",
+							e->ringing.useruserinfo);
+						ast_channel_unlock(owner);
 					}
 				}
+#endif
+
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_PROGRESS:
 				if (sig_pri_is_cis_call(e->proceeding.channel)) {
@@ -6101,44 +6268,48 @@ static void *pri_dchannel(void *vpri)
 						e->proceeding.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
-				if (chanpos > -1) {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
-						e->proceeding.subcmds, e->proceeding.call);
+				chanpos = pri_find_fixup_principle(pri, e->proceeding.channel,
+					e->proceeding.call);
+				if (chanpos < 0) {
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
+					e->proceeding.subcmds, e->proceeding.call);
 
-					if (e->proceeding.cause > -1) {
-						ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
+				if (e->proceeding.cause > -1) {
+					ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
 
-						/* Work around broken, out of spec USER_BUSY cause in a progress message */
-						if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
-							if (pri->pvts[chanpos]->owner) {
-								ast_verb(3, "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
+					/* Work around broken, out of spec USER_BUSY cause in a progress message */
+					if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
+						if (pri->pvts[chanpos]->owner) {
+							ast_verb(3, "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
 
-								pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
-								pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
-							}
+							pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
+							pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
 						}
 					}
+				}
 
-					if (!pri->pvts[chanpos]->progress
-						&& !pri->pvts[chanpos]->no_b_channel
+				if (!pri->pvts[chanpos]->progress
+					&& !pri->pvts[chanpos]->no_b_channel
 #ifdef PRI_PROGRESS_MASK
-						&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
+					&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
 #else
-						&& e->proceeding.progress == 8
+					&& e->proceeding.progress == 8
 #endif
-						) {
-						/* Bring voice path up */
-						ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
-							pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
-						pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
-						pri->pvts[chanpos]->progress = 1;
-						sig_pri_set_dialing(pri->pvts[chanpos], 0);
-						sig_pri_open_media(pri->pvts[chanpos]);
-					}
-					sig_pri_unlock_private(pri->pvts[chanpos]);
+					) {
+					/* Bring voice path up */
+					ast_debug(1,
+						"Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
+						pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,
+						pri->span);
+					pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
+					pri->pvts[chanpos]->progress = 1;
+					sig_pri_set_dialing(pri->pvts[chanpos], 0);
+					sig_pri_open_media(pri->pvts[chanpos]);
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_PROCEEDING:
 				if (sig_pri_is_cis_call(e->proceeding.channel)) {
@@ -6146,33 +6317,37 @@ static void *pri_dchannel(void *vpri)
 						e->proceeding.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
-				if (chanpos > -1) {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
-						e->proceeding.subcmds, e->proceeding.call);
-					if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
-						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
-						ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
-							pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
-						pri_queue_control(pri, chanpos, AST_CONTROL_PROCEEDING);
-					}
-					if (!pri->pvts[chanpos]->progress
-						&& !pri->pvts[chanpos]->no_b_channel
+				chanpos = pri_find_fixup_principle(pri, e->proceeding.channel,
+					e->proceeding.call);
+				if (chanpos < 0) {
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
+					e->proceeding.subcmds, e->proceeding.call);
+				if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_PROCEEDING) {
+					pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
+					ast_debug(1,
+						"Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
+						pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,
+						pri->span);
+					pri_queue_control(pri, chanpos, AST_CONTROL_PROCEEDING);
+				}
+				if (!pri->pvts[chanpos]->progress
+					&& !pri->pvts[chanpos]->no_b_channel
 #ifdef PRI_PROGRESS_MASK
-						&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
+					&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
 #else
-						&& e->proceeding.progress == 8
+					&& e->proceeding.progress == 8
 #endif
-						) {
-						/* Bring voice path up */
-						pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
-						pri->pvts[chanpos]->progress = 1;
-						sig_pri_set_dialing(pri->pvts[chanpos], 0);
-						sig_pri_open_media(pri->pvts[chanpos]);
-					}
-					sig_pri_unlock_private(pri->pvts[chanpos]);
+					) {
+					/* Bring voice path up */
+					pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
+					pri->pvts[chanpos]->progress = 1;
+					sig_pri_set_dialing(pri->pvts[chanpos], 0);
+					sig_pri_open_media(pri->pvts[chanpos]);
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_FACILITY:
 				if (!e->facility.call || sig_pri_is_cis_call(e->facility.channel)) {
@@ -6186,27 +6361,21 @@ static void *pri_dchannel(void *vpri)
 #endif	/* !defined(HAVE_PRI_CALL_REROUTING) */
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->facility.channel, e->facility.call);
+				chanpos = pri_find_principle_by_call(pri, e->facility.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->facility.call);
-					if (chanpos < 0) {
-						ast_log(LOG_WARNING, "Facility requested on channel %d/%d not in use on span %d\n",
-							PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
-					} else {
-						sig_pri_lock_private(pri->pvts[chanpos]);
+					ast_log(LOG_WARNING, "Span %d: Received facility for unknown call.\n",
+						pri->span);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
 #if defined(HAVE_PRI_CALL_REROUTING)
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
-							e->facility.subcmds, e->facility.subcall);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
+					e->facility.subcmds, e->facility.subcall);
 #else
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
-							e->facility.subcmds, e->facility.call);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
+					e->facility.subcmds, e->facility.call);
 #endif	/* !defined(HAVE_PRI_CALL_REROUTING) */
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-					}
-				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_ANSWER:
 				if (sig_pri_is_cis_call(e->answer.channel)) {
@@ -6218,16 +6387,8 @@ static void *pri_dchannel(void *vpri)
 						e->answer.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->answer.channel, e->answer.call);
+				chanpos = pri_find_fixup_principle(pri, e->answer.channel, e->answer.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
-					break;
-				}
-				chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
-				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
-						PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
 					break;
 				}
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -6240,11 +6401,23 @@ static void *pri_dchannel(void *vpri)
 						 * kill the call with PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION.
 						 */
 						new_chanpos = pri_find_empty_chan(pri, 1);
+						if (0 <= new_chanpos) {
+							new_chanpos = pri_fixup_principle(pri, new_chanpos,
+								e->answer.call);
+						}
 						if (new_chanpos < 0) {
+							/*
+							 * Either no channel was available or someone stole
+							 * the channel!
+							 */
+							ast_verb(3,
+								"Span %d: Channel not available for call waiting call.\n",
+								pri->span);
 							sig_pri_lock_private(pri->pvts[chanpos]);
 							sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
 								e->answer.subcmds, e->answer.call);
 							sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+							sig_pri_lock_owner(pri, chanpos);
 							if (pri->pvts[chanpos]->owner) {
 								pri->pvts[chanpos]->owner->hangupcause = PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 								switch (pri->pvts[chanpos]->owner->_state) {
@@ -6256,6 +6429,7 @@ static void *pri_dchannel(void *vpri)
 									pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
 									break;
 								}
+								ast_channel_unlock(pri->pvts[chanpos]->owner);
 							} else {
 								pri->pvts[chanpos]->is_call_waiting = 0;
 								ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
@@ -6263,17 +6437,13 @@ static void *pri_dchannel(void *vpri)
 								pri->pvts[chanpos]->call = NULL;
 							}
 							sig_pri_unlock_private(pri->pvts[chanpos]);
+							sig_pri_span_devstate_changed(pri);
 							break;
 						}
-						chanpos = pri_fixup_principle(pri, new_chanpos, e->answer.call);
-						if (chanpos < 0) {
-							ast_log(LOG_WARNING,
-								"Unable to move call waiting call channel on span %d\n",
-								pri->span);
-							break;
-						}
+						chanpos = new_chanpos;
 					}
 					pri_connect_ack(pri->pri, e->answer.call, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+					sig_pri_span_devstate_changed(pri);
 				} else {
 					/* Call is normal so do normal CONNECT_ACKNOWLEDGE. */
 					pri_connect_ack(pri->pri, e->answer.call, 0);
@@ -6285,7 +6455,6 @@ static void *pri_dchannel(void *vpri)
 				if (pri->pvts[chanpos]->is_call_waiting) {
 					pri->pvts[chanpos]->is_call_waiting = 0;
 					ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
-					sig_pri_span_devstate_changed(pri);
 				}
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
 				sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
@@ -6322,28 +6491,18 @@ static void *pri_dchannel(void *vpri)
 						e->connect_ack.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->connect_ack.channel,
+				chanpos = pri_find_fixup_principle(pri, e->connect_ack.channel,
 					e->connect_ack.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Connect ACK on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->connect_ack.channel),
-						PRI_CHANNEL(e->connect_ack.channel), pri->span);
-					break;
-				}
-				chanpos = pri_fixup_principle(pri, chanpos, e->connect_ack.call);
-				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Connect ACK requested on channel %d/%d not in use on span %d\n",
-						PRI_SPAN(e->connect_ack.channel),
-						PRI_CHANNEL(e->connect_ack.channel), pri->span);
 					break;
 				}
 
 				sig_pri_lock_private(pri->pvts[chanpos]);
-				sig_pri_span_devstate_changed(pri);
 				sig_pri_handle_subcmds(pri, chanpos, e->e, e->connect_ack.channel,
 					e->connect_ack.subcmds, e->connect_ack.call);
 				sig_pri_open_media(pri->pvts[chanpos]);
 				sig_pri_unlock_private(pri->pvts[chanpos]);
+				sig_pri_span_devstate_changed(pri);
 				break;
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
 			case PRI_EVENT_HANGUP:
@@ -6353,130 +6512,140 @@ static void *pri_dchannel(void *vpri)
 					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
+				chanpos = pri_find_principle_by_call(pri, e->hangup.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
 					/*
 					 * Continue hanging up the call even though
-					 * it is on an unconfigured channel.
+					 * we do not remember it (if we ever did).
 					 */
 					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
-					if (chanpos > -1) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
-							e->hangup.subcmds, e->hangup.call);
-						if (!pri->pvts[chanpos]->alreadyhungup) {
-							/* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
-							pri->pvts[chanpos]->alreadyhungup = 1;
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
+					e->hangup.subcmds, e->hangup.call);
+				switch (e->hangup.cause) {
+				case PRI_CAUSE_INVALID_CALL_REFERENCE:
+					/*
+					 * The peer denies the existence of this call so we must
+					 * continue hanging it up and forget about it.
+					 */
+					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+					pri->pvts[chanpos]->call = NULL;
+					break;
+				default:
+					break;
+				}
+				if (!pri->pvts[chanpos]->alreadyhungup) {
+					/* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
+					pri->pvts[chanpos]->alreadyhungup = 1;
+					switch (e->hangup.cause) {
+					case PRI_CAUSE_USER_BUSY:
+					case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+						sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+						break;
+					default:
+						break;
+					}
+					if (pri->pvts[chanpos]->owner) {
+						int do_hangup = 0;
+
+						/* Queue a BUSY instead of a hangup if our cause is appropriate */
+						pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
+						switch (pri->pvts[chanpos]->owner->_state) {
+						case AST_STATE_BUSY:
+						case AST_STATE_UP:
+							do_hangup = 1;
+							break;
+						default:
+							if (!pri->pvts[chanpos]->outgoing) {
+								/*
+								 * The incoming call leg hung up before getting
+								 * connected so just hangup the call.
+								 */
+								do_hangup = 1;
+								break;
+							}
 							switch (e->hangup.cause) {
 							case PRI_CAUSE_USER_BUSY:
+								pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
+								break;
+							case PRI_CAUSE_CALL_REJECTED:
+							case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
 							case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-								sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+							case PRI_CAUSE_SWITCH_CONGESTION:
+							case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
+							case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
+								pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
 								break;
 							default:
+								do_hangup = 1;
 								break;
 							}
-							if (pri->pvts[chanpos]->owner) {
-								int do_hangup = 0;
-								/* Queue a BUSY instead of a hangup if our cause is appropriate */
-								pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
-								switch (pri->pvts[chanpos]->owner->_state) {
-								case AST_STATE_BUSY:
-								case AST_STATE_UP:
-									do_hangup = 1;
-									break;
-								default:
-									if (!pri->pvts[chanpos]->outgoing) {
-										/*
-										 * The incoming call leg hung up before getting
-										 * connected so just hangup the call.
-										 */
-										do_hangup = 1;
-										break;
-									}
-									switch (e->hangup.cause) {
-									case PRI_CAUSE_USER_BUSY:
-										pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
-										break;
-									case PRI_CAUSE_CALL_REJECTED:
-									case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
-									case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-									case PRI_CAUSE_SWITCH_CONGESTION:
-									case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
-									case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
-										pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
-										break;
-									default:
-										do_hangup = 1;
-										break;
-									}
-									break;
-								}
+							break;
+						}
 
-								if (do_hangup) {
+						if (do_hangup) {
 #if defined(HAVE_PRI_AOC_EVENTS)
-									if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-										/* If a AOC-E msg was sent during the release, we must use a
-										 * AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
-										pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-									} else {
-										pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-									}
-#else
-									pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-								}
+							if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
+								/* If a AOC-E msg was sent during the release, we must use a
+								 * AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
+								pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
 							} else {
-								/*
-								 * Continue hanging up the call even though
-								 * we do not have an owner.
-								 */
-								pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
-								pri->pvts[chanpos]->call = NULL;
-							}
-							ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
-								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
-						} else {
-							/* Continue hanging up the call. */
-							pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
-							pri->pvts[chanpos]->call = NULL;
-						}
-						if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
-							ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
-								PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
-							pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
-							pri->pvts[chanpos]->resetting = 1;
-						}
-						if (e->hangup.aoc_units > -1)
-							ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
-								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
-
-#ifdef SUPPORT_USERUSER
-						if (!ast_strlen_zero(e->hangup.useruserinfo)) {
-							struct ast_channel *owner;
-
-							sig_pri_lock_owner(pri, chanpos);
-							owner = pri->pvts[chanpos]->owner;
-							if (owner) {
-								pbx_builtin_setvar_helper(owner, "USERUSERINFO",
-									e->hangup.useruserinfo);
-								ast_channel_unlock(owner);
+								pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 							}
+#else
+							pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 						}
-#endif
-
-						sig_pri_unlock_private(pri->pvts[chanpos]);
 					} else {
 						/*
 						 * Continue hanging up the call even though
-						 * we do not remember it (if we ever did).
+						 * we do not have an owner.
 						 */
-						pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+						pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+						pri->pvts[chanpos]->call = NULL;
 					}
+					ast_verb(3, "Span %d: Channel %d/%d got hangup, cause %d\n",
+						pri->span, pri->pvts[chanpos]->logicalspan,
+						pri->pvts[chanpos]->prioffset, e->hangup.cause);
+				} else {
+					/* Continue hanging up the call. */
+					pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+					pri->pvts[chanpos]->call = NULL;
 				}
+#if defined(FORCE_RESTART_UNAVAIL_CHANS)
+				if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
+					&& pri->sig != SIG_BRI_PTMP && !pri->resetting
+					&& !pri->pvts[chanpos]->resetting) {
+					ast_verb(3,
+						"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
+						pri->span, pri->pvts[chanpos]->logicalspan,
+						pri->pvts[chanpos]->prioffset);
+					pri->pvts[chanpos]->resetting = 1;
+					pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+				}
+#endif	/* defined(FORCE_RESTART_UNAVAIL_CHANS) */
+				if (e->hangup.aoc_units > -1)
+					ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
+						pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
+
+#ifdef SUPPORT_USERUSER
+				if (!ast_strlen_zero(e->hangup.useruserinfo)) {
+					struct ast_channel *owner;
+
+					sig_pri_lock_owner(pri, chanpos);
+					owner = pri->pvts[chanpos]->owner;
+					if (owner) {
+						pbx_builtin_setvar_helper(owner, "USERUSERINFO",
+							e->hangup.useruserinfo);
+						ast_channel_unlock(owner);
+					}
+				}
+#endif
+
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				sig_pri_span_devstate_changed(pri);
 				break;
 			case PRI_EVENT_HANGUP_REQ:
 				if (sig_pri_is_cis_call(e->hangup.channel)) {
@@ -6485,136 +6654,143 @@ static void *pri_dchannel(void *vpri)
 					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
+				chanpos = pri_find_principle_by_call(pri, e->hangup.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
 					/*
 					 * Continue hanging up the call even though
-					 * it is on an unconfigured channel.
+					 * we do not remember it (if we ever did).
 					 */
 					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
-					if (chanpos > -1) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
-							e->hangup.subcmds, e->hangup.call);
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
+					e->hangup.subcmds, e->hangup.call);
 #if defined(HAVE_PRI_CALL_HOLD)
-						if (e->hangup.call_active && e->hangup.call_held
-							&& pri->hold_disconnect_transfer) {
-							/* We are to transfer the call instead of simply hanging up. */
-							sig_pri_unlock_private(pri->pvts[chanpos]);
-							if (!sig_pri_attempt_transfer(pri, e->hangup.call_held, 1,
-								e->hangup.call_active, 0, NULL, NULL)) {
-								break;
-							}
-							sig_pri_lock_private(pri->pvts[chanpos]);
-						}
+				if (e->hangup.call_active && e->hangup.call_held
+					&& pri->hold_disconnect_transfer) {
+					/* We are to transfer the call instead of simply hanging up. */
+					sig_pri_unlock_private(pri->pvts[chanpos]);
+					if (!sig_pri_attempt_transfer(pri, e->hangup.call_held, 1,
+						e->hangup.call_active, 0, NULL, NULL)) {
+						break;
+					}
+					sig_pri_lock_private(pri->pvts[chanpos]);
+				}
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
+				switch (e->hangup.cause) {
+				case PRI_CAUSE_USER_BUSY:
+				case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+					sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+					break;
+				case PRI_CAUSE_INVALID_CALL_REFERENCE:
+					/*
+					 * The peer denies the existence of this call so we must
+					 * continue hanging it up and forget about it.  We should not
+					 * get this cause here, but for completeness we will handle it
+					 * anyway.
+					 */
+					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+					pri->pvts[chanpos]->call = NULL;
+					break;
+				default:
+					break;
+				}
+				if (pri->pvts[chanpos]->owner) {
+					int do_hangup = 0;
+
+					pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
+					switch (pri->pvts[chanpos]->owner->_state) {
+					case AST_STATE_BUSY:
+					case AST_STATE_UP:
+						do_hangup = 1;
+						break;
+					default:
+						if (!pri->pvts[chanpos]->outgoing) {
+							/*
+							 * The incoming call leg hung up before getting
+							 * connected so just hangup the call.
+							 */
+							do_hangup = 1;
+							break;
+						}
 						switch (e->hangup.cause) {
 						case PRI_CAUSE_USER_BUSY:
+							pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
+							break;
+						case PRI_CAUSE_CALL_REJECTED:
+						case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
 						case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-							sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+						case PRI_CAUSE_SWITCH_CONGESTION:
+						case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
+						case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
+							pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
 							break;
 						default:
+							do_hangup = 1;
 							break;
 						}
-						if (pri->pvts[chanpos]->owner) {
-							int do_hangup = 0;
-
-							pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
-							switch (pri->pvts[chanpos]->owner->_state) {
-							case AST_STATE_BUSY:
-							case AST_STATE_UP:
-								do_hangup = 1;
-								break;
-							default:
-								if (!pri->pvts[chanpos]->outgoing) {
-									/*
-									 * The incoming call leg hung up before getting
-									 * connected so just hangup the call.
-									 */
-									do_hangup = 1;
-									break;
-								}
-								switch (e->hangup.cause) {
-								case PRI_CAUSE_USER_BUSY:
-									pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
-									break;
-								case PRI_CAUSE_CALL_REJECTED:
-								case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
-								case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
-								case PRI_CAUSE_SWITCH_CONGESTION:
-								case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
-								case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
-									pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
-									break;
-								default:
-									do_hangup = 1;
-									break;
-								}
-								break;
-							}
+						break;
+					}
 
-							if (do_hangup) {
+					if (do_hangup) {
 #if defined(HAVE_PRI_AOC_EVENTS)
-								if (!pri->pvts[chanpos]->holding_aoce
-									&& pri->aoce_delayhangup
-									&& ast_bridged_channel(pri->pvts[chanpos]->owner)) {
-									sig_pri_send_aoce_termination_request(pri, chanpos,
-										pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
-								} else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-									/* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
-									 * to guarantee that frame gets read before hangup */
-									pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-								} else {
-									pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-								}
-#else
-								pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-							}
-							ast_verb(3, "Channel %d/%d, span %d got hangup request, cause %d\n",
-								PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
+						if (!pri->pvts[chanpos]->holding_aoce
+							&& pri->aoce_delayhangup
+							&& ast_bridged_channel(pri->pvts[chanpos]->owner)) {
+							sig_pri_send_aoce_termination_request(pri, chanpos,
+								pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
+						} else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
+							/* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
+							 * to guarantee that frame gets read before hangup */
+							pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
 						} else {
-							/*
-							 * Continue hanging up the call even though
-							 * we do not have an owner.
-							 */
-							pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
-							pri->pvts[chanpos]->call = NULL;
-						}
-						if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
-							ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
-								PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
-							pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
-							pri->pvts[chanpos]->resetting = 1;
+							pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 						}
+#else
+						pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+					}
+					ast_verb(3, "Span %d: Channel %d/%d got hangup request, cause %d\n",
+						pri->span, pri->pvts[chanpos]->logicalspan,
+						pri->pvts[chanpos]->prioffset, e->hangup.cause);
+				} else {
+					/*
+					 * Continue hanging up the call even though
+					 * we do not have an owner.
+					 */
+					pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+					pri->pvts[chanpos]->call = NULL;
+				}
+#if defined(FORCE_RESTART_UNAVAIL_CHANS)
+				if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
+					&& pri->sig != SIG_BRI_PTMP && !pri->resetting
+					&& !pri->pvts[chanpos]->resetting) {
+					ast_verb(3,
+						"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
+						pri->span, pri->pvts[chanpos]->logicalspan,
+						pri->pvts[chanpos]->prioffset);
+					pri->pvts[chanpos]->resetting = 1;
+					pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+				}
+#endif	/* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 
 #ifdef SUPPORT_USERUSER
-						if (!ast_strlen_zero(e->hangup.useruserinfo)) {
-							struct ast_channel *owner;
-
-							sig_pri_lock_owner(pri, chanpos);
-							owner = pri->pvts[chanpos]->owner;
-							if (owner) {
-								pbx_builtin_setvar_helper(owner, "USERUSERINFO",
-									e->hangup.useruserinfo);
-								ast_channel_unlock(owner);
-							}
-						}
-#endif
+				if (!ast_strlen_zero(e->hangup.useruserinfo)) {
+					struct ast_channel *owner;
 
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-					} else {
-						/*
-						 * Continue hanging up the call even though
-						 * we do not remember it (if we ever did).
-						 */
-						pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+					sig_pri_lock_owner(pri, chanpos);
+					owner = pri->pvts[chanpos]->owner;
+					if (owner) {
+						pbx_builtin_setvar_helper(owner, "USERUSERINFO",
+							e->hangup.useruserinfo);
+						ast_channel_unlock(owner);
 					}
 				}
+#endif
+
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				sig_pri_span_devstate_changed(pri);
 				break;
 			case PRI_EVENT_HANGUP_ACK:
 				if (sig_pri_is_cis_call(e->hangup.channel)) {
@@ -6622,35 +6798,31 @@ static void *pri_dchannel(void *vpri)
 						e->hangup.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
+				chanpos = pri_find_principle_by_call(pri, e->hangup.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
-						PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
-					if (chanpos > -1) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						pri->pvts[chanpos]->call = NULL;
-						pri->pvts[chanpos]->resetting = 0;
-						if (pri->pvts[chanpos]->owner) {
-							ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
-						}
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				pri->pvts[chanpos]->call = NULL;
+				if (pri->pvts[chanpos]->owner) {
+					ast_verb(3, "Span %d: Channel %d/%d got hangup ACK\n", pri->span,
+						pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset);
+				}
 #ifdef SUPPORT_USERUSER
-						if (!ast_strlen_zero(e->hangup.useruserinfo)) {
-							struct ast_channel *owner;
+				if (!ast_strlen_zero(e->hangup.useruserinfo)) {
+					struct ast_channel *owner;
 
-							sig_pri_lock_owner(pri, chanpos);
-							owner = pri->pvts[chanpos]->owner;
-							if (owner) {
-								pbx_builtin_setvar_helper(owner, "USERUSERINFO",
-									e->hangup.useruserinfo);
-								ast_channel_unlock(owner);
-							}
-						}
-#endif
-						sig_pri_unlock_private(pri->pvts[chanpos]);
+					sig_pri_lock_owner(pri, chanpos);
+					owner = pri->pvts[chanpos]->owner;
+					if (owner) {
+						pbx_builtin_setvar_helper(owner, "USERUSERINFO",
+							e->hangup.useruserinfo);
+						ast_channel_unlock(owner);
 					}
 				}
+#endif
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				sig_pri_span_devstate_changed(pri);
 				break;
 			case PRI_EVENT_CONFIG_ERR:
 				ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->span, e->err.err);
@@ -6665,16 +6837,22 @@ static void *pri_dchannel(void *vpri)
 						if (pri->pvts[x] && pri->pvts[x]->resetting) {
 							chanpos = x;
 							sig_pri_lock_private(pri->pvts[chanpos]);
-							ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan,
-								pri->pvts[chanpos]->prioffset, pri->span);
+							ast_debug(1,
+								"Span %d: Assuming restart ack is for channel %d/%d\n",
+								pri->span, pri->pvts[chanpos]->logicalspan,
+								pri->pvts[chanpos]->prioffset);
 							if (pri->pvts[chanpos]->owner) {
-								ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan,
-									pri->pvts[chanpos]->prioffset, pri->span);
+								ast_log(LOG_WARNING,
+									"Span %d: Got restart ack on channel %d/%d with owner\n",
+									pri->span, pri->pvts[chanpos]->logicalspan,
+									pri->pvts[chanpos]->prioffset);
 								pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 							}
 							pri->pvts[chanpos]->resetting = 0;
-							ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
-								pri->pvts[chanpos]->prioffset, pri->span);
+							ast_verb(3,
+								"Span %d: Channel %d/%d successfully restarted\n",
+								pri->span, pri->pvts[chanpos]->logicalspan,
+								pri->pvts[chanpos]->prioffset);
 							sig_pri_unlock_private(pri->pvts[chanpos]);
 							if (pri->resetting)
 								pri_check_restart(pri);
@@ -6682,24 +6860,28 @@ static void *pri_dchannel(void *vpri)
 						}
 					}
 					if (chanpos < 0) {
-						ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n",
-							PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
+						ast_log(LOG_WARNING,
+							"Span %d: Restart ACK on strange channel %d/%d\n",
+							pri->span, PRI_SPAN(e->restartack.channel),
+							PRI_CHANNEL(e->restartack.channel));
 					}
 				} else {
-					if (pri->pvts[chanpos]) {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						if (pri->pvts[chanpos]->owner) {
-							ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
-								PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
-							pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
-						}
-						pri->pvts[chanpos]->resetting = 0;
-						ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
-							pri->pvts[chanpos]->prioffset, pri->span);
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-						if (pri->resetting)
-							pri_check_restart(pri);
+					sig_pri_lock_private(pri->pvts[chanpos]);
+					if (pri->pvts[chanpos]->owner) {
+						ast_log(LOG_WARNING,
+							"Span %d: Got restart ack on channel %d/%d with owner\n",
+							pri->span, pri->pvts[chanpos]->logicalspan,
+							pri->pvts[chanpos]->prioffset);
+						pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 					}
+					pri->pvts[chanpos]->resetting = 0;
+					ast_verb(3,
+						"Span %d: Channel %d/%d successfully restarted\n",
+						pri->span, pri->pvts[chanpos]->logicalspan,
+						pri->pvts[chanpos]->prioffset);
+					sig_pri_unlock_private(pri->pvts[chanpos]);
+					if (pri->resetting)
+						pri_check_restart(pri);
 				}
 				break;
 			case PRI_EVENT_SETUP_ACK:
@@ -6708,47 +6890,40 @@ static void *pri_dchannel(void *vpri)
 						e->setup_ack.call);
 					break;
 				}
-				chanpos = pri_find_principle(pri, e->setup_ack.channel, e->setup_ack.call);
+				chanpos = pri_find_fixup_principle(pri, e->setup_ack.channel,
+					e->setup_ack.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
-					if (chanpos > -1) {
-						unsigned int len;
-
-						sig_pri_lock_private(pri->pvts[chanpos]);
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.channel,
-							e->setup_ack.subcmds, e->setup_ack.call);
-						if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_OVERLAP) {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
-						}
+					break;
+				}
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.channel,
+					e->setup_ack.subcmds, e->setup_ack.call);
+				if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_OVERLAP) {
+					pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
+				}
 
-						/* Send any queued digits */
-						len = strlen(pri->pvts[chanpos]->dialdest);
-						for (x = 0; x < len; ++x) {
-							ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
-							pri_information(pri->pri, pri->pvts[chanpos]->call,
-								pri->pvts[chanpos]->dialdest[x]);
-						}
+				/* Send any queued digits */
+				len = strlen(pri->pvts[chanpos]->dialdest);
+				for (x = 0; x < len; ++x) {
+					ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
+					pri_information(pri->pri, pri->pvts[chanpos]->call,
+						pri->pvts[chanpos]->dialdest[x]);
+				}
 
-						if (!pri->pvts[chanpos]->progress
-							&& (pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)
-							&& !pri->pvts[chanpos]->digital
-							&& !pri->pvts[chanpos]->no_b_channel) {
-							/*
-							 * Call has a channel.
-							 * Indicate for overlap dialing that dialtone may be present.
-							 */
-							pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
-							pri->pvts[chanpos]->progress = 1;/* Claim to have seen inband-information */
-							sig_pri_set_dialing(pri->pvts[chanpos], 0);
-							sig_pri_open_media(pri->pvts[chanpos]);
-						}
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-					} else
-						ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
+				if (!pri->pvts[chanpos]->progress
+					&& (pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)
+					&& !pri->pvts[chanpos]->digital
+					&& !pri->pvts[chanpos]->no_b_channel) {
+					/*
+					 * Call has a channel.
+					 * Indicate for overlap dialing that dialtone may be present.
+					 */
+					pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
+					pri->pvts[chanpos]->progress = 1;/* Claim to have seen inband-information */
+					sig_pri_set_dialing(pri->pvts[chanpos], 0);
+					sig_pri_open_media(pri->pvts[chanpos]);
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 			case PRI_EVENT_NOTIFY:
 				if (sig_pri_is_cis_call(e->notify.channel)) {
@@ -6761,36 +6936,46 @@ static void *pri_dchannel(void *vpri)
 					break;
 				}
 #if defined(HAVE_PRI_CALL_HOLD)
-				chanpos = pri_find_principle(pri, e->notify.channel, e->notify.call);
+				chanpos = pri_find_principle_by_call(pri, e->notify.call);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "Span %d: Received NOTIFY for unknown call.\n",
+						pri->span);
+					break;
+				}
 #else
+				/*
+				 * This version of libpri does not supply a call pointer for
+				 * this message.  We are just going to have to trust that the
+				 * correct principle is found.
+				 */
 				chanpos = pri_find_principle(pri, e->notify.channel, NULL);
-#endif	/* !defined(HAVE_PRI_CALL_HOLD) */
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
 						PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
-				} else {
-					sig_pri_lock_private(pri->pvts[chanpos]);
+					break;
+				}
+#endif	/* !defined(HAVE_PRI_CALL_HOLD) */
+				sig_pri_lock_private(pri->pvts[chanpos]);
 #if defined(HAVE_PRI_CALL_HOLD)
-					sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
-						e->notify.subcmds, e->notify.call);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
+					e->notify.subcmds, e->notify.call);
 #else
-					sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
-						e->notify.subcmds, NULL);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
+					e->notify.subcmds, NULL);
 #endif	/* !defined(HAVE_PRI_CALL_HOLD) */
-					switch (e->notify.info) {
-					case PRI_NOTIFY_REMOTE_HOLD:
-						if (!pri->discardremoteholdretrieval) {
-							pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
-						}
-						break;
-					case PRI_NOTIFY_REMOTE_RETRIEVAL:
-						if (!pri->discardremoteholdretrieval) {
-							pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
-						}
-						break;
+				switch (e->notify.info) {
+				case PRI_NOTIFY_REMOTE_HOLD:
+					if (!pri->discardremoteholdretrieval) {
+						pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
 					}
-					sig_pri_unlock_private(pri->pvts[chanpos]);
+					break;
+				case PRI_NOTIFY_REMOTE_RETRIEVAL:
+					if (!pri->discardremoteholdretrieval) {
+						pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
+					}
+					break;
 				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
 #if defined(HAVE_PRI_CALL_HOLD)
 			case PRI_EVENT_HOLD:
@@ -6860,7 +7045,6 @@ void sig_pri_init_pri(struct sig_pri_span *pri)
 
 int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
 {
-	int res;
 #ifdef SUPPORT_USERUSER
 	const char *useruser = pbx_builtin_getvar_helper(ast, "USERUSERINFO");
 #endif
@@ -6871,7 +7055,6 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
 		return 0;
 	}
 
-	p->owner = NULL;
 	p->outgoing = 0;
 	sig_pri_set_digital(p, 0);	/* push up to parent for EC*/
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -6890,60 +7073,59 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
 	sig_pri_set_dialing(p, 0);
 
 	/* Make sure we have a call (or REALLY have a call in the case of a PRI) */
-	if (!pri_grab(p, p->pri)) {
-		sig_pri_moh_fsm_event(ast, p, SIG_PRI_MOH_EVENT_RESET);
-		if (p->call) {
-			if (p->alreadyhungup) {
-				ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
+	pri_grab(p, p->pri);
+	sig_pri_moh_fsm_event(ast, p, SIG_PRI_MOH_EVENT_RESET);
+	if (p->call) {
+		if (p->alreadyhungup) {
+			ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
-				pri_call_set_useruser(p->call, useruser);
+			pri_call_set_useruser(p->call, useruser);
 #endif
 
 #if defined(HAVE_PRI_AOC_EVENTS)
-				if (p->holding_aoce) {
-					pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
-				}
+			if (p->holding_aoce) {
+				pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
+			}
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-				pri_hangup(p->pri->pri, p->call, -1);
-				p->call = NULL;
-			} else {
-				const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
-				int icause = ast->hangupcause ? ast->hangupcause : -1;
-				ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
+			pri_hangup(p->pri->pri, p->call, -1);
+			p->call = NULL;
+		} else {
+			const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
+			int icause = ast->hangupcause ? ast->hangupcause : -1;
+			ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
-				pri_call_set_useruser(p->call, useruser);
+			pri_call_set_useruser(p->call, useruser);
 #endif
 
-				p->alreadyhungup = 1;
-				if (cause) {
-					if (atoi(cause))
-						icause = atoi(cause);
-				}
+			p->alreadyhungup = 1;
+			if (cause) {
+				if (atoi(cause))
+					icause = atoi(cause);
+			}
 #if defined(HAVE_PRI_AOC_EVENTS)
-				if (p->holding_aoce) {
-					pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
-				}
-#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-				pri_hangup(p->pri->pri, p->call, icause);
+			if (p->holding_aoce) {
+				pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
 			}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+			pri_hangup(p->pri->pri, p->call, icause);
 		}
-		sig_pri_span_devstate_changed(p->pri);
-		pri_rel(p->pri);
-		res = 0;
-	} else {
-		ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
-		res = -1;
 	}
-
 #if defined(HAVE_PRI_AOC_EVENTS)
 	p->aoc_s_request_invoke_id_valid = 0;
 	p->holding_aoce = 0;
 	p->waiting_for_aoce = 0;
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+	p->allocated = 0;
+	p->owner = NULL;
+
+	sig_pri_span_devstate_changed(p->pri);
+	pri_rel(p->pri);
+
 	ast->tech_pvt = NULL;
-	return res;
+	return 0;
 }
 
 /*!
@@ -7807,16 +7989,10 @@ int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast)
 static int sig_pri_available_check(struct sig_pri_chan *pvt)
 {
 	/*
-	 * If no owner, interface has a B channel, not resetting, not already with call,
-	 * not in alarm, and in-service then available.
+	 * If interface has a B channel and is available for use
+	 * then the channel is available.
 	 */
-	if (!pvt->owner && !pvt->no_b_channel && !pvt->resetting && !pvt->call
-		&& !pvt->inalarm) {
-#if defined(HAVE_PRI_SERVICE_MESSAGES)
-		if (pvt->service_status) {
-			return 0;
-		}
-#endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
+	if (!pvt->no_b_channel && sig_pri_is_chan_available(pvt)) {
 		return 1;
 	}
 	return 0;
@@ -7830,6 +8006,8 @@ static int sig_pri_available_check(struct sig_pri_chan *pvt)
  *
  * \param pri PRI span control structure.
  *
+ * \note Assumes the pri->lock is already obtained.
+ *
  * \retval cw Call waiting interface to use.
  * \retval NULL if no call waiting interface available.
  */
@@ -7839,7 +8017,6 @@ static struct sig_pri_chan *sig_pri_cw_available(struct sig_pri_span *pri)
 	int idx;
 
 	cw = NULL;
-	ast_mutex_lock(&pri->lock);
 	if (pri->num_call_waiting_calls < pri->max_call_waiting_calls) {
 		if (!pri->num_call_waiting_calls) {
 			/*
@@ -7850,7 +8027,6 @@ static struct sig_pri_chan *sig_pri_cw_available(struct sig_pri_span *pri)
 			for (idx = 0; idx < pri->numchans; ++idx) {
 				if (pri->pvts[idx] && sig_pri_available_check(pri->pvts[idx])) {
 					/* There is another channel that is available on this span. */
-					ast_mutex_unlock(&pri->lock);
 					return cw;
 				}
 			}
@@ -7864,7 +8040,6 @@ static struct sig_pri_chan *sig_pri_cw_available(struct sig_pri_span *pri)
 			ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, 1);
 		}
 	}
-	ast_mutex_unlock(&pri->lock);
 	return cw;
 }
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
@@ -7872,12 +8047,15 @@ static struct sig_pri_chan *sig_pri_cw_available(struct sig_pri_span *pri)
 int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
 {
 	struct sig_pri_chan *p = *pvt;
+	struct sig_pri_span *pri;
 
 	if (!p->pri) {
 		/* Something is wrong here.  A PRI channel without the pri pointer? */
 		return 0;
 	}
+	pri = p->pri;
 
+	ast_mutex_lock(&pri->lock);
 	if (
 #if defined(HAVE_PRI_CALL_WAITING)
 		/*
@@ -7886,9 +8064,11 @@ int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
 		 * want new calls to steal a B channel
 		 * freed for an earlier call waiting call.
 		 */
-		!p->pri->num_call_waiting_calls &&
+		!pri->num_call_waiting_calls &&
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
 		sig_pri_available_check(p)) {
+		p->allocated = 1;
+		ast_mutex_unlock(&pri->lock);
 		return 1;
 	}
 
@@ -7896,14 +8076,17 @@ int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel)
 	if (!is_specific_channel) {
 		struct sig_pri_chan *cw;
 
-		cw = sig_pri_cw_available(p->pri);
+		cw = sig_pri_cw_available(pri);
 		if (cw) {
 			/* We have a call waiting interface to use instead. */
+			cw->allocated = 1;
 			*pvt = cw;
+			ast_mutex_unlock(&pri->lock);
 			return 1;
 		}
 	}
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
+	ast_mutex_unlock(&pri->lock);
 	return 0;
 }
 
@@ -8303,28 +8486,34 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
 	return 0;
 }
 
+/*!
+ * \brief Notify new alarm status.
+ *
+ * \param p Channel private pointer.
+ * \param noalarm Non-zero if not in alarm mode.
+ * 
+ * \note Assumes the sig_pri_lock_private(p) is already obtained.
+ *
+ * \return Nothing
+ */
 void sig_pri_chan_alarm_notify(struct sig_pri_chan *p, int noalarm)
 {
+	pri_grab(p, p->pri);
+	p->resetting = 0;
 	sig_pri_set_alarm(p, !noalarm);
 	if (!noalarm) {
-		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) {
-					if (!pri_grab(p, p->pri)) {
-						pri_hangup(p->pri->pri, p->call, -1);
-						pri_destroycall(p->pri->pri, p->call);
-						p->call = NULL;
-						pri_rel(p->pri);
-					} else
-						ast_log(LOG_WARNING, "Failed to grab PRI!\n");
-				} else
-					ast_log(LOG_WARNING, "The PRI Call has 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_span_devstate_changed(p->pri);
+	pri_rel(p->pri);
 }
 
 struct sig_pri_chan *sig_pri_chan_new(void *pvt_data, struct sig_pri_callback *callback, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup)
@@ -8360,12 +8549,12 @@ void sig_pri_chan_delete(struct sig_pri_chan *doomed)
 	ast_free(doomed);
 }
 
-#define SIG_PRI_SC_HEADER	"%-4s %4s %-4s %-10s %-4s %s\n"
-#define SIG_PRI_SC_LINE		"%4d %4d %-4s %-10s %-4s %s"
+#define SIG_PRI_SC_HEADER	"%-4s %4s %-4s %-4s %-10s %-4s %s\n"
+#define SIG_PRI_SC_LINE		 "%4d %4d %-4s %-4s %-10s %-4s %s"
 void sig_pri_cli_show_channels_header(int fd)
 {
-	ast_cli(fd, SIG_PRI_SC_HEADER, "PRI",  "",     "B",    "Call",  "PRI",  "Channel");
-	ast_cli(fd, SIG_PRI_SC_HEADER, "Span", "Chan", "Chan", "Level", "Call", "Name");
+	ast_cli(fd, SIG_PRI_SC_HEADER, "PRI",  "",     "B",    "Chan", "Call",  "PRI",  "Channel");
+	ast_cli(fd, SIG_PRI_SC_HEADER, "Span", "Chan", "Chan", "Idle", "Level", "Call", "Name");
 }
 
 void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri)
@@ -8382,7 +8571,7 @@ void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri)
 		pvt = pri->pvts[idx];
 		sig_pri_lock_private(pvt);
 		sig_pri_lock_owner(pri, idx);
-		if (pvt->no_b_channel && !pvt->call && !pvt->owner) {
+		if (pvt->no_b_channel && sig_pri_is_chan_available(pvt)) {
 			/* Don't show held/call-waiting channels if they are not in use. */
 			sig_pri_unlock_private(pvt);
 			continue;
@@ -8392,6 +8581,7 @@ void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri)
 			pri->span,
 			pvt->channel,
 			pvt->no_b_channel ? "No" : "Yes",/* Has media */
+			sig_pri_is_chan_available(pvt) ? "Yes" : "No",
 			sig_pri_call_level2str(pvt->call_level),
 			pvt->call ? "Yes" : "No",
 			pvt->owner ? pvt->owner->name : "");
diff --git a/channels/sig_pri.h b/channels/sig_pri.h
index f4aef912d22898abb5aa6bbcaa28b9aa1c31500b..f75646e3ffe60d521eb9e217d047b30c5ed115eb 100644
--- a/channels/sig_pri.h
+++ b/channels/sig_pri.h
@@ -305,6 +305,17 @@ struct sig_pri_chan {
 	unsigned int progress:1;		/*!< TRUE if the call has seen inband-information progress through the network */
 	unsigned int resetting:1;		/*!< TRUE if this channel is being reset/restarted */
 
+	/*!
+	 * \brief TRUE when this channel is allocated.
+	 *
+	 * \details
+	 * Needed to hold an outgoing channel allocation before the
+	 * owner pointer is created.
+	 *
+	 * \note This is one of several items to check to see if a
+	 * channel is available for use.
+	 */
+	unsigned int allocated:1;
 	unsigned int outgoing:1;
 	unsigned int digital:1;
 	/*! \brief TRUE if this interface has no B channel.  (call hold and call waiting) */
@@ -558,6 +569,7 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
 
 int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast);
 
+int sig_pri_is_chan_available(struct sig_pri_chan *pvt);
 int sig_pri_available(struct sig_pri_chan **pvt, int is_specific_channel);
 
 void sig_pri_init_pri(struct sig_pri_span *pri);