Merged revisions 312575 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Mon, 4 Apr 2011 16:17:58 +0000 (16:17 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Mon, 4 Apr 2011 16:17:58 +0000 (16:17 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r312575 | rmudgett | 2011-04-04 11:10:50 -0500 (Mon, 04 Apr 2011) | 52 lines

  Merged revisions 312574 via svnmerge from
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2

  ................
    r312574 | rmudgett | 2011-04-04 11:00:02 -0500 (Mon, 04 Apr 2011) | 45 lines

    Merged revisions 312573 via svnmerge from
    https://origsvn.digium.com/svn/asterisk/branches/1.4

    ........
      r312573 | rmudgett | 2011-04-04 10:49:30 -0500 (Mon, 04 Apr 2011) | 38 lines

      Issues with ISDN calls changing B channels during call negotiations.

      The handling of the PROCEEDING message was not using the correct call
      structure if the B channel was changed.  (The same for PROGRESS.) The call
      was also not hungup if the new B channel is not provisioned or is busy.

      * Made all call connection messages (SETUP_ACKNOWLEDGE, PROCEEDING,
      PROGRESS, ALERTING, CONNECT, CONNECT_ACKNOWLEDGE) ensure that they are
      using the correct structure and B channel.  If there is any problem with
      the operations then the call is now hungup with an appropriate cause code.

      * Made miscellaneous messages (INFORMATION, FACILITY, NOTIFY) find the
      correct structure by looking for the call and not using the channel ID.
      NOTIFY is an exception with versions of libpri before v1.4.11 because a
      call pointer is not available for Asterisk to use.

      * Made all hangup messages (DISCONNECT, RELEASE, RELEASE_COMPLETE) find
      the correct structure by looking for the call and not using the channel
      ID.

      (closes issue #18313)
      Reported by: destiny6628
      Tested by: rmudgett
      JIRA SWP-2620

      (closes issue #18231)
      Reported by: destiny6628
      Tested by: rmudgett
      JIRA SWP-2924

      (closes issue #18488)
      Reported by: jpokorny
      JIRA SWP-2929

      JIRA AST-437 (The issues fixed here are most likely causing this JIRA issue.)
      JIRA DAHDI-406
      JIRA LIBPRI-33 (Stuck resetting flag likely fixed)
    ........
  ................
................

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@312579 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_pri.c
channels/sig_pri.h

index 3f1d9e0..e1c4a26 100644 (file)
@@ -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);
index f36a7e2..1df3972 100644 (file)
 /* 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. */
@@ -1039,6 +1054,38 @@ static int pri_find_dchan(struct sig_pri_span *pri)
 
 /*!
  * \internal
+ * \brief Determine if a private channel structure is in use.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if in use.
+ *
+ * \return TRUE if the channel is in use.
+ */
+static int sig_pri_is_chan_in_use(struct sig_pri_chan *pvt)
+{
+       return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+}
+
+/*!
+ * \brief Determine if a private channel structure is available.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if available.
+ *
+ * \return TRUE if the channel is available.
+ */
+int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
+{
+       return !sig_pri_is_chan_in_use(pvt)
+#if defined(HAVE_PRI_SERVICE_MESSAGES)
+               /* And not out-of-service */
+               && !pvt->service_status
+#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
+               ;
+}
+
+/*!
+ * \internal
  * \brief Obtain the sig_pri owner channel lock if the owner exists.
  * \since 1.8
  *
@@ -1150,6 +1197,41 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
 
 /*!
  * \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.
  *
  * \param pri PRI span control structure.
@@ -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 : "");
index f4aef91..f75646e 100644 (file)
@@ -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);