memory leaks: Memory leak cleanup patch by Corey Farrell (second set)
[asterisk/asterisk.git] / channels / chan_dahdi.c
index 560fb02..b682994 100644 (file)
  * You need to install libraries before you attempt to compile
  * and install the DAHDI channel.
  *
- * \par See also
- * \arg \ref Config_dahdi
- *
  * \ingroup channel_drivers
  *
  * \todo Deprecate the "musiconhold" configuration option post 1.4
  */
 
+/*! \li \ref chan_dahdi.c uses the configuration file \ref chan_dahdi.conf
+ * \addtogroup configuration_file
+ */
+
+/*! \page chan_dahdi.conf chan_dahdi.conf
+ * \verbinclude chan_dahdi.conf.sample
+ */
+
 /*** MODULEINFO
        <use type="module">res_smdi</use>
        <depend>dahdi</depend>
@@ -57,13 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #include <sys/signal.h>
 #endif
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <math.h>
-#include <ctype.h>
 
-#include <dahdi/user.h>
-#include <dahdi/tonezone.h>
 #include "sig_analog.h"
 /* Analog signaling is currently still present in chan_dahdi for use with
  * radio. Sig_analog does not currently handle any radio operations. If
@@ -71,19 +72,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  * be placed in sig_analog and the duplicated code could be removed.
  */
 
-#ifdef HAVE_PRI
+#if defined(HAVE_PRI)
 #include "sig_pri.h"
+#ifndef PRI_RESTART
+#error "Upgrade your libpri"
 #endif
+#endif /* defined(HAVE_PRI) */
 
 #if defined(HAVE_SS7)
 #include "sig_ss7.h"
+#if defined(LIBSS7_ABI_COMPATIBILITY)
+#error "Your installed libss7 is not compatible"
+#endif
 #endif /* defined(HAVE_SS7) */
 
-#ifdef HAVE_OPENR2
+#if defined(HAVE_OPENR2)
 /* put this here until sig_mfcr2 comes along */
 #define SIG_MFCR2_MAX_CHANNELS 672             /*!< No more than a DS3 per trunk group */
-#include <openr2.h>
-#endif
+#endif /* defined(HAVE_OPENR2) */
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
@@ -96,8 +102,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/adsi.h"
 #include "asterisk/cli.h"
-#include "asterisk/cdr.h"
-#include "asterisk/cel.h"
+#include "asterisk/pickup.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"
@@ -114,11 +119,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/abstract_jb.h"
 #include "asterisk/smdi.h"
 #include "asterisk/astobj.h"
-#include "asterisk/event.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/paths.h"
 #include "asterisk/ccss.h"
 #include "asterisk/data.h"
+#include "asterisk/features_config.h"
+#include "asterisk/bridge.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/parking.h"
+#include "chan_dahdi.h"
+#include "dahdi/bridge_native_dahdi.h"
 
 /*** DOCUMENTATION
        <application name="DAHDISendKeypadFacility" language="en_US">
@@ -284,6 +294,85 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Similar to the CLI command "pri show spans".</para>
                </description>
        </manager>
+       <managerEvent language="en_US" name="AlarmClear">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel on which the alarm was cleared.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="SpanAlarmClear">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
+                       <syntax>
+                               <parameter name="Span">
+                                       <para>The span on which the alarm was cleared.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="DNDState">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel on which DND status changed.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                               <parameter name="Status">
+                                       <enumlist>
+                                               <enum name="enabled"/>
+                                               <enum name="disabled"/>
+                                       </enumlist>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="Alarm">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The channel on which the alarm occurred.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                               <parameter name="Alarm">
+                                       <para>A textual description of the alarm that occurred.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="SpanAlarm">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
+                       <syntax>
+                               <parameter name="Span">
+                                       <para>The span on which the alarm occurred.</para>
+                               </parameter>
+                               <parameter name="Alarm">
+                                       <para>A textual description of the alarm that occurred.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="DAHDIChannel">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
+                       <syntax>
+                               <channel_snapshot/>
+                               <parameter name="DAHDISpan">
+                                       <para>The DAHDI span associated with this channel.</para>
+                               </parameter>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel associated with this channel.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -331,7 +420,7 @@ static struct ast_jb_conf global_jbconf;
 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
 #define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
 
-static const char tdesc[] = "DAHDI Telephony Driver"
+static const char tdesc[] = "DAHDI Telephony"
 #if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
        " w/"
        #if defined(HAVE_PRI)
@@ -354,33 +443,6 @@ static const char tdesc[] = "DAHDI Telephony Driver"
 
 static const char config[] = "chan_dahdi.conf";
 
-#define SIG_EM         DAHDI_SIG_EM
-#define SIG_EMWINK     (0x0100000 | DAHDI_SIG_EM)
-#define SIG_FEATD      (0x0200000 | DAHDI_SIG_EM)
-#define        SIG_FEATDMF     (0x0400000 | DAHDI_SIG_EM)
-#define        SIG_FEATB       (0x0800000 | DAHDI_SIG_EM)
-#define        SIG_E911        (0x1000000 | DAHDI_SIG_EM)
-#define        SIG_FEATDMF_TA  (0x2000000 | DAHDI_SIG_EM)
-#define        SIG_FGC_CAMA    (0x4000000 | DAHDI_SIG_EM)
-#define        SIG_FGC_CAMAMF  (0x8000000 | DAHDI_SIG_EM)
-#define SIG_FXSLS      DAHDI_SIG_FXSLS
-#define SIG_FXSGS      DAHDI_SIG_FXSGS
-#define SIG_FXSKS      DAHDI_SIG_FXSKS
-#define SIG_FXOLS      DAHDI_SIG_FXOLS
-#define SIG_FXOGS      DAHDI_SIG_FXOGS
-#define SIG_FXOKS      DAHDI_SIG_FXOKS
-#define SIG_PRI                DAHDI_SIG_CLEAR
-#define SIG_BRI                (0x2000000 | DAHDI_SIG_CLEAR)
-#define SIG_BRI_PTMP   (0X4000000 | DAHDI_SIG_CLEAR)
-#define SIG_SS7                (0x1000000 | DAHDI_SIG_CLEAR)
-#define SIG_MFCR2      DAHDI_SIG_CAS
-#define        SIG_SF          DAHDI_SIG_SF
-#define SIG_SFWINK     (0x0100000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATD   (0x0200000 | DAHDI_SIG_SF)
-#define        SIG_SF_FEATDMF  (0x0400000 | DAHDI_SIG_SF)
-#define        SIG_SF_FEATB    (0x0800000 | DAHDI_SIG_SF)
-#define SIG_EM_E1      DAHDI_SIG_EM_E1
-
 #ifdef LOTS_OF_SPANS
 #define NUM_SPANS      DAHDI_MAX_SPANS
 #else
@@ -398,6 +460,8 @@ static const char config[] = "chan_dahdi.conf";
 static int num_cadence = 4;
 static int user_has_defined_cadences = 0;
 
+static int has_pseudo;
+
 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
        { { 125, 125, 2000, 4000 } },                   /*!< Quick chirp followed by normal ring */
        { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
@@ -445,7 +509,7 @@ static int mwilevel = 512;
 static int dtmfcid_level = 256;
 
 #define REPORT_CHANNEL_ALARMS 1
-#define REPORT_SPAN_ALARMS    2 
+#define REPORT_SPAN_ALARMS    2
 static int report_alarms = REPORT_CHANNEL_ALARMS;
 
 #ifdef HAVE_PRI
@@ -487,11 +551,9 @@ static int num_restart_pending = 0;
 
 static int restart_monitor(void);
 
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
-
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
-static void mwi_event_cb(const struct ast_event *event, void *userdata)
+static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        /* This module does not handle MWI in an event-based manner.  However, it
         * subscribes to MWI for each mailbox that is configured so that the core
@@ -532,8 +594,7 @@ static inline int dahdi_wait_event(int fd)
 #define CIDCW_EXPIRE_SAMPLES                   ((500 * 8) / READ_SIZE) /*!< 500 ms */
 #define MIN_MS_SINCE_FLASH                             ((2000) )       /*!< 2000 ms */
 #define DEFAULT_RINGT                                  ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
-
-struct dahdi_pvt;
+#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
 
 /*!
  * \brief Configured ring timeout base.
@@ -559,14 +620,6 @@ static int cur_defaultdpc = -1;
 #endif /* defined(HAVE_SS7) */
 
 #ifdef HAVE_OPENR2
-struct dahdi_mfcr2 {
-       pthread_t r2master;                    /*!< Thread of master */
-       openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
-       struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS];     /*!< Member channel pvt structs */
-       int numchans;                          /*!< Number of channels in this R2 block */
-       int monitored_count;                   /*!< Number of channels being monitored */
-};
-
 struct dahdi_mfcr2_conf {
        openr2_variant_t variant;
        int mfback_timeout;
@@ -601,6 +654,15 @@ struct dahdi_mfcr2_conf {
        openr2_calling_party_category_t category;
 };
 
+/* MFC-R2 pseudo-link structure */
+struct dahdi_mfcr2 {
+       pthread_t r2master;                    /*!< Thread of master */
+       openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
+       struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS];     /*!< Member channel pvt structs */
+       int numchans;                          /*!< Number of channels in this R2 block */
+       struct dahdi_mfcr2_conf conf;         /*!< Configuration used to setup this pseudo-link */
+};
+
 /* malloc'd array of malloc'd r2links */
 static struct dahdi_mfcr2 **r2links;
 /* how many r2links have been malloc'd */
@@ -629,628 +691,16 @@ static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
 struct dahdi_pri;
 #endif
 
-#define SUB_REAL       0                       /*!< Active call */
-#define SUB_CALLWAIT   1                       /*!< Call-Waiting call on hold */
-#define SUB_THREEWAY   2                       /*!< Three-way call */
-
 /* Polarity states */
 #define POLARITY_IDLE   0
 #define POLARITY_REV    1
 
-
-struct distRingData {
-       int ring[3];
-       int range;
-};
-struct ringContextData {
-       char contextData[AST_MAX_CONTEXT];
-};
-struct dahdi_distRings {
-       struct distRingData ringnum[3];
-       struct ringContextData ringContext[3];
-};
-
-static const char * const subnames[] = {
+const char * const subnames[] = {
        "Real",
        "Callwait",
        "Threeway"
 };
 
-struct dahdi_subchannel {
-       int dfd;
-       struct ast_channel *owner;
-       int chan;
-       short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
-       struct ast_frame f;             /*!< One frame for each channel.  How did this ever work before? */
-       unsigned int needringing:1;
-       unsigned int needbusy:1;
-       unsigned int needcongestion:1;
-       unsigned int needanswer:1;
-       unsigned int needflash:1;
-       unsigned int needhold:1;
-       unsigned int needunhold:1;
-       unsigned int linear:1;
-       unsigned int inthreeway:1;
-       struct dahdi_confinfo curconf;
-};
-
-#define CONF_USER_REAL         (1 << 0)
-#define CONF_USER_THIRDCALL    (1 << 1)
-
-#define MAX_SLAVES     4
-
-/* States for sending MWI message
- * First three states are required for send Ring Pulse Alert Signal
- */
-typedef enum {
-       MWI_SEND_NULL = 0,
-       MWI_SEND_SA,
-       MWI_SEND_SA_WAIT,
-       MWI_SEND_PAUSE,
-       MWI_SEND_SPILL,
-       MWI_SEND_CLEANUP,
-       MWI_SEND_DONE,
-} mwisend_states;
-
-struct mwisend_info {
-       struct  timeval pause;
-       mwisend_states  mwisend_current;
-};
-
-/*! Specify the lists dahdi_pvt can be put in. */
-enum DAHDI_IFLIST {
-       DAHDI_IFLIST_NONE,      /*!< The dahdi_pvt is not in any list. */
-       DAHDI_IFLIST_MAIN,      /*!< The dahdi_pvt is in the main interface list */
-#if defined(HAVE_PRI)
-       DAHDI_IFLIST_NO_B_CHAN, /*!< The dahdi_pvt is in a no B channel interface list */
-#endif /* defined(HAVE_PRI) */
-};
-
-struct dahdi_pvt {
-       ast_mutex_t lock;                                       /*!< Channel private lock. */
-       struct callerid_state *cs;
-       struct ast_channel *owner;                      /*!< Our current active owner (if applicable) */
-                                                       /*!< Up to three channels can be associated with this call */
-
-       struct dahdi_subchannel sub_unused;             /*!< Just a safety precaution */
-       struct dahdi_subchannel subs[3];                        /*!< Sub-channels */
-       struct dahdi_confinfo saveconf;                 /*!< Saved conference info */
-
-       struct dahdi_pvt *slaves[MAX_SLAVES];           /*!< Slave to us (follows our conferencing) */
-       struct dahdi_pvt *master;                               /*!< Master to us (we follow their conferencing) */
-       int inconference;                               /*!< If our real should be in the conference */
-
-       int bufsize;                /*!< Size of the buffers */
-       int buf_no;                                     /*!< Number of buffers */
-       int buf_policy;                         /*!< Buffer policy */
-       int faxbuf_no;              /*!< Number of Fax buffers */
-       int faxbuf_policy;          /*!< Fax buffer policy */
-       int sig;                                        /*!< Signalling style */
-       /*!
-        * \brief Nonzero if the signaling type is sent over a radio.
-        * \note Set to a couple of nonzero values but it is only tested like a boolean.
-        */
-       int radio;
-       int outsigmod;                                  /*!< Outbound Signalling style (modifier) */
-       int oprmode;                                    /*!< "Operator Services" mode */
-       struct dahdi_pvt *oprpeer;                              /*!< "Operator Services" peer tech_pvt ptr */
-       /*! \brief Amount of gain to increase during caller id */
-       float cid_rxgain;
-       /*! \brief Rx gain set by chan_dahdi.conf */
-       float rxgain;
-       /*! \brief Tx gain set by chan_dahdi.conf */
-       float txgain;
-
-       float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */
-       float rxdrc;
-       
-       int tonezone;                                   /*!< tone zone for this chan, or -1 for default */
-       enum DAHDI_IFLIST which_iflist; /*!< Which interface list is this structure listed? */
-       struct dahdi_pvt *next;                         /*!< Next channel in list */
-       struct dahdi_pvt *prev;                         /*!< Prev channel in list */
-
-       /* flags */
-
-       /*!
-        * \brief TRUE if ADSI (Analog Display Services Interface) available
-        * \note Set from the "adsi" value read in from chan_dahdi.conf
-        */
-       unsigned int adsi:1;
-       /*!
-        * \brief TRUE if we can use a polarity reversal to mark when an outgoing
-        * call is answered by the remote party.
-        * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
-        */
-       unsigned int answeronpolarityswitch:1;
-       /*!
-        * \brief TRUE if busy detection is enabled.
-        * (Listens for the beep-beep busy pattern.)
-        * \note Set from the "busydetect" value read in from chan_dahdi.conf
-        */
-       unsigned int busydetect:1;
-       /*!
-        * \brief TRUE if call return is enabled.
-        * (*69, if your dialplan doesn't catch this first)
-        * \note Set from the "callreturn" value read in from chan_dahdi.conf
-        */
-       unsigned int callreturn:1;
-       /*!
-        * \brief TRUE if busy extensions will hear the call-waiting tone
-        * and can use hook-flash to switch between callers.
-        * \note Can be disabled by dialing *70.
-        * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
-        */
-       unsigned int callwaiting:1;
-       /*!
-        * \brief TRUE if send caller ID for Call Waiting
-        * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
-        */
-       unsigned int callwaitingcallerid:1;
-       /*!
-        * \brief TRUE if support for call forwarding enabled.
-        * Dial *72 to enable call forwarding.
-        * Dial *73 to disable call forwarding.
-        * \note Set from the "cancallforward" value read in from chan_dahdi.conf
-        */
-       unsigned int cancallforward:1;
-       /*!
-        * \brief TRUE if support for call parking is enabled.
-        * \note Set from the "canpark" value read in from chan_dahdi.conf
-        */
-       unsigned int canpark:1;
-       /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
-       unsigned int confirmanswer:1;
-       /*!
-        * \brief TRUE if the channel is to be destroyed on hangup.
-        * (Used by pseudo channels.)
-        */
-       unsigned int destroy:1;
-       unsigned int didtdd:1;                          /*!< flag to say its done it once */
-       /*! \brief TRUE if analog type line dialed no digits in Dial() */
-       unsigned int dialednone:1;
-       /*!
-        * \brief TRUE if in the process of dialing digits or sending something.
-        * \note This is used as a receive squelch for ISDN until connected.
-        */
-       unsigned int dialing:1;
-       /*! \brief TRUE if the transfer capability of the call is digital. */
-       unsigned int digital:1;
-       /*! \brief TRUE if Do-Not-Disturb is enabled, present only for non sig_analog */
-       unsigned int dnd:1;
-       /*! \brief XXX BOOLEAN Purpose??? */
-       unsigned int echobreak:1;
-       /*!
-        * \brief TRUE if echo cancellation enabled when bridged.
-        * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
-        * \note Disabled if the echo canceller is not setup.
-        */
-       unsigned int echocanbridged:1;
-       /*! \brief TRUE if echo cancellation is turned on. */
-       unsigned int echocanon:1;
-       /*! \brief TRUE if a fax tone has already been handled. */
-       unsigned int faxhandled:1;
-       /*! TRUE if dynamic faxbuffers are configured for use, default is OFF */
-       unsigned int usefaxbuffers:1;
-       /*! TRUE while buffer configuration override is in use */
-       unsigned int bufferoverrideinuse:1;
-       /*! \brief TRUE if over a radio and dahdi_read() has been called. */
-       unsigned int firstradio:1;
-       /*!
-        * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
-        * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
-        */
-       unsigned int hanguponpolarityswitch:1;
-       /*! \brief TRUE if DTMF detection needs to be done by hardware. */
-       unsigned int hardwaredtmf:1;
-       /*!
-        * \brief TRUE if the outgoing caller ID is blocked/hidden.
-        * \note Caller ID can be disabled by dialing *67.
-        * \note Caller ID can be enabled by dialing *82.
-        * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
-        */
-       unsigned int hidecallerid:1;
-       /*!
-        * \brief TRUE if hide just the name not the number for legacy PBX use.
-        * \note Only applies to PRI channels.
-        * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
-        */
-       unsigned int hidecalleridname:1;
-       /*! \brief TRUE if DTMF detection is disabled. */
-       unsigned int ignoredtmf:1;
-       /*!
-        * \brief TRUE if the channel should be answered immediately
-        * without attempting to gather any digits.
-        * \note Set from the "immediate" value read in from chan_dahdi.conf
-        */
-       unsigned int immediate:1;
-       /*! \brief TRUE if in an alarm condition. */
-       unsigned int inalarm:1;
-       /*! \brief TRUE if TDD in MATE mode */
-       unsigned int mate:1;
-       /*! \brief TRUE if we originated the call leg. */
-       unsigned int outgoing:1;
-       /* unsigned int overlapdial:1;                  unused and potentially confusing */
-       /*!
-        * \brief TRUE if busy extensions will hear the call-waiting tone
-        * and can use hook-flash to switch between callers.
-        * \note Set from the "callwaiting" value read in from chan_dahdi.conf
-        */
-       unsigned int permcallwaiting:1;
-       /*!
-        * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
-        * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
-        */
-       unsigned int permhidecallerid:1;
-       /*!
-        * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
-        * \note Set from the "priindication" value read in from chan_dahdi.conf
-        */
-       unsigned int priindication_oob:1;
-       /*!
-        * \brief TRUE if PRI B channels are always exclusively selected.
-        * \note Set from the "priexclusive" value read in from chan_dahdi.conf
-        */
-       unsigned int priexclusive:1;
-       /*!
-        * \brief TRUE if we will pulse dial.
-        * \note Set from the "pulsedial" value read in from chan_dahdi.conf
-        */
-       unsigned int pulse:1;
-       /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
-       unsigned int pulsedial:1;
-       unsigned int restartpending:1;          /*!< flag to ensure counted only once for restart */
-       /*!
-        * \brief TRUE if caller ID is restricted.
-        * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
-        * \note Set from the "restrictcid" value read in from chan_dahdi.conf
-        */
-       unsigned int restrictcid:1;
-       /*!
-        * \brief TRUE if three way calling is enabled
-        * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
-        */
-       unsigned int threewaycalling:1;
-       /*!
-        * \brief TRUE if call transfer is enabled
-        * \note For FXS ports (either direct analog or over T1/E1):
-        *   Support flash-hook call transfer
-        * \note For digital ports using ISDN PRI protocols:
-        *   Support switch-side transfer (called 2BCT, RLT or other names)
-        * \note Set from the "transfer" value read in from chan_dahdi.conf
-        */
-       unsigned int transfer:1;
-       /*!
-        * \brief TRUE if caller ID is used on this channel.
-        * \note PRI and SS7 spans will save caller ID from the networking peer.
-        * \note FXS ports will generate the caller ID spill.
-        * \note FXO ports will listen for the caller ID spill.
-        * \note Set from the "usecallerid" value read in from chan_dahdi.conf
-        */
-       unsigned int use_callerid:1;
-       /*!
-        * \brief TRUE if we will use the calling presentation setting
-        * from the Asterisk channel for outgoing calls.
-        * \note Only applies to PRI and SS7 channels.
-        * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
-        */
-       unsigned int use_callingpres:1;
-       /*!
-        * \brief TRUE if distinctive rings are to be detected.
-        * \note For FXO lines
-        * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
-        */
-       unsigned int usedistinctiveringdetection:1;
-       /*!
-        * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
-        * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
-        */
-       unsigned int dahditrcallerid:1;
-       /*!
-        * \brief TRUE if allowed to flash-transfer to busy channels.
-        * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
-        */
-       unsigned int transfertobusy:1;
-       /*!
-        * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
-        * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
-        */
-       unsigned int mwimonitor_neon:1;
-       /*!
-        * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
-        * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
-        */
-       unsigned int mwimonitor_fsk:1;
-       /*!
-        * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
-        * \note RPAS - Ring Pulse Alert Signal
-        * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
-        */
-       unsigned int mwimonitor_rpas:1;
-       /*! \brief TRUE if an MWI monitor thread is currently active */
-       unsigned int mwimonitoractive:1;
-       /*! \brief TRUE if a MWI message sending thread is active */
-       unsigned int mwisendactive:1;
-       /*!
-        * \brief TRUE if channel is out of reset and ready
-        * \note Set but not used.
-        */
-       unsigned int inservice:1;
-       /*!
-        * \brief TRUE if the channel is locally blocked.
-        * \note Applies to SS7 and MFCR2 channels.
-        */
-       unsigned int locallyblocked:1;
-       /*!
-        * \brief TRUE if the channel is remotely blocked.
-        * \note Applies to SS7 and MFCR2 channels.
-        */
-       unsigned int remotelyblocked:1;
-       /*!
-        * \brief TRUE if the channel alarms will be managed also as Span ones
-        * \note Applies to all channels
-        */
-       unsigned int manages_span_alarms:1;
-
-#if defined(HAVE_PRI)
-       struct sig_pri_span *pri;
-       int logicalspan;
-#endif
-       /*!
-        * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
-        * \note Set from the "usesmdi" value read in from chan_dahdi.conf
-        */
-       unsigned int use_smdi:1;
-       struct mwisend_info mwisend_data;
-       /*! \brief The SMDI interface to get SMDI messages from. */
-       struct ast_smdi_interface *smdi_iface;
-
-       /*! \brief Distinctive Ring data */
-       struct dahdi_distRings drings;
-
-       /*!
-        * \brief The configured context for incoming calls.
-        * \note The "context" string read in from chan_dahdi.conf
-        */
-       char context[AST_MAX_CONTEXT];
-       /*! 
-        * \brief A description for the channel configuration
-        * \note The "description" string read in from chan_dahdi.conf
-        */
-       char description[32];
-       /*!
-        * \brief Saved context string.
-        */
-       char defcontext[AST_MAX_CONTEXT];
-       /*! \brief Extension to use in the dialplan. */
-       char exten[AST_MAX_EXTENSION];
-       /*!
-        * \brief Language configured for calls.
-        * \note The "language" string read in from chan_dahdi.conf
-        */
-       char language[MAX_LANGUAGE];
-       /*!
-        * \brief The configured music-on-hold class to use for calls.
-        * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
-        */
-       char mohinterpret[MAX_MUSICCLASS];
-       /*!
-        * \brief Suggested music-on-hold class for peer channel to use for calls.
-        * \note The "mohsuggest" string read in from chan_dahdi.conf
-        */
-       char mohsuggest[MAX_MUSICCLASS];
-       char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
-#if defined(HAVE_PRI) || defined(HAVE_SS7)
-       /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
-       char cid_ani[AST_MAX_EXTENSION];
-#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
-       /*! \brief Automatic Number Identification code from PRI */
-       int cid_ani2;
-       /*! \brief Caller ID number from an incoming call. */
-       char cid_num[AST_MAX_EXTENSION];
-       /*!
-        * \brief Caller ID tag from incoming call
-        * \note the "cid_tag" string read in from chan_dahdi.conf
-        */
-       char cid_tag[AST_MAX_EXTENSION];
-       /*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
-       int cid_ton;
-       /*! \brief Caller ID name from an incoming call. */
-       char cid_name[AST_MAX_EXTENSION];
-       /*! \brief Caller ID subaddress from an incoming call. */
-       char cid_subaddr[AST_MAX_EXTENSION];
-       char *origcid_num;                              /*!< malloced original callerid */
-       char *origcid_name;                             /*!< malloced original callerid */
-       /*! \brief Call waiting number. */
-       char callwait_num[AST_MAX_EXTENSION];
-       /*! \brief Call waiting name. */
-       char callwait_name[AST_MAX_EXTENSION];
-       /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
-       char rdnis[AST_MAX_EXTENSION];
-       /*! \brief Dialed Number Identifier */
-       char dnid[AST_MAX_EXTENSION];
-       /*!
-        * \brief Bitmapped groups this belongs to.
-        * \note The "group" bitmapped group string read in from chan_dahdi.conf
-        */
-       ast_group_t group;
-       /*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
-       int law_default;
-       /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
-       int law;
-       int confno;                                     /*!< Our conference */
-       int confusers;                                  /*!< Who is using our conference */
-       int propconfno;                                 /*!< Propagated conference number */
-       /*!
-        * \brief Bitmapped call groups this belongs to.
-        * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
-        */
-       ast_group_t callgroup;
-       /*!
-        * \brief Bitmapped pickup groups this belongs to.
-        * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
-        */
-       ast_group_t pickupgroup;
-       /*!
-        * \brief Channel variable list with associated values to set when a channel is created.
-        * \note The "setvar" strings read in from chan_dahdi.conf
-        */
-       struct ast_variable *vars;
-       int channel;                                    /*!< Channel Number */
-       int span;                                       /*!< Span number */
-       time_t guardtime;                               /*!< Must wait this much time before using for new call */
-       int cid_signalling;                             /*!< CID signalling type bell202 or v23 */
-       int cid_start;                                  /*!< CID start indicator, polarity or ring or DTMF without warning event */
-       int dtmfcid_holdoff_state;              /*!< State indicator that allows for line to settle before checking for dtmf energy */
-       struct timeval  dtmfcid_delay;  /*!< Time value used for allow line to settle */
-       int callingpres;                                /*!< The value of calling presentation that we're going to use when placing a PRI call */
-       int callwaitingrepeat;                          /*!< How many samples to wait before repeating call waiting */
-       int cidcwexpire;                                /*!< When to stop waiting for CID/CW CAS response (In samples) */
-       int cid_suppress_expire;                /*!< How many samples to suppress after a CID spill. */
-       /*! \brief Analog caller ID waveform sample buffer */
-       unsigned char *cidspill;
-       /*! \brief Position in the cidspill buffer to send out next. */
-       int cidpos;
-       /*! \brief Length of the cidspill buffer containing samples. */
-       int cidlen;
-       /*! \brief Ring timeout timer?? */
-       int ringt;
-       /*!
-        * \brief Ring timeout base.
-        * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
-        */
-       int ringt_base;
-       /*!
-        * \brief Number of most significant digits/characters to strip from the dialed number.
-        * \note Feature is deprecated.  Use dialplan logic.
-        * \note The characters are stripped before the PRI TON/NPI prefix
-        * characters are processed.
-        */
-       int stripmsd;
-       /*!
-        * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
-        * \note
-        * After CAS is sent, the call waiting caller id will be sent if the phone
-        * gives a positive reply.
-        */
-       int callwaitcas;
-       /*! \brief Number of call waiting rings. */
-       int callwaitrings;
-       /*! \brief Echo cancel parameters. */
-       struct {
-               struct dahdi_echocanparams head;
-               struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
-       } echocancel;
-       /*!
-        * \brief Echo training time. 0 = disabled
-        * \note Set from the "echotraining" value read in from chan_dahdi.conf
-        */
-       int echotraining;
-       /*! \brief Filled with 'w'.  XXX Purpose?? */
-       char echorest[20];
-       /*!
-        * \brief Number of times to see "busy" tone before hanging up.
-        * \note Set from the "busycount" value read in from chan_dahdi.conf
-        */
-       int busycount;
-       /*!
-        * \brief Busy cadence pattern description.
-        * \note Set from the "busypattern" value read from chan_dahdi.conf
-        */
-       struct ast_dsp_busy_pattern busy_cadence;
-       /*!
-        * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
-        * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
-        */
-       int callprogress;
-       /*!
-        * \brief Number of milliseconds to wait for dialtone.
-        * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf
-        */
-       int waitfordialtone;
-       struct timeval waitingfordt;                    /*!< Time we started waiting for dialtone */
-       struct timeval flashtime;                       /*!< Last flash-hook time */
-       /*! \brief Opaque DSP configuration structure. */
-       struct ast_dsp *dsp;
-       /*! \brief DAHDI dial operation command struct for ioctl() call. */
-       struct dahdi_dialoperation dop;
-       int whichwink;                                  /*!< SIG_FEATDMF_TA Which wink are we on? */
-       /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
-       char finaldial[64];
-       char accountcode[AST_MAX_ACCOUNT_CODE];         /*!< Account code */
-       int amaflags;                                   /*!< AMA Flags */
-       struct tdd_state *tdd;                          /*!< TDD flag */
-       /*! \brief Accumulated call forwarding number. */
-       char call_forward[AST_MAX_EXTENSION];
-       /*!
-        * \brief Voice mailbox location.
-        * \note Set from the "mailbox" string read in from chan_dahdi.conf
-        */
-       char mailbox[AST_MAX_EXTENSION];
-       /*! \brief Opaque event subscription parameters for message waiting indication support. */
-       struct ast_event_sub *mwi_event_sub;
-       /*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
-       char dialdest[256];
-#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
-       struct dahdi_vmwi_info mwisend_setting;                         /*!< Which VMWI methods to use */
-       unsigned int mwisend_fsk: 1;            /*! Variable for enabling FSK MWI handling in chan_dahdi */
-       unsigned int mwisend_rpas:1;            /*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
-#endif
-       int distinctivering;                            /*!< Which distinctivering to use */
-       int dtmfrelax;                                  /*!< whether to run in relaxed DTMF mode */
-       /*! \brief Holding place for event injected from outside normal operation. */
-       int fake_event;
-       /*!
-        * \brief Minimal time period (ms) between the answer polarity
-        * switch and hangup polarity switch.
-        */
-       int polarityonanswerdelay;
-       /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
-       struct timeval polaritydelaytv;
-       /*!
-        * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
-        * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
-        */
-       int sendcalleridafter;
-       /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
-       int polarity;
-       /*! \brief DSP feature flags: DSP_FEATURE_xxx */
-       int dsp_features;
-#if defined(HAVE_SS7)
-       /*! \brief SS7 control parameters */
-       struct sig_ss7_linkset *ss7;
-#endif /* defined(HAVE_SS7) */
-#ifdef HAVE_OPENR2
-       struct dahdi_mfcr2 *mfcr2;
-       openr2_chan_t *r2chan;
-       openr2_calling_party_category_t mfcr2_recvd_category;
-       openr2_calling_party_category_t mfcr2_category;
-       int mfcr2_dnis_index;
-       int mfcr2_ani_index;
-       int mfcr2call:1;
-       int mfcr2_answer_pending:1;
-       int mfcr2_charge_calls:1;
-       int mfcr2_allow_collect_calls:1;
-       int mfcr2_forced_release:1;
-       int mfcr2_dnis_matched:1;
-       int mfcr2_call_accepted:1;
-       int mfcr2_accept_on_offer:1;
-       int mfcr2_progress_sent:1;
-#endif
-       /*! \brief DTMF digit in progress.  0 when no digit in progress. */
-       char begindigit;
-       /*! \brief TRUE if confrence is muted. */
-       int muting;
-       void *sig_pvt;
-       struct ast_cc_config_params *cc_params;
-       /* DAHDI channel names may differ greatly from the
-        * string that was provided to an app such as Dial. We
-        * need to save the original string passed to dahdi_request
-        * for call completion purposes. This way, we can replicate
-        * the original dialed string later.
-        */
-       char dialstring[AST_CHANNEL_NAME];
-};
-
 #define DATA_EXPORT_DAHDI_PVT(MEMBER)                                  \
        MEMBER(dahdi_pvt, cid_rxgain, AST_DATA_DOUBLE)                  \
        MEMBER(dahdi_pvt, rxgain, AST_DATA_DOUBLE)                      \
@@ -1368,6 +818,18 @@ struct dahdi_chan_conf {
         * \note Set from the "smdiport" string read in from chan_dahdi.conf
         */
        char smdi_port[SMDI_MAX_FILENAME_LEN];
+
+       /*!
+        * \brief Don't create channels below this number
+        * \note by default is 0 (no limit)
+        */
+       int wanted_channels_start;
+
+       /*!
+        * \brief Don't create channels above this number (infinity by default)
+        * \note by default is 0 (special value that means "no limit").
+        */
+       int wanted_channels_end;
 };
 
 /*! returns a new dahdi_chan_conf with default values (by-value) */
@@ -1400,6 +862,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
                        .localprefix = "",
                        .privateprefix = "",
                        .unknownprefix = "",
+                       .colp_send = SIG_PRI_COLP_UPDATE,
                        .resetinterval = -1,
                },
 #endif
@@ -1536,7 +999,6 @@ static struct ast_channel_tech dahdi_tech = {
        .answer = dahdi_answer,
        .read = dahdi_read,
        .write = dahdi_write,
-       .bridge = dahdi_bridge,
        .exception = dahdi_exception,
        .indicate = dahdi_indicate,
        .fixup = dahdi_fixup,
@@ -1550,36 +1012,6 @@ static struct ast_channel_tech dahdi_tech = {
 
 #define GET_CHANNEL(p) ((p)->channel)
 
-#define SIG_PRI_LIB_HANDLE_CASES       \
-       SIG_PRI:                                                \
-       case SIG_BRI:                                   \
-       case SIG_BRI_PTMP
-
-/*!
- * \internal
- * \brief Determine if sig_pri handles the signaling.
- * \since 1.8
- *
- * \param signaling Signaling to determine if is for sig_pri.
- *
- * \return TRUE if the signaling is for sig_pri.
- */
-static inline int dahdi_sig_pri_lib_handles(int signaling)
-{
-       int handles;
-
-       switch (signaling) {
-       case SIG_PRI_LIB_HANDLE_CASES:
-               handles = 1;
-               break;
-       default:
-               handles = 0;
-               break;
-       }
-
-       return handles;
-}
-
 static enum analog_sigtype dahdisig_to_analogsig(int sig)
 {
        switch (sig) {
@@ -1673,6 +1105,60 @@ static int analogsub_to_dahdisub(enum analog_sub analogsub)
        return index;
 }
 
+/*!
+ * \internal
+ * \brief Send a dial string to DAHDI.
+ * \since 12.0.0
+ *
+ * \param pvt DAHDI private pointer
+ * \param operation DAHDI dial operation to do to string
+ * \param dial_str Dial string to send
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+static int dahdi_dial_str(struct dahdi_pvt *pvt, int operation, const char *dial_str)
+{
+       int res;
+       int offset;
+       const char *pos;
+       struct dahdi_dialoperation zo = {
+               .op = operation,
+       };
+
+       /* Convert the W's to ww. */
+       pos = dial_str;
+       for (offset = 0; offset < sizeof(zo.dialstr) - 1; ++offset) {
+               if (!*pos) {
+                       break;
+               }
+               if (*pos == 'W') {
+                       /* Convert 'W' to "ww" */
+                       ++pos;
+                       if (offset >= sizeof(zo.dialstr) - 3) {
+                               /* No room to expand */
+                               break;
+                       }
+                       zo.dialstr[offset] = 'w';
+                       ++offset;
+                       zo.dialstr[offset] = 'w';
+                       continue;
+               }
+               zo.dialstr[offset] = *pos++;
+       }
+       /* The zo initialization has already terminated the dialstr. */
+
+       ast_debug(1, "Channel %d: Dial str '%s' expanded to '%s' sent to DAHDI_DIAL.\n",
+               pvt->channel, dial_str, zo.dialstr);
+       res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
+       if (res) {
+               ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
+                       pvt->channel, dial_str, strerror(errno));
+       }
+
+       return res;
+}
+
 static enum analog_event dahdievent_to_analogevent(int event);
 static int bump_gains(struct dahdi_pvt *p);
 static int dahdi_setlinear(int dfd, int linear);
@@ -2097,7 +1583,7 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a
                                        ast_mutex_unlock(&p->lock);
                                        ast_channel_unlock(ast);
                                        if (ast_exists_extension(ast, target_context, "fax", 1,
-                                               S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+                                               S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
                                                ast_channel_lock(ast);
                                                ast_mutex_lock(&p->lock);
                                                ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
@@ -2143,6 +1629,50 @@ static void my_deadlock_avoidance_private(void *pvt)
        DEADLOCK_AVOIDANCE(&p->lock);
 }
 
+static struct ast_manager_event_blob *dahdichannel_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+       struct ast_channel_blob *obj = stasis_message_data(msg);
+       struct ast_json *span, *channel;
+
+       channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+       if (!channel_string) {
+               return NULL;
+       }
+
+       span = ast_json_object_get(obj->blob, "span");
+       channel = ast_json_object_get(obj->blob, "channel");
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
+               "%s"
+               "DAHDISpan: %d\r\n"
+               "DAHDIChannel: %s\r\n",
+               ast_str_buffer(channel_string),
+               (unsigned int)ast_json_integer_get(span),
+               ast_json_string_get(channel));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,
+       .to_ami = dahdichannel_to_ami,
+       );
+
+/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
+static void publish_dahdichannel(struct ast_channel *chan, int span, const char *dahdi_channel)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+       ast_assert(dahdi_channel != NULL);
+
+       blob = ast_json_pack("{s: i, s: s}",
+               "span", span,
+               "channel", dahdi_channel);
+       if (!blob) {
+               return;
+       }
+
+       ast_channel_publish_blob(chan, dahdichannel_type(), blob);
+}
+
 /*!
  * \internal
  * \brief Post an AMI DAHDI channel association event.
@@ -2167,15 +1697,7 @@ static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *cha
                /* Real channel */
                snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
        }
-       ast_manager_event(chan, EVENT_FLAG_CALL, "DAHDIChannel",
-               "Channel: %s\r\n"
-               "Uniqueid: %s\r\n"
-               "DAHDISpan: %d\r\n"
-               "DAHDIChannel: %s\r\n",
-               ast_channel_name(chan),
-               ast_channel_uniqueid(chan),
-               p->span,
-               ch_name);
+       publish_dahdichannel(chan, p->span, ch_name);
 }
 
 #ifdef HAVE_PRI
@@ -2198,14 +1720,14 @@ static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
 #endif
 
 /* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
-*      returns the last value of the linear setting 
-*/ 
+*      returns the last value of the linear setting
+*/
 static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
 {
        struct dahdi_pvt *p = pvt;
        int oldval;
        int idx = analogsub_to_dahdisub(sub);
-       
+
        dahdi_setlinear(p->subs[idx].dfd, linear_mode);
        oldval = p->subs[idx].linear;
        p->subs[idx].linear = linear_mode ? 1 : 0;
@@ -2233,11 +1755,16 @@ static void my_get_and_handle_alarms(void *pvt)
 
 static void *my_get_sigpvt_bridged_channel(struct ast_channel *chan)
 {
-       struct dahdi_pvt *p = ast_bridged_channel(chan)->tech_pvt;
-       if (p)
-               return p->sig_pvt;
-       else
-               return NULL;
+       RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup);
+
+       if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
+               struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
+
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                       return p->sig_pvt;
+               }
+       }
+       return NULL;
 }
 
 static int my_get_sub_fd(void *pvt, enum analog_sub sub)
@@ -2247,7 +1774,7 @@ static int my_get_sub_fd(void *pvt, enum analog_sub sub)
        return p->subs[dahdi_sub].dfd;
 }
 
-static void my_set_cadence(void *pvt, int *cidrings, struct ast_channel *ast)
+static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
 {
        struct dahdi_pvt *p = pvt;
 
@@ -2255,11 +1782,11 @@ static void my_set_cadence(void *pvt, int *cidrings, struct ast_channel *ast)
        if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
                if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
                        ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
-               *cidrings = cidrings[p->distinctivering - 1];
+               *cid_rings = cidrings[p->distinctivering - 1];
        } else {
                if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
                        ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
-               *cidrings = p->sendcalleridafter;
+               *cid_rings = p->sendcalleridafter;
        }
 }
 
@@ -2277,6 +1804,13 @@ static void my_set_dialing(void *pvt, int is_dialing)
        p->dialing = is_dialing;
 }
 
+static void my_set_outgoing(void *pvt, int is_outgoing)
+{
+       struct dahdi_pvt *p = pvt;
+
+       p->outgoing = is_outgoing;
+}
+
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
 static void my_set_digital(void *pvt, int is_digital)
 {
@@ -2562,14 +2096,25 @@ static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel
        return;
 }
 
-static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid);
+/*!
+ * \internal
+ * \brief performs duties of dahdi_new, but also removes and possibly unbinds (if callid_created is 1) before returning
+ * \note this variant of dahdi should only be used in conjunction with ast_callid_threadstorage_auto()
+ *
+ * \param callid_created value returned from ast_callid_threadstorage_auto()
+ */
+static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linked, struct ast_callid *callid, int callid_created);
+
+static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid);
 
 static struct ast_channel *my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub, const struct ast_channel *requestor)
 {
+       struct ast_callid *callid = NULL;
+       int callid_created = ast_callid_threadstorage_auto(&callid);
        struct dahdi_pvt *p = pvt;
        int dsub = analogsub_to_dahdisub(sub);
 
-       return dahdi_new(p, state, startpbx, dsub, 0, requestor ? ast_channel_linkedid(requestor) : "");
+       return dahdi_new_callid_clean(p, state, startpbx, dsub, 0, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
@@ -2589,6 +2134,8 @@ static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state, enum sig
        struct dahdi_pvt *p = pvt;
        int audio;
        int newlaw = -1;
+       struct ast_callid *callid = NULL;
+       int callid_created = ast_callid_threadstorage_auto(&callid);
 
        switch (p->sig) {
        case SIG_PRI_LIB_HANDLE_CASES:
@@ -2624,23 +2171,24 @@ static struct ast_channel *my_new_pri_ast_channel(void *pvt, int state, enum sig
                        newlaw = DAHDI_LAW_MULAW;
                        break;
        }
-       return dahdi_new(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "");
+
+       return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 #endif /* defined(HAVE_PRI) */
 
 static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
 
-#if defined(HAVE_PRI)
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
 /*!
  * \internal
- * \brief Open the PRI channel media path.
+ * \brief Open the PRI/SS7 channel media path.
  * \since 1.8
  *
  * \param p Channel private control structure.
  *
  * \return Nothing
  */
-static void my_pri_open_media(void *p)
+static void my_pri_ss7_open_media(void *p)
 {
        struct dahdi_pvt *pvt = p;
        int res;
@@ -2679,7 +2227,7 @@ static void my_pri_open_media(void *p)
                pvt->dsp_features = 0;
        }
 }
-#endif /* defined(HAVE_PRI) */
+#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
 
 #if defined(HAVE_PRI)
 /*!
@@ -2696,19 +2244,13 @@ static void my_pri_open_media(void *p)
  */
 static void my_pri_dial_digits(void *p, const char *dial_string)
 {
-       struct dahdi_dialoperation zo = {
-               .op = DAHDI_DIAL_OP_APPEND,
-       };
+       char dial_str[DAHDI_MAX_DTMF_BUF];
        struct dahdi_pvt *pvt = p;
        int res;
 
-       snprintf(zo.dialstr, sizeof(zo.dialstr), "T%s", dial_string);
-       ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", pvt->channel, zo.dialstr);
-       res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
-       if (res) {
-               ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
-                       pvt->channel, dial_string, strerror(errno));
-       } else {
+       snprintf(dial_str, sizeof(dial_str), "T%s", dial_string);
+       res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
+       if (!res) {
                pvt->dialing = 1;
        }
 }
@@ -2898,17 +2440,14 @@ static int my_is_off_hook(void *pvt)
        return par.rxisoffhook;
 }
 
-static void dahdi_enable_ec(struct dahdi_pvt *p);
-static void dahdi_disable_ec(struct dahdi_pvt *p);
-
 static int my_set_echocanceller(void *pvt, int enable)
 {
        struct dahdi_pvt *p = pvt;
 
        if (enable)
-               dahdi_enable_ec(p);
+               dahdi_ec_enable(p);
        else
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
        return 0;
 }
@@ -2999,10 +2538,7 @@ static int my_start(void *pvt)
 
 static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
 {
-       int index = analogsub_to_dahdisub(sub);
-       int res;
        struct dahdi_pvt *p = pvt;
-       struct dahdi_dialoperation ddop;
 
        if (dop->op != ANALOG_DIAL_OP_REPLACE) {
                ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
@@ -3015,17 +2551,7 @@ static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoper
                return -1;
        }
 
-       ddop.op = DAHDI_DIAL_OP_REPLACE;
-       ast_copy_string(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
-
-       ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", p->channel, ddop.dialstr);
-
-       res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
-       if (res == -1) {
-               ast_debug(1, "DAHDI_DIAL ioctl failed on %s: %s\n", ast_channel_name(p->owner), strerror(errno));
-       }
-
-       return res;
+       return dahdi_dial_str(p, DAHDI_DIAL_OP_REPLACE, dop->dialstr);
 }
 
 static void dahdi_train_ec(struct dahdi_pvt *p);
@@ -3070,8 +2596,8 @@ static void my_pri_fixup_chans(void *chan_old, void *chan_new)
        new_chan->owner = old_chan->owner;
        old_chan->owner = NULL;
        if (new_chan->owner) {
-               new_chan->owner->tech_pvt = new_chan;
-               new_chan->owner->fds[0] = new_chan->subs[SUB_REAL].dfd;
+               ast_channel_tech_pvt_set(new_chan->owner, new_chan);
+               ast_channel_internal_fd_set(new_chan->owner, 0, new_chan->subs[SUB_REAL].dfd);
                new_chan->subs[SUB_REAL].owner = old_chan->subs[SUB_REAL].owner;
                old_chan->subs[SUB_REAL].owner = NULL;
        }
@@ -3120,13 +2646,26 @@ static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
 #endif /* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
+static void pri_destroy_span(struct sig_pri_span *pri);
+
 static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 {
        int x;
 
        ioctl(pri->fds[index], DAHDI_GETEVENT, &x);
-       if (x) {
-               ast_log(LOG_NOTICE, "PRI got event: %s (%d) on D-channel of span %d\n", event2str(x), x, pri->span);
+       switch (x) {
+       case DAHDI_EVENT_NONE:
+               break;
+       case DAHDI_EVENT_ALARM:
+       case DAHDI_EVENT_NOALARM:
+               if (sig_pri_is_alarm_ignored(pri)) {
+                       break;
+               }
+               /* Fall through */
+       default:
+               ast_log(LOG_NOTICE, "Got DAHDI event: %s (%d) on D-channel of span %d\n",
+                       event2str(x), x, pri->span);
+               break;
        }
        /* Keep track of alarm state */
        switch (x) {
@@ -3136,6 +2675,9 @@ static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
        case DAHDI_EVENT_NOALARM:
                pri_event_noalarm(pri, index, 0);
                break;
+       case DAHDI_EVENT_REMOVED:
+               pri_destroy_span(pri);
+               break;
        default:
                break;
        }
@@ -3331,7 +2873,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->congestion_devstate != new_state) {
                pri->congestion_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/congestion", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/congestion", pri->span);
        }
 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
        /* Update the span threshold device state and report any change. */
@@ -3347,7 +2889,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->threshold_devstate != new_state) {
                pri->threshold_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/threshold", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/threshold", pri->span);
        }
 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
 }
@@ -3387,7 +2929,7 @@ static void my_pri_init_config(void *priv, struct sig_pri_span *pri);
 #endif /* defined(HAVE_PRI_CALL_WAITING) */
 static int dahdi_new_pri_nobch_channel(struct sig_pri_span *pri);
 
-static struct sig_pri_callback dahdi_pri_callbacks =
+struct sig_pri_callback sig_pri_callbacks =
 {
        .handle_dchan_exception = my_handle_dchan_exception,
        .play_tone = my_pri_play_tone,
@@ -3400,6 +2942,7 @@ static struct sig_pri_callback dahdi_pri_callbacks =
        .fixup_chans = my_pri_fixup_chans,
        .set_alarm = my_set_alarm,
        .set_dialing = my_set_dialing,
+       .set_outgoing = my_set_outgoing,
        .set_digital = my_set_digital,
        .set_callerid = my_set_callerid,
        .set_dnid = my_set_dnid,
@@ -3414,7 +2957,7 @@ static struct sig_pri_callback dahdi_pri_callbacks =
        .module_ref = my_module_ref,
        .module_unref = my_module_unref,
        .dial_digits = my_pri_dial_digits,
-       .open_media = my_pri_open_media,
+       .open_media = my_pri_ss7_open_media,
        .ami_channel_event = my_ami_channel_event,
 };
 #endif /* defined(HAVE_PRI) */
@@ -3492,6 +3035,8 @@ static struct ast_channel *my_new_ss7_ast_channel(void *pvt, int state, enum sig
        struct dahdi_pvt *p = pvt;
        int audio;
        int newlaw;
+       struct ast_callid *callid = NULL;
+       int callid_created = ast_callid_threadstorage_auto(&callid);
 
        /* Set to audio mode at this point */
        audio = 1;
@@ -3518,7 +3063,7 @@ static struct ast_channel *my_new_ss7_ast_channel(void *pvt, int state, enum sig
                newlaw = DAHDI_LAW_MULAW;
                break;
        }
-       return dahdi_new(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "");
+       return dahdi_new_callid_clean(p, state, 0, SUB_REAL, newlaw, requestor ? ast_channel_linkedid(requestor) : "", callid, callid_created);
 }
 #endif /* defined(HAVE_SS7) */
 
@@ -3556,7 +3101,7 @@ static int my_ss7_play_tone(void *pvt, enum sig_ss7_tone tone)
 #endif /* defined(HAVE_SS7) */
 
 #if defined(HAVE_SS7)
-static struct sig_ss7_callback dahdi_ss7_callbacks =
+struct sig_ss7_callback sig_ss7_callbacks =
 {
        .lock_private = my_lock_private,
        .unlock_private = my_unlock_private,
@@ -3571,12 +3116,14 @@ static struct sig_ss7_callback dahdi_ss7_callbacks =
        .handle_link_exception = my_handle_link_exception,
        .set_alarm = my_set_alarm,
        .set_dialing = my_set_dialing,
+       .set_outgoing = my_set_outgoing,
        .set_digital = my_set_digital,
        .set_inservice = my_set_inservice,
        .set_locallyblocked = my_set_locallyblocked,
        .set_remotelyblocked = my_set_remotelyblocked,
        .set_callerid = my_set_callerid,
        .set_dnid = my_set_dnid,
+       .open_media = my_pri_ss7_open_media,
 };
 #endif /* defined(HAVE_SS7) */
 
@@ -3601,7 +3148,6 @@ static struct sig_ss7_callback dahdi_ss7_callbacks =
 static void notify_message(char *mailbox_full, int thereornot)
 {
        char s[sizeof(mwimonitornotify) + 80];
-       struct ast_event *event;
        char *mailbox, *context;
 
        /* Strip off @default */
@@ -3610,16 +3156,7 @@ static void notify_message(char *mailbox_full, int thereornot)
        if (ast_strlen_zero(context))
                context = "default";
 
-       if (!(event = ast_event_new(AST_EVENT_MWI,
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-                       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-                       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
-                       AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
-                       AST_EVENT_IE_END))) {
-               return;
-       }
-
-       ast_event_queue_and_cache(event);
+       ast_publish_mwi_state(mailbox, context, thereornot, thereornot);
 
        if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
                snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
@@ -3662,7 +3199,7 @@ static int my_have_progressdetect(void *pvt)
        }
 }
 
-static struct analog_callback dahdi_analog_callbacks =
+struct analog_callback analog_callbacks =
 {
        .play_tone = my_play_tone,
        .get_event = my_get_event,
@@ -3712,6 +3249,7 @@ static struct analog_callback dahdi_analog_callbacks =
        .set_cadence = my_set_cadence,
        .set_alarm = my_set_alarm,
        .set_dialing = my_set_dialing,
+       .set_outgoing = my_set_outgoing,
        .set_ringtimeout = my_set_ringtimeout,
        .set_waitingfordt = my_set_waitingfordt,
        .check_waitingfordt = my_check_waitingfordt,
@@ -3734,8 +3272,7 @@ static struct analog_callback dahdi_analog_callbacks =
 /*! Round robin search locations. */
 static struct dahdi_pvt *round_robin[32];
 
-#define dahdi_get_index(ast, p, nullok)        _dahdi_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
-static int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
+int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
 {
        int res;
        if (p->subs[SUB_REAL].owner == ast)
@@ -3810,15 +3347,50 @@ static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
        }
 }
 
+static void publish_channel_alarm_clear(int channel)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+       if (!dahdi_chan) {
+               return;
+       }
+
+       ast_str_set(&dahdi_chan, 0, "%d", channel);
+       ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
+       body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_span_alarm_clear(int span)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
+       body = ast_json_pack("{s: i}", "Span", span);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
 static void handle_clear_alarms(struct dahdi_pvt *p)
 {
+#if defined(HAVE_PRI)
+       if (dahdi_sig_pri_lib_handles(p->sig) && sig_pri_is_alarm_ignored(p->pri)) {
+               return;
+       }
+#endif /* defined(HAVE_PRI) */
+
        if (report_alarms & REPORT_CHANNEL_ALARMS) {
-               ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
-               manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+               publish_channel_alarm_clear(p->channel);
        }
        if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
-               ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", p->span);
-               manager_event(EVENT_FLAG_SYSTEM, "SpanAlarmClear", "Span: %d\r\n", p->span);
+               publish_span_alarm_clear(p->span);
        }
 }
 
@@ -3855,7 +3427,7 @@ static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_
 {
        openr2_calling_party_category_t cat;
        const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
-       struct dahdi_pvt *p = c->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(c);
        if (ast_strlen_zero(catstr)) {
                ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
                                ast_channel_name(c), openr2_proto_get_category_string(p->mfcr2_category));
@@ -3925,8 +3497,8 @@ static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_er
        struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
        ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
        if (p->owner) {
-               p->owner->hangupcause = AST_CAUSE_PROTOCOL_ERROR;
-               p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+               ast_channel_hangupcause_set(p->owner, AST_CAUSE_PROTOCOL_ERROR);
+               ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
        }
        ast_mutex_lock(&p->lock);
        p->mfcr2call = 0;
@@ -3950,6 +3522,8 @@ static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, con
 {
        struct dahdi_pvt *p;
        struct ast_channel *c;
+       struct ast_callid *callid = NULL;
+       int callid_created = ast_callid_threadstorage_auto(&callid);
        ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
                        openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
                        openr2_proto_get_category_string(category));
@@ -3958,7 +3532,7 @@ static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, con
        if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
                ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
                dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
-               return;
+               goto dahdi_r2_on_call_offered_cleanup;
        }
        ast_mutex_lock(&p->lock);
        p->mfcr2_recvd_category = category;
@@ -3979,16 +3553,16 @@ static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, con
                ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
                                p->channel, p->exten, p->context);
                dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
-               return;
+               goto dahdi_r2_on_call_offered_cleanup;
        }
        if (!p->mfcr2_accept_on_offer) {
                /* The user wants us to start the PBX thread right away without accepting the call first */
-               c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL);
+               c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, callid);
                if (c) {
                        /* Done here, don't disable reading now since we still need to generate MF tones to accept
                           the call or reject it and detect the tone off condition of the other end, all of this
                           will be done in the PBX thread now */
-                       return;
+                       goto dahdi_r2_on_call_offered_cleanup;
                }
                ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
                dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
@@ -3999,6 +3573,9 @@ static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, con
                ast_debug(1, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
                openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
        }
+
+dahdi_r2_on_call_offered_cleanup:
+       ast_callid_threadstorage_auto_clean(callid, callid_created);
 }
 
 static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
@@ -4010,13 +3587,14 @@ static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
        ast_mutex_unlock(&p->lock);
 }
 
-static void dahdi_enable_ec(struct dahdi_pvt *p);
 static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
 {
        struct dahdi_pvt *p = NULL;
        struct ast_channel *c = NULL;
+       struct ast_callid *callid = NULL;
+       int callid_created = ast_callid_threadstorage_auto(&callid);
        p = openr2_chan_get_client_data(r2chan);
-       dahdi_enable_ec(p);
+       dahdi_ec_enable(p);
        p->mfcr2_call_accepted = 1;
        /* if it's an incoming call ... */
        if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
@@ -4031,19 +3609,19 @@ static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t
                                ast_debug(1, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
                                dahdi_r2_answer(p);
                        }
-                       return;
+                       goto dahdi_r2_on_call_accepted_cleanup;
                }
-               c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL);
+               c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, NULL, callid);
                if (c) {
                        /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
                           library to forget about it */
                        openr2_chan_disable_read(r2chan);
-                       return;
+                       goto dahdi_r2_on_call_accepted_cleanup;
                }
                ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
                /* failed to create the channel, bail out and report it as an out of order line */
                dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
-               return;
+               goto dahdi_r2_on_call_accepted_cleanup;
        }
        /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
        ast_verbose("MFC/R2 call has been accepted on forward channel %d\n", p->channel);
@@ -4051,6 +3629,9 @@ static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t
        p->dialing = 0;
        /* chan_dahdi will take care of reading from now on in the PBX thread, tell the library to forget about it */
        openr2_chan_disable_read(r2chan);
+
+dahdi_r2_on_call_accepted_cleanup:
+       ast_callid_threadstorage_auto_clean(callid, callid_created);
 }
 
 static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
@@ -4089,6 +3670,10 @@ static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
 static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
 {
        struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+       char cause_str[50];
+       struct ast_control_pvt_cause_code *cause_code;
+       int datalen = sizeof(*cause_code);
+
        ast_verbose("MFC/R2 call disconnected on channel %d\n", openr2_chan_get_number(r2chan));
        ast_mutex_lock(&p->lock);
        if (!p->owner) {
@@ -4097,10 +3682,21 @@ static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disco
                dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
                return;
        }
+
+       snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
+       datalen += strlen(cause_str);
+       cause_code = ast_alloca(datalen);
+       memset(cause_code, 0, datalen);
+       cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
+       ast_copy_string(cause_code->chan_name, ast_channel_name(p->owner), AST_CHANNEL_NAME);
+       ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
+       ast_queue_control_data(p->owner, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
+       ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
+
        /* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
           be done in dahdi_hangup */
-       if (p->owner->_state == AST_STATE_UP) {
-               p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+       if (ast_channel_state(p->owner) == AST_STATE_UP) {
+               ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
                ast_mutex_unlock(&p->lock);
        } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
                /* being the forward side we must report what happened to the call to whoever requested it */
@@ -4117,7 +3713,7 @@ static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disco
                        p->subs[SUB_REAL].needcongestion = 1;
                        break;
                default:
-                       p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                       ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV);
                }
                ast_mutex_unlock(&p->lock);
        } else {
@@ -4458,7 +4054,7 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
        int dtmf = -1;
        int res;
 
-       pvt = chan->tech_pvt;
+       pvt = ast_channel_tech_pvt(chan);
 
        ast_mutex_lock(&pvt->lock);
 
@@ -4482,19 +4078,15 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
                goto out;
 
        if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
-               struct dahdi_dialoperation zo = {
-                       .op = DAHDI_DIAL_OP_APPEND,
-               };
+               char dial_str[] = { 'T', digit, '\0' };
 
-               zo.dialstr[0] = 'T';
-               zo.dialstr[1] = digit;
-               zo.dialstr[2] = '\0';
-               if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
-                       ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
-               else
+               res = dahdi_dial_str(pvt, DAHDI_DIAL_OP_APPEND, dial_str);
+               if (!res) {
                        pvt->dialing = 1;
+               }
        } else {
-               ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
+               ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
+                       ast_channel_name(chan), digit);
                pvt->dialing = 1;
                pvt->begindigit = digit;
        }
@@ -4512,7 +4104,7 @@ static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int du
        int idx;
        int x;
 
-       pvt = chan->tech_pvt;
+       pvt = ast_channel_tech_pvt(chan);
 
        ast_mutex_lock(&pvt->lock);
 
@@ -4530,7 +4122,8 @@ static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int du
 
        if (pvt->begindigit) {
                x = -1;
-               ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
+               ast_debug(1, "Channel %s ending VLDTMF digit '%c'\n",
+                       ast_channel_name(chan), digit);
                res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
                pvt->dialing = 0;
                pvt->begindigit = 0;
@@ -4662,45 +4255,6 @@ static char *dahdi_sig2str(int sig)
 
 #define sig2str dahdi_sig2str
 
-static int analog_lib_handles(int signalling, int radio, int oprmode)
-{
-       switch (signalling) {
-       case SIG_FXOLS:
-       case SIG_FXOGS:
-       case SIG_FXOKS:
-       case SIG_FXSLS:
-       case SIG_FXSGS:
-       case SIG_FXSKS:
-       case SIG_EMWINK:
-       case SIG_EM:
-       case SIG_EM_E1:
-       case SIG_FEATD:
-       case SIG_FEATDMF:
-       case SIG_E911:
-       case SIG_FGC_CAMA:
-       case SIG_FGC_CAMAMF:
-       case SIG_FEATB:
-       case SIG_SFWINK:
-       case SIG_SF:
-       case SIG_SF_FEATD:
-       case SIG_SF_FEATDMF:
-       case SIG_FEATDMF_TA:
-       case SIG_SF_FEATB:
-               break;
-       default:
-               /* The rest of the function should cover the remainder of signalling types */
-               return 0;
-       }
-
-       if (radio)
-               return 0;
-
-       if (oprmode)
-               return 0;
-
-       return 1;
-}
-
 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
 {
        /* If the conference already exists, and we're already in it
@@ -4827,7 +4381,7 @@ static int reset_conf(struct dahdi_pvt *p)
        return 0;
 }
 
-static int update_conf(struct dahdi_pvt *p)
+void dahdi_conf_update(struct dahdi_pvt *p)
 {
        int needconf = 0;
        int x;
@@ -4880,10 +4434,9 @@ static int update_conf(struct dahdi_pvt *p)
                p->confno = -1;
        }
        ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
-       return 0;
 }
 
-static void dahdi_enable_ec(struct dahdi_pvt *p)
+void dahdi_ec_enable(struct dahdi_pvt *p)
 {
        int res;
        if (!p)
@@ -4955,7 +4508,7 @@ static void dahdi_train_ec(struct dahdi_pvt *p)
        }
 }
 
-static void dahdi_disable_ec(struct dahdi_pvt *p)
+void dahdi_ec_disable(struct dahdi_pvt *p)
 {
        int res;
 
@@ -4973,13 +4526,22 @@ static void dahdi_disable_ec(struct dahdi_pvt *p)
        p->echocanon = 0;
 }
 
+static int set_hwgain(int fd, float gain, int tx_direction)
+{
+       struct dahdi_hwgain hwgain;
+
+       hwgain.newgain = gain * 10.0;
+       hwgain.tx = tx_direction;
+       return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
+}
+
 /* perform a dynamic range compression transform on the given sample */
 static int drc_sample(int sample, float drc)
 {
        float neg;
        float shallow, steep;
        float max = SHRT_MAX;
-       
+
        neg = (sample < 0 ? -1 : 1);
        steep = drc*sample;
        shallow = neg*(max-max/drc)+(float)sample/drc;
@@ -5009,9 +4571,12 @@ static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
                                if (drc) {
                                        k = drc_sample(k, drc);
                                }
-                               k = (float)k*linear_gain;
-                               if (k > 32767) k = 32767;
-                               if (k < -32767) k = -32767;
+                               k = (float)k * linear_gain;
+                               if (k > 32767) {
+                                       k = 32767;
+                               } else if (k < -32768) {
+                                       k = -32768;
+                               }
                                g->txgain[j] = AST_LIN2A(k);
                        } else {
                                g->txgain[j] = j;
@@ -5025,9 +4590,12 @@ static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law)
                                if (drc) {
                                        k = drc_sample(k, drc);
                                }
-                               k = (float)k*linear_gain;
-                               if (k > 32767) k = 32767;
-                               if (k < -32767) k = -32767;
+                               k = (float)k * linear_gain;
+                               if (k > 32767) {
+                                       k = 32767;
+                               } else if (k < -32768) {
+                                       k = -32768;
+                               }
                                g->txgain[j] = AST_LIN2MU(k);
 
                        } else {
@@ -5052,9 +4620,12 @@ static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
                                if (drc) {
                                        k = drc_sample(k, drc);
                                }
-                               k = (float)k*linear_gain;
-                               if (k > 32767) k = 32767;
-                               if (k < -32767) k = -32767;
+                               k = (float)k * linear_gain;
+                               if (k > 32767) {
+                                       k = 32767;
+                               } else if (k < -32768) {
+                                       k = -32768;
+                               }
                                g->rxgain[j] = AST_LIN2A(k);
                        } else {
                                g->rxgain[j] = j;
@@ -5068,9 +4639,12 @@ static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law)
                                if (drc) {
                                        k = drc_sample(k, drc);
                                }
-                               k = (float)k*linear_gain;
-                               if (k > 32767) k = 32767;
-                               if (k < -32767) k = -32767;
+                               k = (float)k * linear_gain;
+                               if (k > 32767) {
+                                       k = 32767;
+                               } else if (k < -32768) {
+                                       k = -32768;
+                               }
                                g->rxgain[j] = AST_LIN2MU(k);
                        } else {
                                g->rxgain[j] = j;
@@ -5262,24 +4836,25 @@ static int send_cwcidspill(struct dahdi_pvt *p)
 static int has_voicemail(struct dahdi_pvt *p)
 {
        int new_msgs;
-       struct ast_event *event;
        char *mailbox, *context;
+       RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
+       struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
 
        mailbox = context = ast_strdupa(p->mailbox);
        strsep(&context, "@");
-       if (ast_strlen_zero(context))
+       if (ast_strlen_zero(context)) {
                context = "default";
+       }
 
-       event = ast_event_get_cached(AST_EVENT_MWI,
-               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-               AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-               AST_EVENT_IE_END);
+       ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
+       mwi_message = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
 
-       if (event) {
-               new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
-               ast_event_destroy(event);
-       } else
+       if (mwi_message) {
+               struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
+               new_msgs = mwi_state->new_msgs;
+       } else {
                new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
+       }
 
        return new_msgs;
 }
@@ -5324,7 +4899,7 @@ static int send_callerid(struct dahdi_pvt *p)
 
 static int dahdi_callwait(struct ast_channel *ast)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        struct ast_format tmpfmt;
        p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
        if (p->cidspill) {
@@ -5358,7 +4933,7 @@ static int dahdi_callwait(struct ast_channel *ast)
 
 static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        int x, res, mysig;
        char *dest;
        AST_DECLARE_APP_ARGS(args,
@@ -5395,12 +4970,12 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
                ast_copy_string(p->exten, args.ext, sizeof(p->exten));
        }
 
-       if ((ast->_state == AST_STATE_BUSY)) {
+       if ((ast_channel_state(ast) == AST_STATE_BUSY)) {
                p->subs[SUB_REAL].needbusy = 1;
                ast_mutex_unlock(&p->lock);
                return 0;
        }
-       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+       if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
                ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
                ast_mutex_unlock(&p->lock);
                return -1;
@@ -5420,11 +4995,11 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
                ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
        p->outgoing = 1;
 
-       if (IS_DIGITAL(ast->transfercapability)){
+       if (IS_DIGITAL(ast_channel_transfercapability(ast))){
                set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
        } else {
                set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
-       }       
+       }
 
 #ifdef HAVE_PRI
        if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -5444,7 +5019,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 #endif /* defined(HAVE_SS7) */
 
        /* If this is analog signalling we can exit here */
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                p->callwaitrings = 0;
                res = analog_call(p->sig_pvt, ast, rdest, timeout);
                ast_mutex_unlock(&p->lock);
@@ -5476,7 +5051,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 
                c = args.ext;
                if (!p->hidecallerid) {
-                       l = ast->connected.id.number.valid ? ast->connected.id.number.str : NULL;
+                       l = ast_channel_connected(ast)->id.number.valid ? ast_channel_connected(ast)->id.number.str : NULL;
                } else {
                        l = NULL;
                }
@@ -5795,7 +5370,7 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
        }
 
        if (p->sig_pvt) {
-               if (analog_lib_handles(p->sig, 0, 0)) {
+               if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
                        analog_delete(p->sig_pvt);
                }
                switch (p->sig) {
@@ -5814,20 +5389,27 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
                }
        }
        ast_free(p->cidspill);
-       if (p->use_smdi)
+       if (p->use_smdi) {
                ast_smdi_interface_unref(p->smdi_iface);
-       if (p->mwi_event_sub)
-               ast_event_unsubscribe(p->mwi_event_sub);
+       }
+       if (p->mwi_event_sub) {
+               p->mwi_event_sub = stasis_unsubscribe(p->mwi_event_sub);
+       }
        if (p->vars) {
                ast_variables_destroy(p->vars);
        }
        if (p->cc_params) {
                ast_cc_config_params_destroy(p->cc_params);
        }
+
+       p->named_callgroups = ast_unref_namedgroups(p->named_callgroups);
+       p->named_pickupgroups = ast_unref_namedgroups(p->named_pickupgroups);
+
        ast_mutex_destroy(&p->lock);
        dahdi_close_sub(p, SUB_REAL);
-       if (p->owner)
-               p->owner->tech_pvt = NULL;
+       if (p->owner) {
+               ast_channel_tech_pvt_set(p->owner, NULL);
+       }
        ast_free(p);
 }
 
@@ -5924,7 +5506,7 @@ static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char
                return -1;
        }
 
-       p = (struct dahdi_pvt *)chan->tech_pvt;
+       p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
 
        if (!p) {
                ast_debug(1, "Unable to find technology private\n");
@@ -5946,7 +5528,7 @@ static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, cons
        /* Data will be our digit string */
        struct dahdi_pvt *pvt;
        char *parse;
-       int res = -1;
+       int res;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(destination);
                AST_APP_ARG(original);
@@ -5957,11 +5539,11 @@ static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, cons
                ast_debug(1, "No data sent to application!\n");
                return -1;
        }
-       if (chan->tech != &dahdi_tech) {
+       if (ast_channel_tech(chan) != &dahdi_tech) {
                ast_debug(1, "Only DAHDI technology accepted!\n");
                return -1;
        }
-       pvt = (struct dahdi_pvt *) chan->tech_pvt;
+       pvt = (struct dahdi_pvt *) ast_channel_tech_pvt(chan);
        if (!pvt) {
                ast_debug(1, "Unable to find technology private\n");
                return -1;
@@ -5993,10 +5575,17 @@ static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, cons
                args.reason = NULL;
        }
 
-       pri_send_callrerouting_facility_exec(pvt->sig_pvt, chan->_state, args.destination,
-               args.original, args.reason);
+       res = pri_send_callrerouting_facility_exec(pvt->sig_pvt, ast_channel_state(chan),
+               args.destination, args.original, args.reason);
+       if (!res) {
+               /*
+                * Wait up to 5 seconds for a reply before hanging up this call
+                * leg if the peer does not disconnect first.
+                */
+               ast_safe_sleep(chan, 5000);
+       }
 
-       return res;
+       return -1;
 }
 #endif /* defined(HAVE_PRI_PROG_W_CAUSE) */
 #endif /* defined(HAVE_PRI) */
@@ -6021,12 +5610,12 @@ static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
                return -1;
        }
 
-       if (chan->tech != &dahdi_tech) {
+       if (ast_channel_tech(chan) != &dahdi_tech) {
                ast_debug(1, "Only DAHDI technology accepted!\n");
                return -1;
        }
 
-       p = (struct dahdi_pvt *)chan->tech_pvt;
+       p = (struct dahdi_pvt *)ast_channel_tech_pvt(chan);
        if (!p) {
                ast_debug(1, "Unable to find technology private!\n");
                return -1;
@@ -6078,6 +5667,7 @@ static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
                if (res == 0) {
                        continue;
                }
+               res = 0;
                f = ast_read(chan);
                if (!f) {
                        ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
@@ -6172,18 +5762,18 @@ static int dahdi_hangup(struct ast_channel *ast)
        int idx,x;
        int law;
        /*static int restore_gains(struct dahdi_pvt *p);*/
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        struct dahdi_params par;
 
        ast_debug(1, "dahdi_hangup(%s)\n", ast_channel_name(ast));
-       if (!ast->tech_pvt) {
+       if (!ast_channel_tech_pvt(ast)) {
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
        }
 
        ast_mutex_lock(&p->lock);
        p->exten[0] = '\0';
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                dahdi_confmute(p, 0);
                restore_gains(p);
                p->ignoredtmf = 0;
@@ -6241,14 +5831,14 @@ static int dahdi_hangup(struct ast_channel *ast)
                sig_pri_hangup(p->sig_pvt, ast);
 
                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
                x = 0;
                ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
                p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
                p->rdnis[0] = '\0';
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
 
                /* Restore data mode */
@@ -6303,13 +5893,13 @@ static int dahdi_hangup(struct ast_channel *ast)
                sig_ss7_hangup(p->sig_pvt, ast);
 
                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
                x = 0;
                ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
                p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
 
                /* Restore data mode */
@@ -6388,10 +5978,9 @@ static int dahdi_hangup(struct ast_channel *ast)
                                swap_subs(p, SUB_CALLWAIT, SUB_REAL);
                                unalloc_sub(p, SUB_CALLWAIT);
                                p->owner = p->subs[SUB_REAL].owner;
-                               if (p->owner->_state != AST_STATE_UP)
+                               if (ast_channel_state(p->owner) != AST_STATE_UP)
                                        p->subs[SUB_REAL].needanswer = 1;
-                               if (ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->subs[SUB_REAL].owner);
                        } else if (p->subs[SUB_THREEWAY].dfd > -1) {
                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                unalloc_sub(p, SUB_THREEWAY);
@@ -6412,10 +6001,8 @@ static int dahdi_hangup(struct ast_channel *ast)
                        if (p->subs[SUB_CALLWAIT].inthreeway) {
                                /* This is actually part of a three way, placed on hold.  Place the third part
                                   on music on hold now */
-                               if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-                                       ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               if (p->subs[SUB_THREEWAY].owner) {
+                                       ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
                                }
                                p->subs[SUB_THREEWAY].inthreeway = 0;
                                /* Make it the call wait now */
@@ -6427,10 +6014,8 @@ static int dahdi_hangup(struct ast_channel *ast)
                        if (p->subs[SUB_CALLWAIT].inthreeway) {
                                /* The other party of the three way call is currently in a call-wait state.
                                   Start music on hold for them, and take the main guy out of the third call */
-                               if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
-                                       ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               if (p->subs[SUB_CALLWAIT].owner) {
+                                       ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
                                }
                                p->subs[SUB_CALLWAIT].inthreeway = 0;
                        }
@@ -6476,7 +6061,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                                const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
                                int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
                                openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
-                                                                                     : dahdi_ast_cause_to_r2_cause(ast->hangupcause);
+                                                                                     : dahdi_ast_cause_to_r2_cause(ast_channel_hangupcause(ast));
                                dahdi_r2_disconnect_call(p, r2cause);
                        }
                } else if (p->mfcr2call) {
@@ -6525,7 +6110,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                case SIG_FXSKS:
                        /* Make sure we're not made available for at least two seconds assuming
                        we were actually used for an inbound or outbound call. */
-                       if (ast->_state != AST_STATE_RESERVED) {
+                       if (ast_channel_state(ast) != AST_STATE_RESERVED) {
                                time(&p->guardtime);
                                p->guardtime += 2;
                        }
@@ -6535,7 +6120,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                        break;
                }
                if (p->sig)
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                x = 0;
                ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
                ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
@@ -6546,7 +6131,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                p->waitingfordt.tv_sec = 0;
                p->dialing = 0;
                p->rdnis[0] = '\0';
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
                /* Restore data mode */
                switch (p->sig) {
@@ -6567,7 +6152,7 @@ static int dahdi_hangup(struct ast_channel *ast)
        p->cid_suppress_expire = 0;
        p->oprmode = 0;
 hangup_out:
-       ast->tech_pvt = NULL;
+       ast_channel_tech_pvt_set(ast, NULL);
        ast_free(p->cidspill);
        p->cidspill = NULL;
 
@@ -6590,7 +6175,7 @@ hangup_out:
 
 static int dahdi_answer(struct ast_channel *ast)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        int res = 0;
        int idx;
        ast_setstate(ast, AST_STATE_UP);/*! \todo XXX this is redundantly set by the analog and PRI submodules! */
@@ -6604,7 +6189,7 @@ static int dahdi_answer(struct ast_channel *ast)
                return 0;
        }
 
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                res = analog_answer(p->sig_pvt, ast);
                ast_mutex_unlock(&p->lock);
                return res;
@@ -6652,7 +6237,7 @@ static int dahdi_answer(struct ast_channel *ast)
        return res;
 }
 
-static void disable_dtmf_detect(struct dahdi_pvt *p)
+void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
 {
        int val = 0;
 
@@ -6666,7 +6251,7 @@ static void disable_dtmf_detect(struct dahdi_pvt *p)
        }
 }
 
-static void enable_dtmf_detect(struct dahdi_pvt *p)
+void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
 {
        int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
 
@@ -6686,7 +6271,7 @@ static void enable_dtmf_detect(struct dahdi_pvt *p)
 static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
 {
        char *cp;
-       struct dahdi_pvt *p = chan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
 
        /* all supported options require data */
        if (!p || !data || (*datalen < 1)) {
@@ -6730,7 +6315,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
        signed char *scp;
        int x;
        int idx;
-       struct dahdi_pvt *p = chan->tech_pvt, *pp;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan), *pp;
        struct oprmode *oprmode;
 
 
@@ -6791,7 +6376,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                }
                ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
                        (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
                /* otherwise, turn it on */
                if (!p->didtdd) { /* if havent done it yet */
                        unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
@@ -6873,7 +6458,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                if (!*cp) {
                        ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
                        x = 0;
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                } else {
                        ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
                        x = 1;
@@ -6884,13 +6469,13 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
        case AST_OPTION_OPRMODE:  /* Operator services mode */
                oprmode = (struct oprmode *) data;
                /* We don't support operator mode across technologies */
-               if (strcasecmp(chan->tech->type, oprmode->peer->tech->type)) {
+               if (strcasecmp(ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type)) {
                        ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n",
-                                       chan->tech->type, oprmode->peer->tech->type);
+                                       ast_channel_tech(chan)->type, ast_channel_tech(oprmode->peer)->type);
                        errno = EINVAL;
                        return -1;
                }
-               pp = oprmode->peer->tech_pvt;
+               pp = ast_channel_tech_pvt(oprmode->peer);
                p->oprmode = pp->oprmode = 0;
                /* setup peers */
                p->oprpeer = pp;
@@ -6908,19 +6493,19 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                cp = (char *) data;
                if (*cp) {
                        ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                } else {
                        ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                }
                break;
        case AST_OPTION_DIGIT_DETECT:
                cp = (char *) data;
                ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
                if (*cp) {
-                       enable_dtmf_detect(p);
+                       dahdi_dtmf_detect_enable(p);
                } else {
-                       disable_dtmf_detect(p);
+                       dahdi_dtmf_detect_disable(p);
                }
                break;
        case AST_OPTION_FAX_DETECT:
@@ -6945,7 +6530,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
 
 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
 {
-       struct dahdi_pvt *p = chan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
        int res = 0;
 
        if (!p) {
@@ -7084,7 +6669,7 @@ static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy
 
 static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
 {
-       struct dahdi_pvt *p = chan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
        int res = 0;
 
        if (!p) {
@@ -7115,11 +6700,11 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
        } else if (!strcasecmp(data, "echocan_mode")) {
                if (!strcasecmp(value, "on")) {
                        ast_mutex_lock(&p->lock);
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        ast_mutex_unlock(&p->lock);
                } else if (!strcasecmp(value, "off")) {
                        ast_mutex_lock(&p->lock);
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        ast_mutex_unlock(&p->lock);
 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
                } else if (!strcasecmp(value, "fax")) {
@@ -7127,7 +6712,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
                        ast_mutex_lock(&p->lock);
                        if (!p->echocanon) {
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                        }
                        if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
                                ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -7138,7 +6723,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
                        ast_mutex_lock(&p->lock);
                        if (!p->echocanon) {
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                        }
                        if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
                                ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -7156,7 +6741,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
        return res;
 }
 
-static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
+void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
 {
        /* Unlink a specific slave or all slaves/masters from a given master */
        int x;
@@ -7204,7 +6789,7 @@ static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int
                }
                master->master = NULL;
        }
-       update_conf(master);
+       dahdi_conf_update(master);
        if (needlock) {
                if (slave)
                        ast_mutex_unlock(&slave->lock);
@@ -7212,7 +6797,8 @@ static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int
        }
 }
 
-static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
+void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
+{
        int x;
        if (!slave || !master) {
                ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
@@ -7235,376 +6821,9 @@ static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
        ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
-{
-       struct ast_channel *who;
-       struct dahdi_pvt *p0, *p1, *op0, *op1;
-       struct dahdi_pvt *master = NULL, *slave = NULL;
-       struct ast_frame *f;
-       int inconf = 0;
-       int nothingok = 1;
-       int ofd0, ofd1;
-       int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
-       int os0 = -1, os1 = -1;
-       int priority = 0;
-       struct ast_channel *oc0, *oc1;
-       enum ast_bridge_result res;
-#ifdef PRI_2BCT
-       int triedtopribridge = 0;
-       q931_call *q931c0;
-       q931_call *q931c1;
-#endif
-
-       /* For now, don't attempt to native bridge if either channel needs DTMF detection.
-          There is code below to handle it properly until DTMF is actually seen,
-          but due to currently unresolved issues it's ignored...
-       */
-
-       if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
-               return AST_BRIDGE_FAILED_NOWARN;
-
-       ast_channel_lock(c0);
-       while (ast_channel_trylock(c1)) {
-               CHANNEL_DEADLOCK_AVOIDANCE(c0);
-       }
-
-       p0 = c0->tech_pvt;
-       p1 = c1->tech_pvt;
-       /* cant do pseudo-channels here */
-       if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               return AST_BRIDGE_FAILED_NOWARN;
-       }
-
-       oi0 = dahdi_get_index(c0, p0, 0);
-       oi1 = dahdi_get_index(c1, p1, 0);
-       if ((oi0 < 0) || (oi1 < 0)) {
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               return AST_BRIDGE_FAILED;
-       }
-
-       op0 = p0 = c0->tech_pvt;
-       op1 = p1 = c1->tech_pvt;
-       ofd0 = c0->fds[0];
-       ofd1 = c1->fds[0];
-       oc0 = p0->owner;
-       oc1 = p1->owner;
-
-       if (ast_mutex_trylock(&p0->lock)) {
-               /* Don't block, due to potential for deadlock */
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
-               return AST_BRIDGE_RETRY;
-       }
-       if (ast_mutex_trylock(&p1->lock)) {
-               /* Don't block, due to potential for deadlock */
-               ast_mutex_unlock(&p0->lock);
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
-               return AST_BRIDGE_RETRY;
-       }
-
-       if ((p0->callwaiting && p0->callwaitingcallerid)
-               || (p1->callwaiting && p1->callwaitingcallerid)) {
-               /*
-                * Call Waiting Caller ID requires DTMF detection to know if it
-                * can send the CID spill.
-                *
-                * For now, don't attempt to native bridge if either channel
-                * needs DTMF detection.  There is code below to handle it
-                * properly until DTMF is actually seen, but due to currently
-                * unresolved issues it's ignored...
-                */
-               ast_mutex_unlock(&p0->lock);
-               ast_mutex_unlock(&p1->lock);
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               return AST_BRIDGE_FAILED_NOWARN;
-       }
-
-#if defined(HAVE_PRI)
-       if ((dahdi_sig_pri_lib_handles(p0->sig)
-                       && ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
-               || (dahdi_sig_pri_lib_handles(p1->sig)
-                       && ((struct sig_pri_chan *) p1->sig_pvt)->no_b_channel)) {
-               /*
-                * PRI nobch channels (hold and call waiting) are equivalent to
-                * pseudo channels and cannot be done here.
-                */
-               ast_mutex_unlock(&p0->lock);
-               ast_mutex_unlock(&p1->lock);
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-               return AST_BRIDGE_FAILED_NOWARN;
-       }
-#endif /* defined(HAVE_PRI) */
-
-       if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
-               if (p0->owner && p1->owner) {
-                       /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
-                       if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
-                               master = p0;
-                               slave = p1;
-                               inconf = 1;
-                       } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
-                               master = p1;
-                               slave = p0;
-                               inconf = 1;
-                       } else {
-                               ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
-                               ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
-                                       p0->channel,
-                                       oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
-                                       p0->subs[SUB_REAL].inthreeway, p0->channel,
-                                       oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
-                                       p1->subs[SUB_REAL].inthreeway);
-                       }
-                       nothingok = 0;
-               }
-       } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
-               if (p1->subs[SUB_THREEWAY].inthreeway) {
-                       master = p1;
-                       slave = p0;
-                       nothingok = 0;
-               }
-       } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
-               if (p0->subs[SUB_THREEWAY].inthreeway) {
-                       master = p0;
-                       slave = p1;
-                       nothingok = 0;
-               }
-       } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
-               /* We have a real and a call wait.  If we're in a three way call, put us in it, otherwise,
-                  don't put us in anything */
-               if (p1->subs[SUB_CALLWAIT].inthreeway) {
-                       master = p1;
-                       slave = p0;
-                       nothingok = 0;
-               }
-       } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
-               /* Same as previous */
-               if (p0->subs[SUB_CALLWAIT].inthreeway) {
-                       master = p0;
-                       slave = p1;
-                       nothingok = 0;
-               }
-       }
-       ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
-               master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
-       if (master && slave) {
-               /* Stop any tones, or play ringtone as appropriate.  If they're bridged
-                  in an active threeway call with a channel that is ringing, we should
-                  indicate ringing. */
-               if ((oi1 == SUB_THREEWAY) &&
-                       p1->subs[SUB_THREEWAY].inthreeway &&
-                       p1->subs[SUB_REAL].owner &&
-                       p1->subs[SUB_REAL].inthreeway &&
-                       (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
-                       ast_debug(1,
-                               "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
-                               p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
-                       tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
-                       os1 = p1->subs[SUB_REAL].owner->_state;
-               } else {
-                       ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
-                               p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
-                       tone_zone_play_tone(p0->subs[oi0].dfd, -1);
-               }
-               if ((oi0 == SUB_THREEWAY) &&
-                       p0->subs[SUB_THREEWAY].inthreeway &&
-                       p0->subs[SUB_REAL].owner &&
-                       p0->subs[SUB_REAL].inthreeway &&
-                       (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
-                       ast_debug(1,
-                               "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
-                               p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
-                       tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
-                       os0 = p0->subs[SUB_REAL].owner->_state;
-               } else {
-                       ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
-                               p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
-                       tone_zone_play_tone(p1->subs[oi1].dfd, -1);
-               }
-               if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
-                       if (!p0->echocanbridged || !p1->echocanbridged) {
-                               /* Disable echo cancellation if appropriate */
-                               dahdi_disable_ec(p0);
-                               dahdi_disable_ec(p1);
-                       }
-               }
-               dahdi_link(slave, master);
-               master->inconference = inconf;
-       } else if (!nothingok)
-               ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
-
-       update_conf(p0);
-       update_conf(p1);
-       t0 = p0->subs[SUB_REAL].inthreeway;
-       t1 = p1->subs[SUB_REAL].inthreeway;
-
-       ast_mutex_unlock(&p0->lock);
-       ast_mutex_unlock(&p1->lock);
-
-       ast_channel_unlock(c0);
-       ast_channel_unlock(c1);
-
-       /* Native bridge failed */
-       if ((!master || !slave) && !nothingok) {
-               dahdi_enable_ec(p0);
-               dahdi_enable_ec(p1);
-               return AST_BRIDGE_FAILED;
-       }
-
-       ast_verb(3, "Native bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
-
-       if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
-               disable_dtmf_detect(op0);
-
-       if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
-               disable_dtmf_detect(op1);
-
-       for (;;) {
-               struct ast_channel *c0_priority[2] = {c0, c1};
-               struct ast_channel *c1_priority[2] = {c1, c0};
-
-               /* Here's our main loop...  Start by locking things, looking for private parts,
-                  and then balking if anything is wrong */
-
-               ast_channel_lock(c0);
-               while (ast_channel_trylock(c1)) {
-                       CHANNEL_DEADLOCK_AVOIDANCE(c0);
-               }
-
-               p0 = c0->tech_pvt;
-               p1 = c1->tech_pvt;
-
-               if (op0 == p0)
-                       i0 = dahdi_get_index(c0, p0, 1);
-               if (op1 == p1)
-                       i1 = dahdi_get_index(c1, p1, 1);
-
-               ast_channel_unlock(c0);
-               ast_channel_unlock(c1);
-
-               if (!timeoutms ||
-                       (op0 != p0) ||
-                       (op1 != p1) ||
-                       (ofd0 != c0->fds[0]) ||
-                       (ofd1 != c1->fds[0]) ||
-                       (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) ||
-                       (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) ||
-                       (oc0 != p0->owner) ||
-                       (oc1 != p1->owner) ||
-                       (t0 != p0->subs[SUB_REAL].inthreeway) ||
-                       (t1 != p1->subs[SUB_REAL].inthreeway) ||
-                       (oi0 != i0) ||
-                       (oi1 != i1)) {
-                       ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
-                               op0->channel, oi0, op1->channel, oi1);
-                       res = AST_BRIDGE_RETRY;
-                       goto return_from_bridge;
-               }
-
-#ifdef PRI_2BCT
-               if (!triedtopribridge) {
-                       triedtopribridge = 1;
-                       if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
-                               ast_mutex_lock(&p0->pri->lock);
-                               switch (p0->sig) {
-                               case SIG_PRI_LIB_HANDLE_CASES:
-                                       q931c0 = ((struct sig_pri_chan *) (p0->sig_pvt))->call;
-                                       break;
-                               default:
-                                       q931c0 = NULL;
-                                       break;
-                               }
-                               switch (p1->sig) {
-                               case SIG_PRI_LIB_HANDLE_CASES:
-                                       q931c1 = ((struct sig_pri_chan *) (p1->sig_pvt))->call;
-                                       break;
-                               default:
-                                       q931c1 = NULL;
-                                       break;
-                               }
-                               if (q931c0 && q931c1) {
-                                       pri_channel_bridge(q931c0, q931c1);
-                               }
-                               ast_mutex_unlock(&p0->pri->lock);
-                       }
-               }
-#endif
-
-               who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
-               if (!who) {
-                       ast_debug(1, "Ooh, empty read...\n");
-                       continue;
-               }
-               f = ast_read(who);
-               switch (f ? f->frametype : AST_FRAME_CONTROL) {
-               case AST_FRAME_CONTROL:
-                       *fo = f;
-                       *rc = who;
-                       res = AST_BRIDGE_COMPLETE;
-                       goto return_from_bridge;
-               case AST_FRAME_DTMF_END:
-                       if ((who == c0) && p0->pulsedial) {
-                               ast_write(c1, f);
-                       } else if ((who == c1) && p1->pulsedial) {
-                               ast_write(c0, f);
-                       } else {
-                               *fo = f;
-                               *rc = who;
-                               res = AST_BRIDGE_COMPLETE;
-                               goto return_from_bridge;
-                       }
-                       break;
-               case AST_FRAME_TEXT:
-                       if (who == c0) {
-                               ast_write(c1, f);
-                       } else {
-                               ast_write(c0, f);
-                       }
-                       break;
-               case AST_FRAME_VOICE:
-                       /* Native bridge handles voice frames in hardware. */
-               case AST_FRAME_NULL:
-                       break;
-               default:
-                       ast_debug(1, "Chan '%s' is discarding frame of frametype:%d\n",
-                               ast_channel_name(who), f->frametype);
-                       break;
-               }
-               ast_frfree(f);
-
-               /* Swap who gets priority */
-               priority = !priority;
-       }
-
-return_from_bridge:
-       if (op0 == p0)
-               dahdi_enable_ec(p0);
-
-       if (op1 == p1)
-               dahdi_enable_ec(p1);
-
-       if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
-               enable_dtmf_detect(op0);
-
-       if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
-               enable_dtmf_detect(op1);
-
-       dahdi_unlink(slave, master, 1);
-
-       return res;
-}
-
 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
-       struct dahdi_pvt *p = newchan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
        int x;
 
        ast_mutex_lock(&p->lock);
@@ -7616,12 +6835,12 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        for (x = 0; x < 3; x++) {
                if (p->subs[x].owner == oldchan) {
                        if (!x) {
-                               dahdi_unlink(NULL, p, 0);
+                               dahdi_master_slave_unlink(NULL, p, 0);
                        }
                        p->subs[x].owner = newchan;
                }
        }
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                analog_fixup(oldchan, newchan, p->sig_pvt);
 #if defined(HAVE_PRI)
        } else if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -7632,11 +6851,11 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
                sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
 #endif /* defined(HAVE_SS7) */
        }
-       update_conf(p);
+       dahdi_conf_update(p);
 
        ast_mutex_unlock(&p->lock);
 
-       if (newchan->_state == AST_STATE_RINGING) {
+       if (ast_channel_state(newchan) == AST_STATE_RINGING) {
                dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
        }
        return 0;
@@ -7674,56 +6893,49 @@ static int dahdi_ring_phone(struct dahdi_pvt *p)
 
 static void *analog_ss_thread(void *data);
 
+/*!
+ * \internal
+ * \brief Attempt to transfer 3-way call.
+ *
+ * \param p DAHDI private structure.
+ *
+ * \note On entry these locks are held: real-call, private, 3-way call.
+ * \note On exit these locks are held: real-call, private.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
 static int attempt_transfer(struct dahdi_pvt *p)
 {
-       /* In order to transfer, we need at least one of the channels to
-          actually be in a call bridge.  We can't conference two applications
-          together (but then, why would we want to?) */
-       if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
-               /* The three-way person we're about to transfer to could still be in MOH, so
-                  stop if now if appropriate */
-               if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
-                       ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
-               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
-                       ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
-               }
-               if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
-                       tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
-               }
-                if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
-                       ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
-                                       ast_channel_name(ast_bridged_channel(p->subs[SUB_REAL].owner)), ast_channel_name(p->subs[SUB_THREEWAY].owner));
-                       return -1;
-               }
-               /* Orphan the channel after releasing the lock */
-               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
-               unalloc_sub(p, SUB_THREEWAY);
-       } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
-               if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
-                       ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
-               }
-               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
-                       tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
-               }
-               if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
-                       ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
-                                       ast_channel_name(ast_bridged_channel(p->subs[SUB_THREEWAY].owner)), ast_channel_name(p->subs[SUB_REAL].owner));
-                       return -1;
-               }
-               /* Three-way is now the REAL */
-               swap_subs(p, SUB_THREEWAY, SUB_REAL);
-               ast_channel_unlock(p->subs[SUB_REAL].owner);
-               unalloc_sub(p, SUB_THREEWAY);
-               /* Tell the caller not to hangup */
-               return 1;
-       } else {
-               ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
-                       ast_channel_name(p->subs[SUB_REAL].owner), ast_channel_name(p->subs[SUB_THREEWAY].owner));
-               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
-               return -1;
+       struct ast_channel *owner_real;
+       struct ast_channel *owner_3way;
+       enum ast_transfer_result xfer_res;
+       int res = 0;
+
+       owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
+       owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
+
+       ast_verb(3, "TRANSFERRING %s to %s\n",
+               ast_channel_name(owner_3way), ast_channel_name(owner_real));
+
+       ast_channel_unlock(owner_real);
+       ast_channel_unlock(owner_3way);
+       ast_mutex_unlock(&p->lock);
+
+       xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
+       if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
+               ast_softhangup(owner_3way, AST_SOFTHANGUP_DEV);
+               res = -1;
        }
-       return 0;
+
+       /* Must leave with these locked. */
+       ast_channel_lock(owner_real);
+       ast_mutex_lock(&p->lock);
+
+       ast_channel_unref(owner_real);
+       ast_channel_unref(owner_3way);
+
+       return res;
 }
 
 static int check_for_conference(struct dahdi_pvt *p)
@@ -7781,7 +6993,7 @@ static int get_alarms(struct dahdi_pvt *p)
 
 static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        struct ast_frame *f = *dest;
 
        ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
@@ -7850,7 +7062,7 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
                                        ast_mutex_unlock(&p->lock);
                                        ast_channel_unlock(ast);
                                        if (ast_exists_extension(ast, target_context, "fax", 1,
-                                               S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+                                               S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
                                                ast_channel_lock(ast);
                                                ast_mutex_lock(&p->lock);
                                                ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast));
@@ -7877,24 +7089,58 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
        }
 }
 
+static void publish_span_alarm(int span, const char *alarm_txt)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       body = ast_json_pack("{s: i, s: s}",
+               "Span", span,
+               "Alarm", alarm_txt);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_channel_alarm(int channel, const char *alarm_txt)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+       if (!dahdi_chan) {
+               return;
+       }
+
+       ast_str_set(&dahdi_chan, 0, "%d", channel);
+       body = ast_json_pack("{s: s, s: s}",
+               "DAHDIChannel", ast_str_buffer(dahdi_chan),
+               "Alarm", alarm_txt);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM, body);
+}
+
 static void handle_alarms(struct dahdi_pvt *p, int alms)
 {
-       const char *alarm_str = alarm2str(alms);
+       const char *alarm_str;
+
+#if defined(HAVE_PRI)
+       if (dahdi_sig_pri_lib_handles(p->sig) && sig_pri_is_alarm_ignored(p->pri)) {
+               return;
+       }
+#endif /* defined(HAVE_PRI) */
 
+       alarm_str = alarm2str(alms);
        if (report_alarms & REPORT_CHANNEL_ALARMS) {
                ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
-               manager_event(EVENT_FLAG_SYSTEM, "Alarm",
-                                         "Alarm: %s\r\n"
-                                         "Channel: %d\r\n",
-                                         alarm_str, p->channel);
+               publish_channel_alarm(p->channel, alarm_str);
        }
 
        if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
                ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
-               manager_event(EVENT_FLAG_SYSTEM, "SpanAlarm",
-                                         "Alarm: %s\r\n"
-                                         "Span: %d\r\n",
-                                         alarm_str, p->span);
+               publish_span_alarm(p->span, alarm_str);
        }
 }
 
@@ -7903,12 +7149,15 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
        int res, x;
        int idx, mysig;
        char *c;
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        pthread_t threadid;
        struct ast_channel *chan;
        struct ast_frame *f;
 
        idx = dahdi_get_index(ast, p, 0);
+       if (idx < 0) {
+               return &ast_null_frame;
+       }
        mysig = p->sig;
        if (p->outsigmod > -1)
                mysig = p->outsigmod;
@@ -7922,8 +7171,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
        p->subs[idx].f.data.ptr = NULL;
        f = &p->subs[idx].f;
 
-       if (idx < 0)
-               return &p->subs[idx].f;
        if (p->fake_event) {
                res = p->fake_event;
                p->fake_event = 0;
@@ -8003,9 +7250,10 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 #else
                ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
 #endif
+               break;
        case DAHDI_EVENT_PULSE_START:
                /* Stop tone if there's a pulse start and the PBX isn't started */
-               if (!ast->pbx)
+               if (!ast_channel_pbx(ast))
                        tone_zone_play_tone(p->subs[idx].dfd, -1);
                break;
        case DAHDI_EVENT_DIALCOMPLETE:
@@ -8033,7 +7281,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                }
 #endif /* defined(HAVE_PRI) */
 #ifdef HAVE_OPENR2
-               if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
+               if ((p->sig & SIG_MFCR2) && p->r2chan && ast_channel_state(ast) != AST_STATE_UP) {
                        /* we don't need to do anything for this event for R2 signaling
                           if the call is being setup */
                        break;
@@ -8046,18 +7294,18 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                        return NULL;
                }
                if (!x) { /* if not still dialing in driver */
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        if (p->echobreak) {
                                dahdi_train_ec(p);
                                ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
                                p->dop.op = DAHDI_DIAL_OP_REPLACE;
-                               res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+                               res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
                                p->echobreak = 0;
                        } else {
                                p->dialing = 0;
                                if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
                                        /* if thru with dialing after offhook */
-                                       if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
+                                       if (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK) {
                                                ast_setstate(ast, AST_STATE_UP);
                                                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
                                                p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
@@ -8067,7 +7315,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
                                        }
                                }
-                               if (ast->_state == AST_STATE_DIALING) {
+                               if (ast_channel_state(ast) == AST_STATE_DIALING) {
                                        if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
                                                ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
                                        } else if (p->confirmanswer || (!p->dialednone
@@ -8167,7 +7415,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        p->cid_suppress_expire = 0;
                                        p->owner = NULL;
                                        /* Don't start streaming audio yet if the incoming call isn't up yet */
-                                       if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
+                                       if (ast_channel_state(p->subs[SUB_REAL].owner) != AST_STATE_UP)
                                                p->dialing = 1;
                                        dahdi_ring_phone(p);
                                } else if (p->subs[SUB_THREEWAY].owner) {
@@ -8198,36 +7446,32 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                   hanging up.  Hangup both channels now */
                                                if (p->subs[SUB_THREEWAY].owner)
                                                        ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
-                                               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                               ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
                                                ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
-                                       } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
+                                       } else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
                                                if (p->transfer) {
                                                        /* In any case this isn't a threeway call anymore */
                                                        p->subs[SUB_REAL].inthreeway = 0;
                                                        p->subs[SUB_THREEWAY].inthreeway = 0;
                                                        /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
-                                                       if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
+                                                       if (!p->transfertobusy && ast_channel_state(ast) == AST_STATE_BUSY) {
                                                                ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
                                                                /* Swap subs and dis-own channel */
                                                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                                                p->owner = NULL;
                                                                /* Ring the phone */
                                                                dahdi_ring_phone(p);
-                                                       } else {
-                                                               if ((res = attempt_transfer(p)) < 0) {
-                                                                       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
-                                                                       if (p->subs[SUB_THREEWAY].owner)
-                                                                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
-                                                               } else if (res) {
-                                                                       /* Don't actually hang up at this point */
-                                                                       if (p->subs[SUB_THREEWAY].owner)
-                                                                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
-                                                                       break;
-                                                               }
+                                                       } else if (!attempt_transfer(p)) {
+                                                               /*
+                                                                * Transfer successful.  Don't actually hang up at this point.
+                                                                * Let our channel legs of the calls die off as the transfer
+                                                                * percolates through the core.
+                                                                */
+                                                               break;
                                                        }
                                                } else {
-                                                       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                       ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                        if (p->subs[SUB_THREEWAY].owner)
                                                                ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
                                                }
@@ -8245,7 +7489,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                        }
                        /* Fall through */
                default:
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        return NULL;
                }
                break;
@@ -8270,7 +7514,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                }
                /* for E911, its supposed to wait for offhook then dial
                   the second half of the dial string */
-               if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
+               if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast_channel_state(ast) == AST_STATE_DIALING_OFFHOOK)) {
                        c = strchr(p->dialdest, '/');
                        if (c)
                                c++;
@@ -8286,14 +7530,11 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
                        } else
                                p->echobreak = 0;
-                       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
-                               int saveerr = errno;
-
+                       if (dahdi_dial_str(p, p->dop.op, p->dop.dialstr)) {
                                x = DAHDI_ONHOOK;
                                ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
-                               ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
                                return NULL;
-                               }
+                       }
                        p->dialing = 1;
                        return &p->subs[idx].f;
                }
@@ -8301,9 +7542,9 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_FXOLS:
                case SIG_FXOGS:
                case SIG_FXOKS:
-                       switch (ast->_state) {
+                       switch (ast_channel_state(ast)) {
                        case AST_STATE_RINGING:
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                                dahdi_train_ec(p);
                                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
                                p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
@@ -8325,9 +7566,8 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        p->subs[idx].f.subclass.integer = 0;
                                } else if (!ast_strlen_zero(p->dop.dialstr)) {
                                        /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
-                                       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
-                                       if (res < 0) {
-                                               ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
+                                       res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
+                                       if (res) {
                                                p->dop.dialstr[0] = '\0';
                                                return NULL;
                                        } else {
@@ -8343,7 +7583,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                return &p->subs[idx].f;
                        case AST_STATE_DOWN:
                                ast_setstate(ast, AST_STATE_RING);
-                               ast->rings = 1;
+                               ast_channel_rings_set(ast, 1);
                                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
                                p->subs[idx].f.subclass.integer = AST_CONTROL_OFFHOOK;
                                ast_debug(1, "channel %d picked up\n", p->channel);
@@ -8352,8 +7592,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                /* Make sure it stops ringing */
                                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
                                /* Okay -- probably call waiting*/
-                               if (ast_bridged_channel(p->owner))
-                                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                                p->subs[idx].needunhold = 1;
                                break;
                        case AST_STATE_RESERVED:
@@ -8364,13 +7603,13 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
                                break;
                        default:
-                               ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
+                               ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast_channel_state(ast));
                        }
                        break;
                case SIG_FXSLS:
                case SIG_FXSGS:
                case SIG_FXSKS:
-                       if (ast->_state == AST_STATE_RING) {
+                       if (ast_channel_state(ast) == AST_STATE_RING) {
                                p->ringt = p->ringt_base;
                        }
 
@@ -8397,13 +7636,13 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_SF_FEATD:
                case SIG_SF_FEATDMF:
                case SIG_SF_FEATB:
-                       if (ast->_state == AST_STATE_PRERING)
+                       if (ast_channel_state(ast) == AST_STATE_PRERING)
                                ast_setstate(ast, AST_STATE_RING);
-                       if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
+                       if ((ast_channel_state(ast) == AST_STATE_DOWN) || (ast_channel_state(ast) == AST_STATE_RING)) {
                                ast_debug(1, "Ring detected\n");
                                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
                                p->subs[idx].f.subclass.integer = AST_CONTROL_RING;
-                       } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
+                       } else if (p->outgoing && ((ast_channel_state(ast) == AST_STATE_RINGING) || (ast_channel_state(ast) == AST_STATE_DIALING))) {
                                ast_debug(1, "Line answered\n");
                                if (p->confirmanswer) {
                                        p->subs[idx].f.frametype = AST_FRAME_NULL;
@@ -8413,8 +7652,8 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
                                        ast_setstate(ast, AST_STATE_UP);
                                }
-                       } else if (ast->_state != AST_STATE_RING)
-                               ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
+                       } else if (ast_channel_state(ast) != AST_STATE_RING)
+                               ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast_channel_state(ast), p->channel);
                        break;
                default:
                        ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
@@ -8425,7 +7664,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_FXSLS:
                case SIG_FXSGS:
                case SIG_FXSKS:
-                       if (ast->_state == AST_STATE_RING) {
+                       if (ast_channel_state(ast) == AST_STATE_RING) {
                                p->ringt = p->ringt_base;
                        }
                        break;
@@ -8499,7 +7738,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
                                p->owner = p->subs[SUB_REAL].owner;
                                ast_debug(1, "Making %s the new owner\n", ast_channel_name(p->owner));
-                               if (p->owner->_state == AST_STATE_RINGING) {
+                               if (ast_channel_state(p->owner) == AST_STATE_RINGING) {
                                        ast_setstate(p->owner, AST_STATE_UP);
                                        p->subs[SUB_REAL].needanswer = 1;
                                }
@@ -8507,17 +7746,11 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                p->cidcwexpire = 0;
                                p->cid_suppress_expire = 0;
                                /* Start music on hold if appropriate */
-                               if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
-                                       ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               if (!p->subs[SUB_CALLWAIT].inthreeway) {
+                                       ast_queue_hold(p->subs[SUB_CALLWAIT].owner, p->mohsuggest);
                                }
                                p->subs[SUB_CALLWAIT].needhold = 1;
-                               if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
-                                       ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
-                                               S_OR(p->mohsuggest, NULL),
-                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
-                               }
+                               ast_queue_hold(p->subs[SUB_REAL].owner, p->mohsuggest);
                                p->subs[SUB_REAL].needunhold = 1;
                        } else if (!p->subs[SUB_THREEWAY].owner) {
                                if (!p->threewaycalling) {
@@ -8525,28 +7758,30 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        p->subs[SUB_REAL].needflash = 1;
                                        goto winkflashdone;
                                } else if (!check_for_conference(p)) {
+                                       struct ast_callid *callid = NULL;
+                                       int callid_created;
                                        char cid_num[256];
                                        char cid_name[256];
 
                                        cid_num[0] = 0;
                                        cid_name[0] = 0;
                                        if (p->dahditrcallerid && p->owner) {
-                                               if (p->owner->caller.id.number.valid
-                                                       && p->owner->caller.id.number.str) {
-                                                       ast_copy_string(cid_num, p->owner->caller.id.number.str,
+                                               if (ast_channel_caller(p->owner)->id.number.valid
+                                                       && ast_channel_caller(p->owner)->id.number.str) {
+                                                       ast_copy_string(cid_num, ast_channel_caller(p->owner)->id.number.str,
                                                                sizeof(cid_num));
                                                }
-                                               if (p->owner->caller.id.name.valid
-                                                       && p->owner->caller.id.name.str) {
-                                                       ast_copy_string(cid_name, p->owner->caller.id.name.str,
+                                               if (ast_channel_caller(p->owner)->id.name.valid
+                                                       && ast_channel_caller(p->owner)->id.name.str) {
+                                                       ast_copy_string(cid_name, ast_channel_caller(p->owner)->id.name.str,
                                                                sizeof(cid_name));
                                                }
                                        }
                                        /* XXX This section needs much more error checking!!! XXX */
                                        /* Start a 3-way call if feasible */
-                                       if (!((ast->pbx) ||
-                                               (ast->_state == AST_STATE_UP) ||
-                                               (ast->_state == AST_STATE_RING))) {
+                                       if (!((ast_channel_pbx(ast)) ||
+                                               (ast_channel_state(ast) == AST_STATE_UP) ||
+                                               (ast_channel_state(ast) == AST_STATE_RING))) {
                                                ast_debug(1, "Flash when call not up or ringing\n");
                                                goto winkflashdone;
                                        }
@@ -8554,8 +7789,18 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
                                                goto winkflashdone;
                                        }
-                                       /* Make new channel */
-                                       chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL);
+                                       callid_created = ast_callid_threadstorage_auto(&callid);
+                                       /*
+                                        * Make new channel
+                                        *
+                                        * We cannot hold the p or ast locks while creating a new
+                                        * channel.
+                                        */
+                                       ast_mutex_unlock(&p->lock);
+                                       ast_channel_unlock(ast);
+                                       chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, NULL, callid);
+                                       ast_channel_lock(ast);
+                                       ast_mutex_lock(&p->lock);
                                        if (p->dahditrcallerid) {
                                                if (!p->origcid_num)
                                                        p->origcid_num = ast_strdup(p->cid_num);
@@ -8567,7 +7812,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        /* Swap things around between the three-way and real call */
                                        swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                        /* Disable echo canceller for better dialing */
-                                       dahdi_disable_ec(p);
+                                       dahdi_ec_disable(p);
                                        res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
                                        if (res)
                                                ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
@@ -8577,19 +7822,16 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
                                                ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
                                                res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                                ast_hangup(chan);
                                        } else {
                                                ast_verb(3, "Started three way call on channel %d\n", p->channel);
 
-                                               /* Start music on hold if appropriate */
-                                               if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-                                                       ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
-                                                               S_OR(p->mohsuggest, NULL),
-                                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
-                                               }
+                                               /* Start music on hold */
+                                               ast_queue_hold(p->subs[SUB_THREEWAY].owner, p->mohsuggest);
                                                p->subs[SUB_THREEWAY].needhold = 1;
                                        }
+                                       ast_callid_threadstorage_auto_clean(callid, callid_created);
                                }
                        } else {
                                /* Already have a 3 way call */
@@ -8597,20 +7839,20 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        /* Call is already up, drop the last person */
                                        ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
                                        /* If the primary call isn't answered yet, use it */
-                                       if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
+                                       if ((ast_channel_state(p->subs[SUB_REAL].owner) != AST_STATE_UP) && (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_UP)) {
                                                /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
                                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                                p->owner = p->subs[SUB_REAL].owner;
                                        }
                                        /* Drop the last call and stop the conference */
                                        ast_verb(3, "Dropping three-way call on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
-                                       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                       ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                        p->subs[SUB_REAL].inthreeway = 0;
                                        p->subs[SUB_THREEWAY].inthreeway = 0;
                                } else {
                                        /* Lets see what we're up to */
-                                       if (((ast->pbx) || (ast->_state == AST_STATE_UP)) &&
-                                               (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
+                                       if (((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) &&
+                                               (p->transfertobusy || (ast_channel_state(ast) != AST_STATE_BUSY))) {
                                                int otherindex = SUB_THREEWAY;
 
                                                ast_verb(3, "Building conference call with %s and %s\n",
@@ -8619,28 +7861,30 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                /* Put them in the threeway, and flip */
                                                p->subs[SUB_THREEWAY].inthreeway = 1;
                                                p->subs[SUB_REAL].inthreeway = 1;
-                                               if (ast->_state == AST_STATE_UP) {
+                                               if (ast_channel_state(ast) == AST_STATE_UP) {
                                                        swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                                        otherindex = SUB_REAL;
                                                }
-                                               if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
-                                                       ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
+                                               if (p->subs[otherindex].owner) {
+                                                       ast_queue_unhold(p->subs[otherindex].owner);
+                                               }
                                                p->subs[otherindex].needunhold = 1;
                                                p->owner = p->subs[SUB_REAL].owner;
                                        } else {
                                                ast_verb(3, "Dumping incomplete call on on %s\n", ast_channel_name(p->subs[SUB_THREEWAY].owner));
                                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
-                                               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                               ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                p->owner = p->subs[SUB_REAL].owner;
-                                               if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                                       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                               if (p->subs[SUB_REAL].owner) {
+                                                       ast_queue_unhold(p->subs[SUB_REAL].owner);
+                                               }
                                                p->subs[SUB_REAL].needunhold = 1;
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                        }
                                }
                        }
 winkflashdone:
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                case SIG_EM:
                case SIG_EM_E1:
@@ -8653,18 +7897,18 @@ winkflashdone:
                        if (p->dialing)
                                ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
                        else
-                               ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
+                               ast_debug(1, "Got wink in weird state %d on channel %d\n", ast_channel_state(ast), p->channel);
                        break;
                case SIG_FEATDMF_TA:
                        switch (p->whichwink) {
                        case 0:
-                               ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->caller.ani2,
-                                       S_COR(p->owner->caller.ani.number.valid,
-                                               p->owner->caller.ani.number.str, ""));
+                               ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", ast_channel_caller(p->owner)->ani2,
+                                       S_COR(ast_channel_caller(p->owner)->ani.number.valid,
+                                               ast_channel_caller(p->owner)->ani.number.str, ""));
                                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#",
-                                       p->owner->caller.ani2,
-                                       S_COR(p->owner->caller.ani.number.valid,
-                                               p->owner->caller.ani.number.str, ""));
+                                       ast_channel_caller(p->owner)->ani2,
+                                       S_COR(ast_channel_caller(p->owner)->ani.number.valid,
+                                               ast_channel_caller(p->owner)->ani.number.str, ""));
                                break;
                        case 1:
                                ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
@@ -8685,9 +7929,8 @@ winkflashdone:
                case SIG_EMWINK:
                        /* FGD MF and EMWINK *Must* wait for wink */
                        if (!ast_strlen_zero(p->dop.dialstr)) {
-                               res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
-                               if (res < 0) {
-                                       ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
+                               res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
+                               if (res) {
                                        p->dop.dialstr[0] = '\0';
                                        return NULL;
                                } else
@@ -8715,9 +7958,8 @@ winkflashdone:
                case SIG_SFWINK:
                case SIG_SF_FEATD:
                        if (!ast_strlen_zero(p->dop.dialstr)) {
-                               res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
-                               if (res < 0) {
-                                       ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
+                               res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
+                               if (res) {
                                        p->dop.dialstr[0] = '\0';
                                        return NULL;
                                } else
@@ -8750,38 +7992,38 @@ winkflashdone:
                if (p->polarity == POLARITY_IDLE) {
                        p->polarity = POLARITY_REV;
                        if (p->answeronpolarityswitch &&
-                               ((ast->_state == AST_STATE_DIALING) ||
-                               (ast->_state == AST_STATE_RINGING))) {
+                               ((ast_channel_state(ast) == AST_STATE_DIALING) ||
+                               (ast_channel_state(ast) == AST_STATE_RINGING))) {
                                ast_debug(1, "Answering on polarity switch!\n");
                                ast_setstate(p->owner, AST_STATE_UP);
                                if (p->hanguponpolarityswitch) {
                                        p->polaritydelaytv = ast_tvnow();
                                }
                        } else
-                               ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
+                               ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast_channel_state(ast));
                }
                /* Removed else statement from here as it was preventing hangups from ever happening*/
                /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
                if (p->hanguponpolarityswitch &&
                        (p->polarityonanswerdelay > 0) &&
                        (p->polarity == POLARITY_REV) &&
-                       ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) {
+                       ((ast_channel_state(ast) == AST_STATE_UP) || (ast_channel_state(ast) == AST_STATE_RING)) ) {
                        /* Added log_debug information below to provide a better indication of what is going on */
-                       ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64 "\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
+                       ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64 "\n", p->channel, ast_channel_state(ast), p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
 
                        if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
                                ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
                                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
                                p->polarity = POLARITY_IDLE;
                        } else
-                               ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
+                               ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast_channel_state(ast));
 
                } else {
                        p->polarity = POLARITY_IDLE;
-                       ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
+                       ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast_channel_state(ast));
                }
                /* Added more log_debug information below to provide a better indication of what is going on */
-               ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64 "\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
+               ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %" PRIi64 "\n", p->channel, ast_channel_state(ast), p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
                break;
        default:
                ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
@@ -8795,9 +8037,11 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
        int idx;
        struct ast_frame *f;
        int usedindex = -1;
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
 
-       idx = dahdi_get_index(ast, p, 1);
+       if ((idx = dahdi_get_index(ast, p, 0)) < 0) {
+               idx = SUB_REAL;
+       }
 
        p->subs[idx].f.frametype = AST_FRAME_NULL;
        p->subs[idx].f.datalen = 0;
@@ -8826,13 +8070,14 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                        (res != DAHDI_EVENT_HOOKCOMPLETE)) {
                        ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
                        p->owner = p->subs[SUB_REAL].owner;
-                       if (p->owner && ast_bridged_channel(p->owner))
-                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                       if (p->owner) {
+                               ast_queue_unhold(p->owner);
+                       }
                        p->subs[SUB_REAL].needunhold = 1;
                }
                switch (res) {
                case DAHDI_EVENT_ONHOOK:
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        if (p->owner) {
                                ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
                                dahdi_ring_phone(p);
@@ -8841,12 +8086,12 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                                p->cid_suppress_expire = 0;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                case DAHDI_EVENT_RINGOFFHOOK:
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
-                       if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
+                       if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
                                p->subs[SUB_REAL].needanswer = 1;
                                p->dialing = 0;
                        }
@@ -8860,7 +8105,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                        p->flashtime = ast_tvnow();
                        if (p->owner) {
                                ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, ast_channel_name(p->owner));
-                               if (p->owner->_state != AST_STATE_UP) {
+                               if (ast_channel_state(p->owner) != AST_STATE_UP) {
                                        /* Answer if necessary */
                                        usedindex = dahdi_get_index(p->owner, p, 0);
                                        if (usedindex > -1) {
@@ -8871,12 +8116,11 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                                p->callwaitingrepeat = 0;
                                p->cidcwexpire = 0;
                                p->cid_suppress_expire = 0;
-                               if (ast_bridged_channel(p->owner))
-                                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+                               ast_queue_unhold(p->owner);
                                p->subs[SUB_REAL].needunhold = 1;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                default:
                        ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
@@ -8885,29 +8129,36 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                return f;
        }
        if (!(p->radio || (p->oprmode < 0)))
-               ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
+               ast_debug(1, "Exception on %d, channel %d\n", ast_channel_fd(ast, 0), p->channel);
        /* If it's not us, return NULL immediately */
        if (ast != p->owner) {
-               ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
+               if (p->owner) {
+                       ast_log(LOG_WARNING, "We're %s, not %s\n", ast_channel_name(ast), ast_channel_name(p->owner));
+               }
                f = &p->subs[idx].f;
                return f;
        }
+
        f = dahdi_handle_event(ast);
+       if (!f) {
+               const char *name = ast_strdupa(ast_channel_name(ast));
 
-       /* tell the cdr this zap device hung up */
-       if (f == NULL) {
-               ast_set_hangupsource(ast, ast_channel_name(ast), 0);
+               /* Tell the CDR this DAHDI device hung up */
+               ast_mutex_unlock(&p->lock);
+               ast_channel_unlock(ast);
+               ast_set_hangupsource(ast, name, 0);
+               ast_channel_lock(ast);
+               ast_mutex_lock(&p->lock);
        }
-
        return f;
 }
 
 static struct ast_frame *dahdi_exception(struct ast_channel *ast)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        struct ast_frame *f;
        ast_mutex_lock(&p->lock);
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                struct analog_pvt *analog_p = p->sig_pvt;
                f = analog_exception(analog_p, ast);
        } else {
@@ -8930,16 +8181,25 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
         * analog ports can have more than one Asterisk channel using
         * the same private structure.
         */
-       p = ast->tech_pvt;
+       p = ast_channel_tech_pvt(ast);
        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.
+                * Check to see if the channel is still associated with the same
+                * private structure.  While the Asterisk channel was unlocked
+                * the following events may have occured:
+                *
+                * 1) A masquerade may have associated the channel with another
+                * technology or private structure.
+                *
+                * 2) For PRI calls, call signaling could change the channel
+                * association to another B channel (private structure).
                 */
-               p = ast->tech_pvt;
+               if (ast_channel_tech_pvt(ast) != p) {
+                       /* The channel is no longer associated.  Quit gracefully. */
+                       return &ast_null_frame;
+               }
        }
 
        idx = dahdi_get_index(ast, p, 0);
@@ -9004,8 +8264,8 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                        /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
                         * now enqueue a progress frame to bridge the media up */
                        if (p->mfcr2_call_accepted &&
-                               !p->mfcr2_progress_sent && 
-                               ast->_state == AST_STATE_RINGING) {
+                               !p->mfcr2_progress_sent &&
+                               ast_channel_state(ast) == AST_STATE_RINGING) {
                                ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
                                ast_queue_frame(p->owner, &fr);
                                p->mfcr2_progress_sent = 1;
@@ -9095,7 +8355,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
         * if this channel owns the private.
         */
        if (p->fake_event && p->owner == ast) {
-               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                        struct analog_pvt *analog_p = p->sig_pvt;
 
                        f = analog_exception(analog_p, ast);
@@ -9106,15 +8366,15 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                return f;
        }
 
-       if (ast->rawreadformat.id == AST_FORMAT_SLINEAR) {
+       if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) {
                if (!p->subs[idx].linear) {
                        p->subs[idx].linear = 1;
                        res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
                        if (res)
                                ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
                }
-       } else if ((ast->rawreadformat.id == AST_FORMAT_ULAW) ||
-               (ast->rawreadformat.id == AST_FORMAT_ALAW)) {
+       } else if ((ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) ||
+               (ast_channel_rawreadformat(ast)->id == AST_FORMAT_ALAW)) {
                if (p->subs[idx].linear) {
                        p->subs[idx].linear = 0;
                        res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
@@ -9122,14 +8382,14 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
                }
        } else {
-               ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(&ast->rawreadformat));
+               ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast_channel_rawreadformat(ast)));
                ast_mutex_unlock(&p->lock);
                return NULL;
        }
        readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
        CHECK_BLOCKING(ast);
        res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-       ast_clear_flag(ast, AST_FLAG_BLOCKING);
+       ast_clear_flag(ast_channel_flags(ast), AST_FLAG_BLOCKING);
        /* Check for hangup */
        if (res < 0) {
                f = NULL;
@@ -9139,7 +8399,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                ast_mutex_unlock(&p->lock);
                                return &p->subs[idx].f;
                        } else if (errno == ELAST) {
-                               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                                        struct analog_pvt *analog_p = p->sig_pvt;
                                        f = analog_exception(analog_p, ast);
                                } else {
@@ -9153,7 +8413,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
        }
        if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
                ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                        struct analog_pvt *analog_p = p->sig_pvt;
                        f = analog_exception(analog_p, ast);
                } else {
@@ -9214,7 +8474,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
        }
 
        p->subs[idx].f.frametype = AST_FRAME_VOICE;
-       ast_format_copy(&p->subs[idx].f.subclass.format, &ast->rawreadformat);
+       ast_format_copy(&p->subs[idx].f.subclass.format, ast_channel_rawreadformat(ast));
        p->subs[idx].f.samples = READ_SIZE;
        p->subs[idx].f.mallocd = 0;
        p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
@@ -9223,7 +8483,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
        ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
 #endif
        if (p->dialing ||  p->radio || /* Transmitting something */
-               (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
+               (idx && (ast_channel_state(ast) != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
                ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
                ) {
                /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
@@ -9236,7 +8496,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                p->subs[idx].f.data.ptr = NULL;
                p->subs[idx].f.datalen= 0;
        }
-       if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec) && !idx) {
+       if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec || p->dialtone_detect) && !idx) {
                /* Perform busy detection etc on the dahdi line */
                int mute;
 
@@ -9250,10 +8510,26 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                }
 
                if (f) {
+                       if ((p->dsp_features & DSP_FEATURE_WAITDIALTONE) && (p->dialtone_detect > 0)
+                               && !p->outgoing && ast_channel_state(ast) == AST_STATE_UP) {
+                               if (++p->dialtone_scanning_time_elapsed >= p->dialtone_detect) {
+                                       p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE;
+                                       ast_dsp_set_features(p->dsp, p->dsp_features);
+                               }
+                       }
                        if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_BUSY)) {
-                               if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
-                                       /* Treat this as a "hangup" instead of a "busy" on the assumption that
-                                          a busy */
+                               if ((ast_channel_state(ast) == AST_STATE_UP) && !p->outgoing) {
+                                       /*
+                                        * Treat this as a "hangup" instead of a "busy" on the
+                                        * assumption that a busy means the incoming call went away.
+                                        */
+                                       ast_frfree(f);
+                                       f = NULL;
+                               }
+                       } else if (p->dialtone_detect && !p->outgoing && f->frametype == AST_FRAME_VOICE) {
+                               if ((ast_dsp_get_tstate(p->dsp) == DSP_TONE_STATE_DIALTONE) && (ast_dsp_get_tcount(p->dsp) > 9)) {
+                                       /* Dialtone detected on inbound call; hangup the channel */
+                                       ast_frfree(f);
                                        f = NULL;
                                }
                        } else if (f->frametype == AST_FRAME_DTMF_BEGIN
@@ -9279,7 +8555,8 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                if (ast_tvdiff_ms(ast_tvnow(), p->waitingfordt) >= p->waitfordialtone ) {
                                        p->waitingfordt.tv_sec = 0;
                                        ast_log(LOG_WARNING, "Never saw dialtone on channel %d\n", p->channel);
-                                       f=NULL;
+                                       ast_frfree(f);
+                                       f = NULL;
                                } else if (f->frametype == AST_FRAME_VOICE) {
                                        f->frametype = AST_FRAME_NULL;
                                        f->subclass.integer = 0;
@@ -9289,11 +8566,11 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                                ast_dsp_set_features(p->dsp, p->dsp_features);
                                                ast_debug(1, "Got 10 samples of dialtone!\n");
                                                if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */
-                                                       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
-                                                       if (res < 0) {
-                                                               ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel);
+                                                       res = dahdi_dial_str(p, p->dop.op, p->dop.dialstr);
+                                                       if (res) {
                                                                p->dop.dialstr[0] = '\0';
                                                                ast_mutex_unlock(&p->lock);
+                                                               ast_frfree(f);
                                                                return NULL;
                                                        } else {
                                                                ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
@@ -9314,7 +8591,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                switch (f->frametype) {
                case AST_FRAME_DTMF_BEGIN:
                case AST_FRAME_DTMF_END:
-                       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                                analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
                        } else {
                                dahdi_handle_dtmf(ast, idx, &f);
@@ -9365,7 +8642,7 @@ static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int
 
 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 {
-       struct dahdi_pvt *p = ast->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        int res;
        int idx;
        idx = dahdi_get_index(ast, p, 0);
@@ -9387,15 +8664,15 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
                return -1;
        }
        if (p->dialing) {
-               ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast_channel_name(ast));
+               ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",ast_channel_name(ast));
                return 0;
        }
        if (!p->owner) {
-               ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast_channel_name(ast));
+               ast_debug(5, "Dropping frame since there is no active owner on %s...\n",ast_channel_name(ast));
                return 0;
        }
        if (p->cidspill) {
-               ast_debug(1, "Dropping frame since I've still got a callerid spill on %s...\n",
+               ast_debug(5, "Dropping frame since I've still got a callerid spill on %s...\n",
                        ast_channel_name(ast));
                return 0;
        }
@@ -9430,7 +8707,7 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
 
 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
 {
-       struct dahdi_pvt *p = chan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
        int res=-1;
        int idx;
        int func = DAHDI_FLASH;
@@ -9470,8 +8747,8 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d
                case AST_CONTROL_RINGING:
                        res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
 
-                       if (chan->_state != AST_STATE_UP) {
-                               if ((chan->_state != AST_STATE_RING) ||
+                       if (ast_channel_state(chan) != AST_STATE_UP) {
+                               if ((ast_channel_state(chan) != AST_STATE_RING) ||
                                        ((p->sig != SIG_FXSKS) &&
                                 (p->sig != SIG_FXSLS) &&
                                 (p->sig != SIG_FXSGS)))
@@ -9495,12 +8772,12 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d
                        break;
                case AST_CONTROL_CONGESTION:
                        /* There are many cause codes that generate an AST_CONTROL_CONGESTION. */
-                       switch (chan->hangupcause) {
+                       switch (ast_channel_hangupcause(chan)) {
                        case AST_CAUSE_USER_BUSY:
                        case AST_CAUSE_NORMAL_CLEARING:
                        case 0:/* Cause has not been set. */
                                /* Supply a more appropriate cause. */
-                               chan->hangupcause = AST_CAUSE_CONGESTION;
+                               ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
                                break;
                        default:
                                break;
@@ -9597,7 +8874,16 @@ static struct ast_str *create_channel_name(struct dahdi_pvt *i)
        return chan_name;
 }
 
-static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid)
+static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid, int callid_created)
+{
+       struct ast_channel *new_channel = dahdi_new(i, state, startpbx, idx, law, linkedid, callid);
+
+       ast_callid_threadstorage_auto_clean(callid, callid_created);
+
+       return new_channel;
+}
+
+static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const char *linkedid, struct ast_callid *callid)
 {
        struct ast_channel *tmp;
        struct ast_format deflaw;
@@ -9629,9 +8915,17 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 
        tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name));
        ast_free(chan_name);
-       if (!tmp)
+       if (!tmp) {
                return NULL;
-       tmp->tech = &dahdi_tech;
+       }
+
+       ast_channel_stage_snapshot(tmp);
+
+       if (callid) {
+               ast_channel_callid_set(tmp, callid);
+       }
+
+       ast_channel_tech_set(tmp, &dahdi_tech);
 #if defined(HAVE_PRI)
        if (i->pri) {
                ast_cc_copy_config_params(i->cc_params, i->pri->cc_params);
@@ -9663,12 +8957,12 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                }
        }
        ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
-       ast_format_cap_add(tmp->nativeformats, &deflaw);
+       ast_format_cap_add(ast_channel_nativeformats(tmp), &deflaw);
        /* Start out assuming ulaw since it's smaller :) */
-       ast_format_copy(&tmp->rawreadformat, &deflaw);
-       ast_format_copy(&tmp->readformat, &deflaw);
-       ast_format_copy(&tmp->rawwriteformat, &deflaw);
-       ast_format_copy(&tmp->writeformat, &deflaw);
+       ast_format_copy(ast_channel_rawreadformat(tmp), &deflaw);
+       ast_format_copy(ast_channel_readformat(tmp), &deflaw);
+       ast_format_copy(ast_channel_rawwriteformat(tmp), &deflaw);
+       ast_format_copy(ast_channel_writeformat(tmp), &deflaw);
        i->subs[idx].linear = 0;
        dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
        features = 0;
@@ -9677,7 +8971,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                        features |= DSP_FEATURE_BUSY_DETECT;
                if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i))
                        features |= DSP_FEATURE_CALL_PROGRESS;
-               if ((i->waitfordialtone) && CANPROGRESSDETECT(i))
+               if ((i->waitfordialtone || i->dialtone_detect) && CANPROGRESSDETECT(i))
                        features |= DSP_FEATURE_WAITDIALTONE;
                if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) ||
                        (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) {
@@ -9723,13 +9017,17 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                }
        }
 
+       i->dialtone_scanning_time_elapsed = 0;
+
        if (state == AST_STATE_RING)
-               tmp->rings = 1;
-       tmp->tech_pvt = i;
+               ast_channel_rings_set(tmp, 1);
+       ast_channel_tech_pvt_set(tmp, i);
        if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
                /* Only FXO signalled stuff can be picked up */
-               tmp->callgroup = i->callgroup;
-               tmp->pickupgroup = i->pickupgroup;
+               ast_channel_callgroup_set(tmp, i->callgroup);
+               ast_channel_pickupgroup_set(tmp, i->pickupgroup);
+               ast_channel_named_callgroups_set(tmp, i->named_callgroups);
+               ast_channel_named_pickupgroups_set(tmp, i->named_pickupgroups);
        }
        if (!ast_strlen_zero(i->parkinglot))
                ast_channel_parkinglot_set(tmp, i->parkinglot);
@@ -9740,46 +9038,46 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        if (!ast_strlen_zero(i->accountcode))
                ast_channel_accountcode_set(tmp, i->accountcode);
        if (i->amaflags)
-               tmp->amaflags = i->amaflags;
+               ast_channel_amaflags_set(tmp, i->amaflags);
        i->subs[idx].owner = tmp;
        ast_channel_context_set(tmp, i->context);
-       if (!analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+       if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                ast_channel_call_forward_set(tmp, i->call_forward);
        }
        /* If we've been told "no ADSI" then enforce it */
        if (!i->adsi)
-               tmp->adsicpe = AST_ADSI_UNAVAILABLE;
+               ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
        if (!ast_strlen_zero(i->exten))
                ast_channel_exten_set(tmp, i->exten);
        if (!ast_strlen_zero(i->rdnis)) {
-               tmp->redirecting.from.number.valid = 1;
-               tmp->redirecting.from.number.str = ast_strdup(i->rdnis);
+               ast_channel_redirecting(tmp)->from.number.valid = 1;
+               ast_channel_redirecting(tmp)->from.number.str = ast_strdup(i->rdnis);
        }
        if (!ast_strlen_zero(i->dnid)) {
-               tmp->dialed.number.str = ast_strdup(i->dnid);
+               ast_channel_dialed(tmp)->number.str = ast_strdup(i->dnid);
        }
 
        /* Don't use ast_set_callerid() here because it will
         * generate a needless NewCallerID event */
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
        if (!ast_strlen_zero(i->cid_ani)) {
-               tmp->caller.ani.number.valid = 1;
-               tmp->caller.ani.number.str = ast_strdup(i->cid_ani);
+               ast_channel_caller(tmp)->ani.number.valid = 1;
+               ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_ani);
        } else if (!ast_strlen_zero(i->cid_num)) {
-               tmp->caller.ani.number.valid = 1;
-               tmp->caller.ani.number.str = ast_strdup(i->cid_num);
+               ast_channel_caller(tmp)->ani.number.valid = 1;
+               ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
        }
 #else
        if (!ast_strlen_zero(i->cid_num)) {
-               tmp->caller.ani.number.valid = 1;
-               tmp->caller.ani.number.str = ast_strdup(i->cid_num);
+               ast_channel_caller(tmp)->ani.number.valid = 1;
+               ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
        }
 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
-       tmp->caller.id.name.presentation = i->callingpres;
-       tmp->caller.id.number.presentation = i->callingpres;
-       tmp->caller.id.number.plan = i->cid_ton;
-       tmp->caller.ani2 = i->cid_ani2;
-       tmp->caller.id.tag = ast_strdup(i->cid_tag);
+       ast_channel_caller(tmp)->id.name.presentation = i->callingpres;
+       ast_channel_caller(tmp)->id.number.presentation = i->callingpres;
+       ast_channel_caller(tmp)->id.number.plan = i->cid_ton;
+       ast_channel_caller(tmp)->ani2 = i->cid_ani2;
+       ast_channel_caller(tmp)->id.tag = ast_strdup(i->cid_tag);
        /* clear the fake event in case we posted one before we had ast_channel */
        i->fake_event = 0;
        /* Assure there is no confmute on this channel */
@@ -9794,11 +9092,14 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        if (dashptr) {
                *dashptr = '\0';
        }
-       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
+       ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, device_name);
 
        for (v = i->vars ; v ; v = v->next)
                pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
+       ast_channel_stage_snapshot_done(tmp);
+
        ast_module_ref(ast_module_info->self);
 
        dahdi_ami_channel_event(i, tmp);
@@ -9855,6 +9156,26 @@ static int dahdi_wink(struct dahdi_pvt *p, int idx)
        return 0;
 }
 
+static void publish_dnd_state(int channel, const char *status)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
+       if (!dahdichan) {
+               return;
+       }
+
+       ast_str_set(&dahdichan, 0, "%d", channel);
+
+       body = ast_json_pack("{s: s, s: s}",
+               "DAHDIChannel", ast_str_buffer(dahdichan),
+               "Status", status);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
+}
+
 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
  * \param flag on 1 to enable, 0 to disable, -1 return dnd value
@@ -9866,7 +9187,7 @@ static int dahdi_wink(struct dahdi_pvt *p, int idx)
  */
 static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
 {
-       if (analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
+       if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
                return analog_dnd(dahdichan->sig_pvt, flag);
        }
 
@@ -9879,23 +9200,19 @@ static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
        ast_verb(3, "%s DND on channel %d\n",
                        flag? "Enabled" : "Disabled",
                        dahdichan->channel);
-       manager_event(EVENT_FLAG_SYSTEM, "DNDState",
-                       "Channel: DAHDI/%d\r\n"
-                       "Status: %s\r\n", dahdichan->channel,
-                       flag? "enabled" : "disabled");
-
+       publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
        return 0;
 }
 
-static int canmatch_featurecode(const char *exten)
+static int canmatch_featurecode(const char *pickupexten, const char *exten)
 {
        int extlen = strlen(exten);
-       const char *pickup_ext;
+
        if (!extlen) {
                return 1;
        }
-       pickup_ext = ast_pickup_ext();
-       if (extlen < strlen(pickup_ext) && !strncmp(pickup_ext, exten, extlen)) {
+
+       if (extlen < strlen(pickupexten) && !strncmp(pickupexten, exten, extlen)) {
                return 1;
        }
        /* hardcoded features are *60, *67, *69, *70, *72, *73, *78, *79, *82, *0 */
@@ -9917,7 +9234,7 @@ static int canmatch_featurecode(const char *exten)
 static void *analog_ss_thread(void *data)
 {
        struct ast_channel *chan = data;
-       struct dahdi_pvt *p = chan->tech_pvt;
+       struct dahdi_pvt *p = ast_channel_tech_pvt(chan);
        char exten[AST_MAX_EXTENSION] = "";
        char exten2[AST_MAX_EXTENSION] = "";
        unsigned char buf[256];
@@ -9941,6 +9258,8 @@ static void *analog_ss_thread(void *data)
        int res;
        int idx;
        struct ast_format tmpfmt;
+       RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
+       const char *pickupexten;
 
        ast_mutex_lock(&ss_thread_lock);
        ss_thread_count++;
@@ -9960,6 +9279,17 @@ static void *analog_ss_thread(void *data)
                ast_hangup(chan);
                goto quit;
        }
+
+       ast_channel_lock(chan);
+       pickup_cfg = ast_get_chan_features_pickup_config(chan);
+       if (!pickup_cfg) {
+               ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
+               pickupexten = "";
+       } else {
+               pickupexten = ast_strdupa(pickup_cfg->pickupexten);
+       }
+       ast_channel_unlock(chan);
+
        if (p->dsp)
                ast_dsp_digitreset(p->dsp);
        switch (p->sig) {
@@ -10194,7 +9524,7 @@ static void *analog_ss_thread(void *data)
                                goto quit;
                        }
                }
-               dahdi_enable_ec(p);
+               dahdi_ec_enable(p);
                if (NEED_MFDETECT(p)) {
                        if (p->dsp) {
                                if (!p->hardwaredtmf)
@@ -10207,7 +9537,7 @@ static void *analog_ss_thread(void *data)
                }
 
                if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1,
-                       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
+                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
                        ast_channel_exten_set(chan, exten);
                        if (p->dsp) ast_dsp_digitreset(p->dsp);
                        res = ast_pbx_run(chan);
@@ -10242,6 +9572,8 @@ static void *analog_ss_thread(void *data)
                if (p->subs[SUB_THREEWAY].owner)
                        timeout = 999999;
                while (len < AST_MAX_EXTENSION-1) {
+                       int is_exten_parking = 0;
+
                        /* Read digit unless it's supposed to be immediate, in which case the
                           only answer is 's' */
                        if (p->immediate)
@@ -10259,11 +9591,15 @@ static void *analog_ss_thread(void *data)
                                exten[len++]=res;
                                exten[len] = '\0';
                        }
-                       if (!ast_ignore_pattern(ast_channel_context(chan), exten))
+                       if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
                                tone_zone_play_tone(p->subs[idx].dfd, -1);
-                       else
+                       } else {
                                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
-                       if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
+                       }
+                       if (ast_parking_provider_registered()) {
+                               is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
+                       }
+                       if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
                                if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
                                        if (getforward) {
                                                /* Record this as the forwarding extension */
@@ -10293,7 +9629,7 @@ static void *analog_ss_thread(void *data)
                                                                ast_set_callerid(chan, NULL, p->cid_name, NULL);
                                                }
                                                ast_setstate(chan, AST_STATE_RING);
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                                res = ast_pbx_run(chan);
                                                if (res) {
                                                        ast_log(LOG_WARNING, "PBX exited non-zero\n");
@@ -10326,7 +9662,7 @@ static void *analog_ss_thread(void *data)
                                memset(exten, 0, sizeof(exten));
                                timeout = firstdigittimeout;
 
-                       } else if (!strcmp(exten,ast_pickup_ext())) {
+                       } else if (!strcmp(exten, pickupexten)) {
                                /* Scan all channels and see if there are any
                                 * ringing channels that have call groups
                                 * that equal this channels pickup group
@@ -10340,7 +9676,7 @@ static void *analog_ss_thread(void *data)
                                                swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
                                                unalloc_sub(p, SUB_THREEWAY);
                                        }
-                                       dahdi_enable_ec(p);
+                                       dahdi_ec_enable(p);
                                        if (ast_pickup_call(chan)) {
                                                ast_debug(1, "No call pickup possible...\n");
                                                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
@@ -10358,10 +9694,10 @@ static void *analog_ss_thread(void *data)
                                ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
                                /* Disable Caller*ID if enabled */
                                p->hidecallerid = 1;
-                               ast_party_number_free(&chan->caller.id.number);
-                               ast_party_number_init(&chan->caller.id.number);
-                               ast_party_name_free(&chan->caller.id.name);
-                               ast_party_name_init(&chan->caller.id.name);
+                               ast_party_number_free(&ast_channel_caller(chan)->id.number);
+                               ast_party_number_init(&ast_channel_caller(chan)->id.number);
+                               ast_party_name_free(&ast_channel_caller(chan)->id.name);
+                               ast_party_name_init(&ast_channel_caller(chan)->id.name);
                                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
                                if (res) {
                                        ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
@@ -10399,14 +9735,35 @@ static void *analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
-                                               p->subs[SUB_THREEWAY].owner &&
-                                               ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-                               /* This is a three way call, the main call being a real channel,
-                                       and we're parking the first call. */
-                               ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner),
-                                       chan, exten, ast_channel_context(chan), 0, NULL);
-                               ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+                       } else if ((p->transfer || p->canpark) && is_exten_parking
+                               && p->subs[SUB_THREEWAY].owner) {
+                               struct ast_bridge_channel *bridge_channel;
+
+                               /*
+                                * This is a three way call, the main call being a real channel,
+                                * and we're parking the first call.
+                                */
+                               ast_channel_lock(p->subs[SUB_THREEWAY].owner);
+                               bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
+                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+                               if (bridge_channel) {
+                                       if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+                                               /*
+                                                * Swap things around between the three-way and real call so we
+                                                * can hear where the channel got parked.
+                                                */
+                                               ast_mutex_lock(&p->lock);
+                                               p->owner = p->subs[SUB_THREEWAY].owner;
+                                               swap_subs(p, SUB_THREEWAY, SUB_REAL);
+                                               ast_mutex_unlock(&p->lock);
+
+                                               ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
+                                               ast_hangup(chan);
+                                               ao2_ref(bridge_channel, -1);
+                                               goto quit;
+                                       }
+                                       ao2_ref(bridge_channel, -1);
+                               }
                                break;
                        } else if (p->hidecallerid && !strcmp(exten, "*82")) {
                                ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
@@ -10425,12 +9782,15 @@ static void *analog_ss_thread(void *data)
                                struct ast_channel *nbridge =
                                        p->subs[SUB_THREEWAY].owner;
                                struct dahdi_pvt *pbridge = NULL;
+                               RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
+
                                /* set up the private struct of the bridged one, if any */
-                               if (nbridge && ast_bridged_channel(nbridge))
-                                       pbridge = ast_bridged_channel(nbridge)->tech_pvt;
+                               if (nbridge && bridged) {
+                                       pbridge = ast_channel_tech_pvt(bridged);
+                               }
                                if (nbridge && pbridge &&
-                                       (nbridge->tech == &dahdi_tech) &&
-                                       (ast_bridged_channel(nbridge)->tech == &dahdi_tech) &&
+                                       (ast_channel_tech(nbridge) == &dahdi_tech) &&
+                                       (ast_channel_tech(bridged) == &dahdi_tech) &&
                                        ISTRUNK(pbridge)) {
                                        int func = DAHDI_FLASH;
                                        /* Clear out the dial buffer */
@@ -10443,8 +9803,7 @@ static void *analog_ss_thread(void *data)
                                        swap_subs(p, SUB_REAL, SUB_THREEWAY);
                                        unalloc_sub(p, SUB_THREEWAY);
                                        p->owner = p->subs[SUB_REAL].owner;
-                                       if (ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+                                       ast_queue_unhold(p->subs[SUB_REAL].owner);
                                        ast_hangup(chan);
                                        goto quit;
                                } else {
@@ -10458,10 +9817,10 @@ static void *analog_ss_thread(void *data)
                                        goto quit;
                                }
                        } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), exten, 1,
-                               S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
-                               && !canmatch_featurecode(exten)) {
+                               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
+                               && !canmatch_featurecode(pickupexten, exten)) {
                                ast_debug(1, "Can't match %s from '%s' in context %s\n", exten,
-                                       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<Unknown Caller>"),
+                                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
                                        ast_channel_context(chan));
                                break;
                        }
@@ -10498,11 +9857,14 @@ static void *analog_ss_thread(void *data)
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
-               } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING &&
+               } else if (p->use_callerid && (ast_channel_state(chan) == AST_STATE_PRERING &&
                                                 (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN || p->cid_start == CID_START_DTMF_NOALERT))) {
                        /* If set to use DTMF CID signalling, listen for DTMF */
                        if (p->cid_signalling == CID_SIG_DTMF) {
                                int k = 0;
+                               int off_ms;
+                               struct timeval start = ast_tvnow();
+                               int ms;
                                cs = NULL;
                                ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
                                dahdi_setlinear(p->subs[idx].dfd, 0);
@@ -10512,11 +9874,13 @@ static void *analog_ss_thread(void *data)
                                 * emulation.  The DTMF digits can come so fast that emulation
                                 * can drop some of them.
                                 */
-                               ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
-                               res = 4000;/* This is a typical OFF time between rings. */
+                               ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
+                               off_ms = 4000;/* This is a typical OFF time between rings. */
                                for (;;) {
                                        struct ast_frame *f;
-                                       res = ast_waitfor(chan, res);
+
+                                       ms = ast_remaining_ms(start, off_ms);
+                                       res = ast_waitfor(chan, ms);
                                        if (res <= 0) {
                                                /*
                                                 * We do not need to restore the dahdi_setlinear()
@@ -10536,14 +9900,14 @@ static void *analog_ss_thread(void *data)
                                                        dtmfbuf[k++] = f->subclass.integer;
                                                }
                                                ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
-                                               res = 4000;/* This is a typical OFF time between rings. */
+                                               start = ast_tvnow();
                                        }
                                        ast_frfree(f);
-                                       if (chan->_state == AST_STATE_RING ||
-                                               chan->_state == AST_STATE_RINGING)
+                                       if (ast_channel_state(chan) == AST_STATE_RING ||
+                                               ast_channel_state(chan) == AST_STATE_RINGING)
                                                break; /* Got ring */
                                }
-                               ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
+                               ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
                                dtmfbuf[k] = '\0';
                                dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
                                /* Got cid and ring. */
@@ -10559,6 +9923,9 @@ static void *analog_ss_thread(void *data)
                        } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
                                cs = callerid_new(p->cid_signalling);
                                if (cs) {
+                                       int off_ms;
+                                       struct timeval start;
+                                       int ms;
                                        samples = 0;
 #if 1
                                        bump_gains(p);
@@ -10635,10 +10002,13 @@ static void *analog_ss_thread(void *data)
                                        }
 
                                        /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
-                                       res = 4000;/* This is a typical OFF time between rings. */
+                                       start = ast_tvnow();
+                                       off_ms = 4000;/* This is a typical OFF time between rings. */
                                        for (;;) {
                                                struct ast_frame *f;
-                                               res = ast_waitfor(chan, res);
+
+                                               ms = ast_remaining_ms(start, off_ms);
+                                               res = ast_waitfor(chan, ms);
                                                if (res <= 0) {
                                                        ast_log(LOG_WARNING, "CID timed out waiting for ring. "
                                                                "Exiting simple switch\n");
@@ -10651,8 +10021,8 @@ static void *analog_ss_thread(void *data)
                                                        goto quit;
                                                }
                                                ast_frfree(f);
-                                               if (chan->_state == AST_STATE_RING ||
-                                                       chan->_state == AST_STATE_RINGING)
+                                               if (ast_channel_state(chan) == AST_STATE_RING ||
+                                                       ast_channel_state(chan) == AST_STATE_RINGING)
                                                        break; /* Got ring */
                                        }
 
@@ -10766,12 +10136,18 @@ static void *analog_ss_thread(void *data)
                } else if (p->use_callerid && p->cid_start == CID_START_RING) {
                        if (p->cid_signalling == CID_SIG_DTMF) {
                                int k = 0;
+                               int off_ms;
+                               struct timeval start;
+                               int ms;
                                cs = NULL;
                                dahdi_setlinear(p->subs[idx].dfd, 0);
-                               res = 2000;
+                               off_ms = 2000;
+                               start = ast_tvnow();
                                for (;;) {
                                        struct ast_frame *f;
-                                       res = ast_waitfor(chan, res);
+
+                                       ms = ast_remaining_ms(start, off_ms);
+                                       res = ast_waitfor(chan, ms);
                                        if (res <= 0) {
                                                ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
                                                        "Exiting simple switch\n");
@@ -10787,7 +10163,7 @@ static void *analog_ss_thread(void *data)
                                        if (f->frametype == AST_FRAME_DTMF) {
                                                dtmfbuf[k++] = f->subclass.integer;
                                                ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
-                                               res = 2000;
+                                               start = ast_tvnow();
                                        }
                                        ast_frfree(f);
 
@@ -11017,7 +10393,7 @@ static void *analog_ss_thread(void *data)
                my_handle_notify_message(chan, p, flags, -1);
 
                ast_setstate(chan, AST_STATE_RING);
-               chan->rings = 1;
+               ast_channel_rings_set(chan, 1);
                p->ringt = p->ringt_base;
                res = ast_pbx_run(chan);
                if (res) {
@@ -11077,9 +10453,7 @@ static void *mwi_thread(void *data)
        struct ast_format tmpfmt;
 
        if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
-               mtd->pvt->mwimonitoractive = 0;
-
-               return NULL;
+               goto quit_no_clean;
        }
 
        callerid_feed(cs, mtd->buf, mtd->len, ast_format_set(&tmpfmt, AST_LAW(mtd->pvt), 0));
@@ -11095,6 +10469,8 @@ static void *mwi_thread(void *data)
 
                if (i & DAHDI_IOMUX_SIGEVENT) {
                        struct ast_channel *chan;
+                       struct ast_callid *callid = NULL;
+                       int callid_created;
 
                        /* If we get an event, screen out events that we do not act on.
                         * Otherwise, cancel and go to the simple switch to let it deal with it.
@@ -11108,7 +10484,7 @@ static void *mwi_thread(void *data)
                        case DAHDI_EVENT_BITSCHANGED:
                                break;
                        case DAHDI_EVENT_NOALARM:
-                               if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+                               if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                        struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
                                        analog_p->inalarm = 0;
@@ -11117,7 +10493,7 @@ static void *mwi_thread(void *data)
                                handle_clear_alarms(mtd->pvt);
                                break;
                        case DAHDI_EVENT_ALARM:
-                               if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+                               if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                        struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
                                        analog_p->inalarm = 1;
@@ -11127,15 +10503,17 @@ static void *mwi_thread(void *data)
                                handle_alarms(mtd->pvt, res);
                                break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
                        default:
+                               callid_created = ast_callid_threadstorage_auto(&callid);
                                ast_log(LOG_NOTICE, "Got event %d (%s)...  Passing along to analog_ss_thread\n", res, event2str(res));
                                callerid_free(cs);
 
                                restore_gains(mtd->pvt);
                                mtd->pvt->ringt = mtd->pvt->ringt_base;
 
-                               if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL))) {
+                               if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, callid))) {
                                        int result;
-                                       if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+
+                                       if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                                result = analog_ss_thread_start(mtd->pvt->sig_pvt, chan);
                                        } else {
                                                result = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
@@ -11146,13 +10524,13 @@ static void *mwi_thread(void *data)
                                                if (res < 0)
                                                        ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
                                                ast_hangup(chan);
-                                               goto quit;
                                        }
-                                       goto quit_no_clean;
-
                                } else {
                                        ast_log(LOG_WARNING, "Could not create channel to handle call\n");
                                }
+
+                               ast_callid_threadstorage_auto_clean(callid, callid_created);
+                               goto quit_no_clean;
                        }
                } else if (i & DAHDI_IOMUX_READ) {
                        if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
@@ -11207,7 +10585,6 @@ quit:
 
 quit_no_clean:
        mtd->pvt->mwimonitoractive = 0;
-
        ast_free(mtd);
 
        return NULL;
@@ -11404,34 +10781,128 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
        return handled;
 }
 
-/* destroy a DAHDI channel, identified by its number */
-static int dahdi_destroy_channel_bynum(int channel)
+/* destroy a range DAHDI channels, identified by their number */
+static void dahdi_destroy_channel_range(int start, int end)
 {
        struct dahdi_pvt *cur;
+       struct dahdi_pvt *next;
+       int destroyed_first = 0;
+       int destroyed_last = 0;
 
        ast_mutex_lock(&iflock);
-       for (cur = iflist; cur; cur = cur->next) {
-               if (cur->channel == channel) {
+       ast_debug(1, "range: %d-%d\n", start, end);
+       for (cur = iflist; cur; cur = next) {
+               next = cur->next;
+               if (cur->channel >= start && cur->channel <= end) {
                        int x = DAHDI_FLASH;
 
+                       if (cur->channel > destroyed_last) {
+                               destroyed_last = cur->channel;
+                       }
+                       if (destroyed_first < 1 || cur->channel < destroyed_first) {
+                               destroyed_first = cur->channel;
+                       }
+                       ast_debug(3, "Destroying %d\n", cur->channel);
                        /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
                        ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
 
                        destroy_channel(cur, 1);
-                       ast_mutex_unlock(&iflock);
                        ast_module_unref(ast_module_info->self);
-                       return RESULT_SUCCESS;
                }
        }
        ast_mutex_unlock(&iflock);
-       return RESULT_FAILURE;
+       if (destroyed_first > start || destroyed_last < end) {
+               ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
+                       start, end, destroyed_first, destroyed_last);
+       }
+}
+
+static int setup_dahdi(int reload);
+static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
+
+/*!
+ * \internal
+ * \brief create a range of new DAHDI channels
+ *
+ * \param start first channel in the range
+ * \param end last channel in the range
+ *
+ * \retval RESULT_SUCCESS on success.
+ * \retval RESULT_FAILURE on error.
+ */
+static int dahdi_create_channel_range(int start, int end)
+{
+       struct dahdi_pvt *cur;
+       struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
+       struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
+       struct dahdi_chan_conf conf = dahdi_chan_conf_default();
+       int i, x;
+       int ret = RESULT_FAILURE; /* be pessimistic */
+
+       ast_debug(1, "channel range caps: %d - %d\n", start, end);
+       ast_mutex_lock(&iflock);
+       for (cur = iflist; cur; cur = cur->next) {
+               if (cur->channel >= start && cur->channel <= end) {
+                       ast_log(LOG_ERROR,
+                               "channel range %d-%d is occupied\n",
+                               start, end);
+                       goto out;
+               }
+       }
+       for (x = 0; x < NUM_SPANS; x++) {
+#ifdef HAVE_PRI
+               struct dahdi_pri *pri = pris + x;
+
+               if (!pris[x].pri.pvts[0]) {
+                       break;
+               }
+               for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
+                       int channo = pri->dchannels[i];
+
+                       if (!channo) {
+                               break;
+                       }
+                       if (!pri->pri.fds[i]) {
+                               break;
+                       }
+                       if (channo >= start && channo <= end) {
+                               ast_log(LOG_ERROR,
+                                               "channel range %d-%d is occupied by span %d\n",
+                                               start, end, x + 1);
+                               goto out;
+                       }
+               }
+#endif
+       }
+       if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
+               !conf.chan.cc_params) {
+               goto out;
+       }
+       default_conf.wanted_channels_start = start;
+       base_conf.wanted_channels_start = start;
+       conf.wanted_channels_start = start;
+       default_conf.wanted_channels_end = end;
+       base_conf.wanted_channels_end = end;
+       conf.wanted_channels_end = end;
+       if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
+               ret = RESULT_SUCCESS;
+       }
+out:
+       ast_cc_config_params_destroy(default_conf.chan.cc_params);
+       ast_cc_config_params_destroy(base_conf.chan.cc_params);
+       ast_cc_config_params_destroy(conf.chan.cc_params);
+       ast_mutex_unlock(&iflock);
+       return ret;
 }
 
+
 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 {
        int res;
        pthread_t threadid;
        struct ast_channel *chan;
+       struct ast_callid *callid = NULL;
+       int callid_created;
 
        /* Handle an event on a given channel for the monitor thread. */
 
@@ -11449,8 +10920,11 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                case SIG_FXOGS:
                case SIG_FXOKS:
                        res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
-                       if (res && (errno == EBUSY))
+                       if (res && (errno == EBUSY)) {
                                break;
+                       }
+
+                       callid_created = ast_callid_threadstorage_auto(&callid);
 
                        /* Cancel VMWI spill */
                        ast_free(i->cidspill);
@@ -11458,10 +10932,10 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                        restore_conference(i);
 
                        if (i->immediate) {
-                               dahdi_enable_ec(i);
+                               dahdi_ec_enable(i);
                                /* The channel is immediately up.  Start right away */
                                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
-                               chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL);
+                               chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, callid);
                                if (!chan) {
                                        ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
                                        res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
@@ -11470,7 +10944,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                                }
                        } else {
                                /* Check for callerid, digits, etc */
-                               chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL);
+                               chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, NULL, callid);
                                if (chan) {
                                        if (has_voicemail(i))
                                                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
@@ -11488,6 +10962,8 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                                } else
                                        ast_log(LOG_WARNING, "Unable to create channel\n");
                        }
+
+                       ast_callid_threadstorage_auto_clean(callid, callid_created);
                        break;
                case SIG_FXSLS:
                case SIG_FXSGS:
@@ -11510,10 +10986,11 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                case SIG_SF_FEATB:
                case SIG_SF:
                        /* Check for callerid, digits, etc */
+                       callid_created = ast_callid_threadstorage_auto(&callid);
                        if (i->cid_start == CID_START_POLARITY_IN) {
-                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL);
+                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
                        } else {
-                               chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL);
+                               chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, NULL, callid);
                        }
 
                        if (!chan) {
@@ -11526,6 +11003,8 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                                }
                                ast_hangup(chan);
                        }
+
+                       ast_callid_threadstorage_auto_clean(callid, callid_created);
                        break;
                default:
                        ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
@@ -11602,7 +11081,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                case SIG_FXSGS:
                case SIG_FXSKS:
                case SIG_FXOKS:
-                       dahdi_disable_ec(i);
+                       dahdi_ec_disable(i);
                        /* Diddle the battery for the zhone */
 #ifdef ZHONE_HACK
                        dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
@@ -11613,7 +11092,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                        break;
                case SIG_SS7:
                case SIG_PRI_LIB_HANDLE_CASES:
-                       dahdi_disable_ec(i);
+                       dahdi_ec_disable(i);
                        res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
                        break;
                default:
@@ -11631,6 +11110,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                           created, but it wasn't handled. We need polarity
                           to be REV for remote hangup detection to work.
                           At least in Spain */
+                       callid_created = ast_callid_threadstorage_auto(&callid);
                        if (i->hanguponpolarityswitch)
                                i->polarity = POLARITY_REV;
                        if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
@@ -11638,13 +11118,15 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                                ast_verb(2, "Starting post polarity "
                                        "CID detection on channel %d\n",
                                        i->channel);
-                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL);
+                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
                                if (!chan) {
                                        ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
                                } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
                                        ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+                                       ast_hangup(chan);
                                }
                        }
+                       ast_callid_threadstorage_auto_clean(callid, callid_created);
                        break;
                default:
                        ast_log(LOG_WARNING, "handle_init_event detected "
@@ -11673,6 +11155,11 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
        return NULL;
 }
 
+static void monitor_pfds_clean(void *arg) {
+       struct pollfd **pfds = arg;
+       ast_free(*pfds);
+}
+
 static void *do_monitor(void *data)
 {
        int count, res, res2, spoint, pollres=0;
@@ -11696,6 +11183,7 @@ static void *do_monitor(void *data)
 #endif
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
+       pthread_cleanup_push(monitor_pfds_clean, &pfds);
        for (;;) {
                /* Lock the interface list */
                ast_mutex_lock(&iflock);
@@ -11717,20 +11205,19 @@ static void *do_monitor(void *data)
                count = 0;
                for (i = iflist; i; i = i->next) {
                        ast_mutex_lock(&i->lock);
-                       if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
-                               if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+                       if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
+                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                                        struct analog_pvt *p = i->sig_pvt;
 
-                                       if (!p)
+                                       if (!p) {
                                                ast_log(LOG_ERROR, "No sig_pvt?\n");
-
-                                       if (!p->owner && !p->subs[SUB_REAL].owner) {
+                                       } else if (!p->owner && !p->subs[SUB_REAL].owner) {
                                                /* This needs to be watched, as it lacks an owner */
                                                pfds[count].fd = i->subs[SUB_REAL].dfd;
                                                pfds[count].events = POLLPRI;
                                                pfds[count].revents = 0;
                                                /* Message waiting or r2 channels also get watched for reading */
-                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk || 
+                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
                                                        (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
                                                        pfds[count].events |= POLLIN;
                                                }
@@ -11780,11 +11267,7 @@ static void *do_monitor(void *data)
                doomed = NULL;
                for (i = iflist;; i = i->next) {
                        if (doomed) {
-                               int res;
-                               res = dahdi_destroy_channel_bynum(doomed->channel);
-                               if (res != RESULT_SUCCESS) {
-                                       ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
-                               }
+                               dahdi_destroy_channel_range(doomed->channel, doomed->channel);
                                doomed = NULL;
                        }
                        if (!i) {
@@ -11833,7 +11316,7 @@ static void *do_monitor(void *data)
                                                ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
                                                /* Don't hold iflock while handling init events */
                                                ast_mutex_unlock(&iflock);
-                                               if (analog_lib_handles(i->sig, i->radio, i->oprmode))
+                                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
                                                        doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
                                                else
                                                        doomed = handle_init_event(i, res);
@@ -11870,11 +11353,12 @@ static void *do_monitor(void *data)
                                                                        mtd->pvt = i;
                                                                        memcpy(mtd->buf, buf, res);
                                                                        mtd->len = res;
+                                                                       i->mwimonitoractive = 1;
                                                                        if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
                                                                                ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
+                                                                               i->mwimonitoractive = 0;
                                                                                ast_free(mtd);
                                                                        }
-                                                                       i->mwimonitoractive = 1;
                                                                }
                                                        }
                                                /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
@@ -11882,7 +11366,7 @@ static void *do_monitor(void *data)
                                                        int energy;
                                                        struct timeval now;
                                                        /* State machine dtmfcid_holdoff_state allows for the line to settle
-                                                        * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again 
+                                                        * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again
                                                        */
                                                        if (1 == i->dtmfcid_holdoff_state) {
                                                                gettimeofday(&i->dtmfcid_delay, NULL);
@@ -11898,22 +11382,26 @@ static void *do_monitor(void *data)
                                                                        pthread_t threadid;
                                                                        struct ast_channel *chan;
                                                                        ast_mutex_unlock(&iflock);
-                                                                       if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+                                                                       if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                                                                                /* just in case this event changes or somehow destroys a channel, set doomed here too */
-                                                                               doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);  
+                                                                               doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);
                                                                                i->dtmfcid_holdoff_state = 1;
                                                                        } else {
-                                                                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL);
+                                                                               struct ast_callid *callid = NULL;
+                                                                               int callid_created = ast_callid_threadstorage_auto(&callid);
+                                                                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, NULL, callid);
                                                                                if (!chan) {
                                                                                        ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
                                                                                } else {
                                                                                        res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
                                                                                        if (res) {
                                                                                                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+                                                                                               ast_hangup(chan);
                                                                                        } else {
                                                                                                i->dtmfcid_holdoff_state = 1;
                                                                                        }
                                                                                }
+                                                                               ast_callid_threadstorage_auto_clean(callid, callid_created);
                                                                        }
                                                                        ast_mutex_lock(&iflock);
                                                                }
@@ -11939,7 +11427,7 @@ static void *do_monitor(void *data)
                                        /* Don't hold iflock while handling init events */
                                        ast_mutex_unlock(&iflock);
                                        if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
-                                               if (analog_lib_handles(i->sig, i->radio, i->oprmode))
+                                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
                                                        doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
                                                else
                                                        doomed = handle_init_event(i, res);
@@ -11951,6 +11439,7 @@ static void *do_monitor(void *data)
                ast_mutex_unlock(&iflock);
        }
        /* Never reached */
+       pthread_cleanup_pop(1);
        return NULL;
 
 }
@@ -12150,14 +11639,20 @@ static void dahdi_r2_destroy_links(void)
        r2links_count = 0;
 }
 
-#define R2_LINK_CAPACITY 10
-static struct dahdi_mfcr2 *dahdi_r2_get_link(void)
+/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
+#define R2_LINK_CAPACITY 30
+static struct dahdi_mfcr2 *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
 {
        struct dahdi_mfcr2 *new_r2link = NULL;
        struct dahdi_mfcr2 **new_r2links = NULL;
-       /* this function is called just when starting up and no monitor threads have been launched,
-          no need to lock monitored_count member */
-       if (!r2links_count || (r2links[r2links_count - 1]->monitored_count == R2_LINK_CAPACITY)) {
+
+       /* Only create a new R2 link if
+          1. This is the first link requested
+          2. Configuration changed
+          3. We got more channels than supported per link */
+       if (!r2links_count ||
+           memcmp(&conf->mfcr2, &r2links[r2links_count - 1]->conf, sizeof(conf->mfcr2)) ||
+          (r2links[r2links_count - 1]->numchans == R2_LINK_CAPACITY)) {
                new_r2link = ast_calloc(1, sizeof(**r2links));
                if (!new_r2link) {
                        ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
@@ -12229,7 +11724,8 @@ static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_
                        ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", conf->mfcr2.r2proto_file);
                }
        }
-       r2_link->monitored_count = 0;
+       /* Save the configuration used to setup this link */
+       memcpy(&r2_link->conf, conf, sizeof(r2_link->conf));
        return 0;
 }
 #endif
@@ -12401,8 +11897,8 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                        tmp->sig = chan_sig;
                        tmp->outsigmod = conf->chan.outsigmod;
 
-                       if (analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
-                               analog_p = analog_new(dahdisig_to_analogsig(chan_sig), &dahdi_analog_callbacks, tmp);
+                       if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
+                               analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
                                if (!analog_p) {
                                        destroy_dahdi_pvt(tmp);
                                        return NULL;
@@ -12432,7 +11928,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                        destroy_dahdi_pvt(tmp);
                                        return NULL;
                                }
-                               ss7_chan = sig_ss7_chan_new(tmp, &dahdi_ss7_callbacks, &ss7->ss7);
+                               ss7_chan = sig_ss7_chan_new(tmp, &ss7->ss7);
                                if (!ss7_chan) {
                                        destroy_dahdi_pvt(tmp);
                                        return NULL;
@@ -12460,7 +11956,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #ifdef HAVE_OPENR2
                        if (chan_sig == SIG_MFCR2) {
                                struct dahdi_mfcr2 *r2_link;
-                               r2_link = dahdi_r2_get_link();
+                               r2_link = dahdi_r2_get_link(conf);
                                if (!r2_link) {
                                        ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
                                        destroy_dahdi_pvt(tmp);
@@ -12502,7 +11998,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                tmp->mfcr2call = 0;
                                tmp->mfcr2_dnis_index = 0;
                                tmp->mfcr2_ani_index = 0;
-                               r2_link->monitored_count++;
                        }
 #endif
 #ifdef HAVE_PRI
@@ -12591,8 +12086,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                                        return NULL;
                                                }
 
-                                               ast_debug(4, "Adding callbacks %p to chan %d\n", &dahdi_pri_callbacks, tmp->channel);
-                                               pri_chan = sig_pri_chan_new(tmp, &dahdi_pri_callbacks, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
+                                               pri_chan = sig_pri_chan_new(tmp, &pris[span].pri, tmp->logicalspan, p.chanpos, pris[span].mastertrunkgroup);
                                                if (!pri_chan) {
                                                        destroy_dahdi_pvt(tmp);
                                                        return NULL;
@@ -12654,11 +12148,19 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #if defined(HAVE_PRI_L2_PERSISTENCE)
                                                pris[span].pri.l2_persistence = conf->pri.pri.l2_persistence;
 #endif /* defined(HAVE_PRI_L2_PERSISTENCE) */
+                                               pris[span].pri.colp_send = conf->pri.pri.colp_send;
 #if defined(HAVE_PRI_AOC_EVENTS)
                                                pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
                                                pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                               if (chan_sig == SIG_BRI_PTMP) {
+                                                       pris[span].pri.layer1_ignored = conf->pri.pri.layer1_ignored;
+                                               } else {
+                                                       /* Option does not apply to this line type. */
+                                                       pris[span].pri.layer1_ignored = 0;
+                                               }
                                                pris[span].pri.append_msn_to_user_tag = conf->pri.pri.append_msn_to_user_tag;
+                                               pris[span].pri.inband_on_proceeding = conf->pri.pri.inband_on_proceeding;
                                                ast_copy_string(pris[span].pri.initial_user_tag, conf->chan.cid_tag, sizeof(pris[span].pri.initial_user_tag));
                                                ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
 #if defined(HAVE_PRI_MWI)
@@ -12859,6 +12361,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                tmp->busy_cadence = conf->chan.busy_cadence;
                tmp->callprogress = conf->chan.callprogress;
                tmp->waitfordialtone = conf->chan.waitfordialtone;
+               tmp->dialtone_detect = conf->chan.dialtone_detect;
                tmp->cancallforward = conf->chan.cancallforward;
                tmp->dtmfrelax = conf->chan.dtmfrelax;
                tmp->callwaiting = tmp->permcallwaiting;
@@ -12908,7 +12411,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
                ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
                tmp->cid_ton = 0;
-               if (analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
+               if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
                        ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
                        ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
                } else {
@@ -12927,15 +12430,20 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
                if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
                        char *mailbox, *context;
+                       struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
+                       struct stasis_topic *mailbox_specific_topic;
+
                        mailbox = context = ast_strdupa(tmp->mailbox);
                        strsep(&context, "@");
                        if (ast_strlen_zero(context))
                                context = "default";
-                       tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "Dahdi MWI subscription", NULL,
-                               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
-                               AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
-                               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
-                               AST_EVENT_IE_END);
+
+                       ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
+
+                       mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
+                       if (mailbox_specific_topic) {
+                               tmp->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, NULL);
+                       }
                }
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
                tmp->mwisend_setting = conf->chan.mwisend_setting;