Make --with-pjproject-bundled the default for Asterisk 15
[asterisk/asterisk.git] / channels / sig_pri.c
index 57c518c..1b228af 100644 (file)
  */
 //#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. */
@@ -754,15 +745,15 @@ static void sig_pri_set_subaddress(struct ast_party_subaddress *ast_subaddress,
                ptr = cnum;
                len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
                for (x = 0; x < len; ++x) {
-                       ptr += sprintf(ptr, "%02x", (unsigned)pri_subaddress->data[x]);
+                       ptr += sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[x]);
                }
 
                if (pri_subaddress->odd_even_indicator) {
                        /* ODD */
-                       sprintf(ptr, "%01x", (unsigned)((pri_subaddress->data[len]) >> 4));
+                       sprintf(ptr, "%01hhx", (unsigned char)((pri_subaddress->data[len]) >> 4));
                } else {
                        /* EVEN */
-                       sprintf(ptr, "%02x", (unsigned)pri_subaddress->data[len]);
+                       sprintf(ptr, "%02hhx", (unsigned char)pri_subaddress->data[len]);
                }
                ast_subaddress->str = cnum;
        }
@@ -1029,13 +1020,13 @@ static int sig_pri_play_tone(struct sig_pri_chan *p, enum sig_pri_tone tone)
 }
 
 static struct ast_channel *sig_pri_new_ast_channel(struct sig_pri_chan *p, int state,
-       int ulaw, int transfercapability, char *exten,
+       enum sig_pri_law law, int transfercapability, char *exten,
        const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
        struct ast_channel *c;
 
        if (sig_pri_callbacks.new_ast_channel) {
-               c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, ulaw, exten, assignedids, requestor);
+               c = sig_pri_callbacks.new_ast_channel(p->chan_pvt, state, law, exten, assignedids, requestor);
        } else {
                return NULL;
        }
@@ -1376,10 +1367,9 @@ static void sig_pri_queue_unhold(struct sig_pri_span *pri, int chanpos)
 static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
 {
        struct ast_frame f = {AST_FRAME_CONTROL, };
-       struct sig_pri_chan *p = pri->pvts[chanpos];
 
        if (sig_pri_callbacks.queue_control) {
-               sig_pri_callbacks.queue_control(p->chan_pvt, subclass);
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, subclass);
        }
 
        f.subclass.integer = subclass;
@@ -1388,6 +1378,31 @@ static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclas
 
 /*!
  * \internal
+ * \brief Queue a request to hangup control frame onto the owner channel.
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_hangup(struct sig_pri_span *pri, int chanpos)
+{
+       if (sig_pri_callbacks.queue_control) {
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, AST_CONTROL_HANGUP);
+       }
+
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_hangup(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
  * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
  * \since 11
  *
@@ -1452,6 +1467,27 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
 
 /*!
  * \internal
+ * \brief Queue the span for destruction
+ * \since 13.0
+ *
+ * \param pri PRI span control structure.
+ *
+ * Asks the channel driver to queue the span for destruction at a
+ * possibly later time, if (e.g.) locking considerations don't allow
+ * destroying it right now.
+ *
+ * \return Nothing
+ */
+static void pri_destroy_later(struct sig_pri_span *pri)
+{
+       if (!sig_pri_callbacks.destroy_later) {
+               return;
+       }
+       sig_pri_callbacks.destroy_later(pri);
+}
+
+/*!
+ * \internal
  * \brief Kill the call.
  * \since 10.0
  *
@@ -1629,6 +1665,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 #if defined(HAVE_PRI_CALL_WAITING)
                new_chan->is_call_waiting = old_chan->is_call_waiting;
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               new_chan->no_dialed_digits = old_chan->no_dialed_digits;
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
 
 #if defined(HAVE_PRI_AOC_EVENTS)
                old_chan->aoc_s_request_invoke_id_valid = 0;
@@ -1644,6 +1683,9 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal
 #if defined(HAVE_PRI_CALL_WAITING)
                old_chan->is_call_waiting = 0;
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               old_chan->no_dialed_digits = 0;
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
 
                /* More stuff to transfer to the new channel. */
                new_chan->call_level = old_chan->call_level;
@@ -2003,11 +2045,10 @@ static void *do_idle_thread(void *v_pvt)
        int timeout_ms = 30000;
        int ms;
        struct timeval start;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        if ((callid = ast_channel_callid(chan))) {
                ast_callid_threadassoc_add(callid);
-               callid = ast_callid_unref(callid);
        }
 
        ast_verb(3, "Initiating idle call on channel %s\n", ast_channel_name(chan));
@@ -2062,7 +2103,7 @@ static void *pri_ss_thread(void *data)
        int res;
        int len;
        int timeout;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        if (!chan) {
                /* We lost the owner before we could get started. */
@@ -2071,7 +2112,6 @@ static void *pri_ss_thread(void *data)
 
        if ((callid = ast_channel_callid(chan))) {
                ast_callid_threadassoc_add(callid);
-               ast_callid_unref(callid);
        }
 
        /*
@@ -4010,14 +4050,14 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        }
 
        if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
        ast_aoc_set_termination_request(decoded);
 
        if (!(encoded = ast_aoc_encode(decoded, &encoded_size, pvt->owner))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -4026,7 +4066,7 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        whentohangup.tv_sec = ms / 1000;
 
        if (ast_queue_control_data(pvt->owner, AST_CONTROL_AOC, encoded, encoded_size)) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -4270,43 +4310,6 @@ static void sig_pri_handle_cis_subcmds(struct sig_pri_span *pri, int event_id,
        }
 }
 
-#if defined(HAVE_PRI_AOC_EVENTS)
-/*!
- * \internal
- * \brief detect if AOC-S subcmd is present.
- * \since 1.8
- *
- * \param subcmds Subcommands to process if any. (Could be NULL).
- *
- * \note Knowing whether or not an AOC-E subcmd is present on certain
- * PRI hangup events is necessary to determine what method to use to hangup
- * the ast_channel.  If an AOC-E subcmd just came in, then a new AOC-E was queued
- * on the ast_channel.  If a soft hangup is used, the AOC-E msg will never make it
- * across the bridge, but if a AST_CONTROL_HANGUP frame is queued behind it
- * we can ensure the AOC-E frame makes it to it's destination before the hangup
- * frame is read.
- *
- *
- * \retval 0 AOC-E is not present in subcmd list
- * \retval 1 AOC-E is present in subcmd list
- */
-static int detect_aoc_e_subcmd(const struct pri_subcommands *subcmds)
-{
-       int i;
-
-       if (!subcmds) {
-               return 0;
-       }
-       for (i = 0; i < subcmds->counter_subcmd; ++i) {
-               const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
-               if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
-
 /*!
  * \internal
  * \brief Handle the call associated PRI subcommand events.
@@ -4677,7 +4680,7 @@ static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int ev
                                        f.frametype = AST_FRAME_TEXT;
                                        f.subclass.integer = 0;
                                        f.offset = 0;
-                                       f.data.ptr = &subcmd->u.display.text;
+                                       f.data.ptr = (void *)&subcmd->u.display.text;
                                        f.datalen = subcmd->u.display.length + 1;
                                        ast_queue_frame(owner, &f);
                                        ast_channel_unlock(owner);
@@ -5342,13 +5345,12 @@ static void sig_pri_moh_fsm_event(struct ast_channel *chan, struct sig_pri_chan
  * \internal
  * \brief Set callid threadstorage for the pri_dchannel thread when a new call is created
  *
- * \return A new callid which has been bound to threadstorage. The return must be
- *         unreffed and the threadstorage should be unbound when the pri_dchannel
- *         primary loop wraps.
+ * \return A new callid which has been bound to threadstorage. The threadstorage
+ *         should be unbound when the pri_dchannel primary loop wraps.
  */
-static struct ast_callid *func_pri_dchannel_new_callid(void)
+static ast_callid func_pri_dchannel_new_callid(void)
 {
-       struct ast_callid *callid = ast_create_callid();
+       ast_callid callid = ast_create_callid();
 
        if (callid) {
                ast_callid_threadassoc_add(callid);
@@ -5367,20 +5369,18 @@ static struct ast_callid *func_pri_dchannel_new_callid(void)
  * \note Assumes the pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
  *
- * \return a reference to the callid bound to the channel which has also
- *         been bound to threadstorage if it exists. If this returns non-NULL,
- *         the callid must be unreffed and the threadstorage should be unbound
- *         when the pri_dchannel primary loop wraps.
+ * \return The callid which has also been bound to threadstorage if it exists.
+ *         The threadstorage should be unbound when the pri_dchannel primary loop wraps.
  */
-static struct ast_callid *func_pri_dchannel_chanpos_callid(struct sig_pri_span *pri, int chanpos)
+static ast_callid func_pri_dchannel_chanpos_callid(struct sig_pri_span *pri, int chanpos)
 {
        if (chanpos < 0) {
-               return NULL;
+               return 0;
        }
 
        sig_pri_lock_owner(pri, chanpos);
        if (pri->pvts[chanpos]->owner) {
-               struct ast_callid *callid;
+               ast_callid callid;
                callid = ast_channel_callid(pri->pvts[chanpos]->owner);
                ast_channel_unlock(pri->pvts[chanpos]->owner);
                if (callid) {
@@ -5389,7 +5389,7 @@ static struct ast_callid *func_pri_dchannel_chanpos_callid(struct sig_pri_span *
                }
        }
 
-       return NULL;
+       return 0;
 }
 
 #if defined(HAVE_PRI_CALL_HOLD)
@@ -5412,7 +5412,7 @@ static int sig_pri_handle_hold(struct sig_pri_span *pri, pri_event *ev)
        int chanpos_old;
        int chanpos_new;
        struct ast_channel *owner;
-       struct ast_callid *callid = NULL;
+       ast_callid callid = 0;
 
        chanpos_old = pri_find_principle_by_call(pri, ev->hold.call);
        if (chanpos_old < 0) {
@@ -5472,7 +5472,6 @@ done_with_private:;
        }
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 
@@ -5496,7 +5495,7 @@ done_with_private:;
 static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        /*
         * We were successfully put on hold by the remote party
@@ -5528,7 +5527,6 @@ static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_span_devstate_changed(pri);
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -5550,7 +5548,7 @@ static void sig_pri_handle_hold_ack(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        chanpos = pri_find_principle(pri, ev->hold_rej.channel, ev->hold_rej.call);
        if (chanpos < 0) {
@@ -5578,7 +5576,6 @@ static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_unlock_private(pri->pvts[chanpos]);
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -5600,7 +5597,7 @@ static void sig_pri_handle_hold_rej(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        if (!(ev->retrieve.channel & PRI_HELD_CALL)) {
                /* The call is not currently held. */
@@ -5653,7 +5650,6 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_span_devstate_changed(pri);
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -5675,7 +5671,7 @@ static void sig_pri_handle_retrieve(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        chanpos = pri_find_fixup_principle(pri, ev->retrieve_ack.channel,
                ev->retrieve_ack.call);
@@ -5694,7 +5690,6 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_span_devstate_changed(pri);
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -5716,7 +5711,7 @@ static void sig_pri_handle_retrieve_ack(struct sig_pri_span *pri, pri_event *ev)
 static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
 {
        int chanpos;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        chanpos = pri_find_principle(pri, ev->retrieve_rej.channel, ev->retrieve_rej.call);
        if (chanpos < 0) {
@@ -5745,7 +5740,6 @@ static void sig_pri_handle_retrieve_rej(struct sig_pri_span *pri, pri_event *ev)
        sig_pri_unlock_private(pri->pvts[chanpos]);
 
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -5863,9 +5857,9 @@ static void sig_pri_handle_setup(struct sig_pri_span *pri, pri_event *e)
        int exten_exists_or_can_exist;
        int could_match_more;
        int need_dialtone;
-       int law;
+       enum sig_pri_law law;
        int chanpos = -1;
-       struct ast_callid *callid = NULL;
+       ast_callid callid = 0;
        struct ast_channel *c;
        char plancallingnum[AST_MAX_EXTENSION];
        char plancallingani[AST_MAX_EXTENSION];
@@ -6219,7 +6213,6 @@ static void sig_pri_handle_setup(struct sig_pri_span *pri, pri_event *e)
 
 setup_exit:;
        if (callid) {
-               ast_callid_unref(callid);
                ast_callid_threadassoc_remove();
        }
 }
@@ -6267,7 +6260,7 @@ static void *pri_dchannel(void *vpri)
                        ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
        }
        for (;;) {
-               struct ast_callid *callid = NULL;
+               ast_callid callid = 0;
 
                for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
                        if (!pri->dchans[i])
@@ -6330,7 +6323,7 @@ static void *pri_dchannel(void *vpri)
                                         */
                                        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, NULL, 0);
+                                       idle = sig_pri_request(pri->pvts[nextidle], SIG_PRI_ULAW, NULL, NULL, 0);
                                        ast_mutex_lock(&pri->lock);
                                        if (idle) {
                                                pri->pvts[nextidle]->isidlecall = 1;
@@ -6427,6 +6420,14 @@ static void *pri_dchannel(void *vpri)
                                }
                                if (e)
                                        break;
+
+                               if ((errno != 0) && (errno != EINTR)) {
+                                       ast_log(LOG_NOTICE, "pri_check_event returned error %d (%s)\n",
+                                               errno, strerror(errno));
+                               }
+                               if (errno == ENODEV) {
+                                       pri_destroy_later(pri);
+                               }
                        }
                } else if (errno != EINTR)
                        ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
@@ -6544,9 +6545,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri->pvts[chanpos]->call = NULL;
                                                        }
                                                }
-                                               /* Force soft hangup if appropriate */
-                                               if (pri->pvts[chanpos]->owner)
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               /* Force hangup if appropriate */
+                                               sig_pri_queue_hangup(pri, chanpos);
                                                sig_pri_unlock_private(pri->pvts[chanpos]);
                                        }
                                } else {
@@ -6558,8 +6558,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri_destroycall(pri->pri, pri->pvts[x]->call);
                                                                pri->pvts[x]->call = NULL;
                                                        }
-                                                       if (pri->pvts[x]->owner)
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[x]->owner, AST_SOFTHANGUP_DEV);
+                                                       /* Force hangup if appropriate */
+                                                       sig_pri_queue_hangup(pri, x);
                                                        sig_pri_unlock_private(pri->pvts[x]);
                                                }
                                }
@@ -7090,10 +7090,11 @@ static void *pri_dchannel(void *vpri)
                                                break;
                                        }
                                        if (pri->pvts[chanpos]->owner) {
-                                               int do_hangup = 0;
-
                                                snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
                                                pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                                       }
+                                       if (pri->pvts[chanpos]->owner) {
+                                               int do_hangup = 0;
 
                                                /* Queue a BUSY instead of a hangup if our cause is appropriate */
                                                ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
@@ -7131,17 +7132,7 @@ static void *pri_dchannel(void *vpri)
                                                }
 
                                                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 {
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                                       }
-#else
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                                       sig_pri_queue_hangup(pri, chanpos);
                                                }
                                        } else {
                                                /*
@@ -7159,9 +7150,9 @@ static void *pri_dchannel(void *vpri)
                                        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->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7170,7 +7161,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        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");
@@ -7245,10 +7235,11 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                if (pri->pvts[chanpos]->owner) {
-                                       int do_hangup = 0;
-
                                        snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
                                        pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                               }
+                               if (pri->pvts[chanpos]->owner) {
+                                       int do_hangup = 0;
 
                                        ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
                                        switch (ast_channel_state(pri->pvts[chanpos]->owner)) {
@@ -7291,16 +7282,11 @@ static void *pri_dchannel(void *vpri)
                                                        && ast_channel_is_bridged(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 {
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                               }
-#else
-                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               } else
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                               {
+                                                       sig_pri_queue_hangup(pri, chanpos);
+                                               }
                                        }
                                        ast_verb(3, "Span %d: Channel %d/%d got hangup request, cause %d\n",
                                                pri->span, pri->pvts[chanpos]->logicalspan,
@@ -7313,9 +7299,9 @@ static void *pri_dchannel(void *vpri)
                                        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->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7324,7 +7310,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        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)) {
@@ -7489,8 +7474,19 @@ static void *pri_dchannel(void *vpri)
                                         * We explicitly DO NOT want to check PRI_PROG_CALL_NOT_E2E_ISDN
                                         * because it will mess up ISDN to SIP interoperability for
                                         * the ALERTING message.
+                                        *
+                                        * Q.931 Section 5.1.3 says that in scenarios with overlap
+                                        * dialing where no called digits are received and the tone
+                                        * option requires dialtone, the switch MAY send an inband
+                                        * progress indication ie to indicate dialtone presence in
+                                        * the SETUP ACKNOWLEDGE.  Therefore, if we did not send any
+                                        * digits with the SETUP then we must assume that dialtone
+                                        * is present and open the voice path.  Fortunately when
+                                        * interoperating with SIP, we should be sending digits.
                                         */
-                                       && (e->setup_ack.progressmask & PRI_PROG_INBAND_AVAILABLE)
+                                       && ((e->setup_ack.progressmask & PRI_PROG_INBAND_AVAILABLE)
+                                               || pri->inband_on_setup_ack
+                                               || pri->pvts[chanpos]->no_dialed_digits)
 #endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
                                        ) {
                                        /*
@@ -7605,9 +7601,8 @@ static void *pri_dchannel(void *vpri)
                                break;
                        }
 
-                       /* If a callid was set, we need to deref it and remove it from thread storage. */
+                       /* If a callid was set, we need to remove it from thread storage. */
                        if (callid) {
-                               callid = ast_callid_unref(callid);
                                ast_callid_threadassoc_remove();
                        }
                }
@@ -8037,7 +8032,7 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        if (p->pri->facilityenable)
                pri_facility_enable(p->pri->pri);
 
-       ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", (unsigned)ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
+       ast_verb(3, "Requested transfer capability: 0x%02hx - %s\n", ast_channel_transfercapability(ast), ast_transfercapability2str(ast_channel_transfercapability(ast)));
        dp_strip = 0;
        pridialplan = p->pri->dialplan - 1;
        if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
@@ -8120,7 +8115,12 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
        if (!keypad || !ast_strlen_zero(c + p->stripmsd + dp_strip))
 #endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
        {
-               pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
+               char *called = c + p->stripmsd + dp_strip;
+
+               pri_sr_set_called(sr, called, pridialplan, s ? 1 : 0);
+#if defined(HAVE_PRI_SETUP_ACK_INBAND)
+               p->no_dialed_digits = !called[0];
+#endif /* defined(HAVE_PRI_SETUP_ACK_INBAND) */
        }
 
 #if defined(HAVE_PRI_SUBADDR)
@@ -8581,16 +8581,18 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
                                                sig_pri_aoc_e_from_ast(p, decoded);
                                        }
-                                       /* if hangup was delayed for this AOC-E msg, waiting_for_aoc
+                                       /*
+                                        * If hangup was delayed for this AOC-E msg, waiting_for_aoc
                                         * will be set.  A hangup is already occuring via a timeout during
                                         * this delay.  Instead of waiting for that timeout to occur, go ahead
-                                        * and initiate the softhangup since the delay is no longer necessary */
+                                        * and initiate the hangup since the delay is no longer necessary.
+                                        */
                                        if (p->waiting_for_aoce) {
                                                p->waiting_for_aoce = 0;
                                                ast_debug(1,
                                                        "Received final AOC-E msg, continue with hangup on %s\n",
                                                        ast_channel_name(chan));
-                                               ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
+                                               ast_queue_hangup(chan);
                                        }
                                        break;
                                case AST_AOC_REQUEST:
@@ -8976,7 +8978,7 @@ void sig_pri_stop_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
        for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
                if (pri->mbox[idx].sub) {
-                       pri->mbox[idx].sub = stasis_unsubscribe(pri->mbox[idx].sub);
+                       pri->mbox[idx].sub = stasis_unsubscribe_and_join(pri->mbox[idx].sub);
                }
        }
 #endif /* defined(HAVE_PRI_MWI) */
@@ -9123,7 +9125,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
 
                mailbox_specific_topic = ast_mwi_topic(mbox_id);
                if (mailbox_specific_topic) {
-                       pri->mbox[i].sub = stasis_subscribe(mailbox_specific_topic, sig_pri_mwi_event_cb, pri);
+                       pri->mbox[i].sub = stasis_subscribe_pool(mailbox_specific_topic, sig_pri_mwi_event_cb, pri);
                }
                if (!pri->mbox[i].sub) {
                        ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s(%s).\n",