[svn-commits] rmudgett: trunk r225692 - in /trunk: ./ channels/ configs/ include/asterisk/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Oct 23 11:57:37 CDT 2009


Author: rmudgett
Date: Fri Oct 23 11:57:33 2009
New Revision: 225692

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=225692
Log:
Add to chan_dahdi ISDN HOLD, Call deflection, and keypad facility support.

* Added handling of received HOLD/RETRIEVE messages and the optional ability
  to transfer a held call on disconnect similar to an analog phone.
* Added CallRerouting/CallDeflection support for Q.SIG, ETSI PTP, ETSI PTMP.
  Will reroute/deflect an outgoing call when receive the message.
  Can use the DAHDISendCallreroutingFacility to send the message for the
  supported switches.
* Added ability to send/receive keypad digits in the SETUP message.
  Send keypad digits in SETUP message: Dial(DAHDI/g1[/K<keypad_digits>][/extension])
  Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)}
* Added support for BRI PTMP NT mode.

Modified:
    trunk/CHANGES
    trunk/channels/chan_dahdi.c
    trunk/channels/sig_pri.c
    trunk/channels/sig_pri.h
    trunk/configs/chan_dahdi.conf.sample
    trunk/configure
    trunk/configure.ac
    trunk/include/asterisk/autoconfig.h.in

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=225692&r1=225691&r2=225692
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Fri Oct 23 11:57:33 2009
@@ -224,6 +224,16 @@
    configured via the rxdrc and txdrc parameters in chan_dahdi.conf.
  * Added support for ISDN calling and called subaddress with partial support
    for connected line subaddress.
+ * Added support for BRI PTMP NT mode. (Requires latest LibPRI.)
+ * Added handling of received HOLD/RETRIEVE messages and the optional ability
+   to transfer a held call on disconnect similar to an analog phone.
+ * Added CallRerouting/CallDeflection support for Q.SIG, ETSI PTP, ETSI PTMP.
+   Will reroute/deflect an outgoing call when receive the message.
+   Can use the DAHDISendCallreroutingFacility to send the message for the
+   supported switches.
+ * Added ability to send/receive keypad digits in the SETUP message.
+   Send keypad digits in SETUP message: Dial(DAHDI/g1[/K<keypad_digits>][/extension])
+   Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)}
 
 Asterisk Manager Interface
 --------------------------

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=225692&r1=225691&r2=225692
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Fri Oct 23 11:57:33 2009
@@ -684,6 +684,9 @@
 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 {
@@ -1261,6 +1264,15 @@
 static struct dahdi_pvt *iflist = NULL;	/*!< Main interface list start */
 static struct dahdi_pvt *ifend = NULL;	/*!< Main interface list end */
 
+#if defined(HAVE_PRI)
+static struct dahdi_parms_pseudo {
+	int buf_no;					/*!< Number of buffers */
+	int buf_policy;				/*!< Buffer policy */
+	int faxbuf_no;              /*!< Number of Fax buffers */
+	int faxbuf_policy;          /*!< Fax buffer policy */
+} dahdi_pseudo_parms;
+#endif	/* defined(HAVE_PRI) */
+
 /*! \brief Channel configuration from chan_dahdi.conf .
  * This struct is used for parsing the [channels] section of chan_dahdi.conf.
  * Generally there is a field here for every possible configuration item.
@@ -2762,6 +2774,8 @@
 	ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
 }
 
+static int dahdi_new_pri_nobch_channel(struct sig_pri_pri *pri);
+
 static struct sig_pri_callback dahdi_pri_callbacks =
 {
 	.handle_dchan_exception = my_handle_dchan_exception,
@@ -2776,6 +2790,7 @@
 	.set_callerid = my_pri_set_callerid,
 	.set_dnid = my_pri_set_dnid,
 	.set_rdnis = my_pri_set_rdnis,
+	.new_nobch_intf = dahdi_new_pri_nobch_channel,
 };
 #endif	/* defined(HAVE_PRI) */
 
@@ -4085,6 +4100,14 @@
 	if (p->echocancel.head.tap_length) {
 		switch (p->sig) {
 		case SIG_PRI_LIB_HANDLE_CASES:
+			if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
+				/*
+				 * PRI nobch pseudo channel.  Does not need ec anyway.
+				 * Does not handle ioctl(DAHDI_AUDIOMODE)
+				 */
+				return;
+			}
+			/* Fall through */
 		case SIG_SS7:
 			x = 1;
 			res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
@@ -4339,6 +4362,11 @@
 	x = muted;
 	switch (p->sig) {
 	case SIG_PRI_LIB_HANDLE_CASES:
+		if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
+			/* PRI nobch pseudo channel.  Does not handle ioctl(DAHDI_AUDIOMODE) */
+			break;
+		}
+		/* Fall through */
 	case SIG_SS7:
 		y = 1;
 		res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
@@ -4863,6 +4891,101 @@
 #if defined(HAVE_PRI)
 /*!
  * \internal
+ * \brief Insert the given chan_dahdi interface structure into the no B channel list.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span control structure holding no B channel list.
+ * \param pvt chan_dahdi private interface structure to insert.
+ *
+ * \details
+ * The interface list is a doubly linked list sorted by the chan_dahdi channel number.
+ * Any duplicates are inserted after the existing entries.
+ *
+ * \note The new interface must not already be in the list.
+ *
+ * \return Nothing
+ */
+static void dahdi_nobch_insert(struct sig_pri_pri *pri, struct dahdi_pvt *pvt)
+{
+	struct dahdi_pvt *cur;
+
+	pvt->which_iflist = DAHDI_IFLIST_NO_B_CHAN;
+
+	/* Find place in middle of list for the new interface. */
+	for (cur = pri->no_b_chan_iflist; cur; cur = cur->next) {
+		if (pvt->channel < cur->channel) {
+			/* New interface goes before the current interface. */
+			pvt->prev = cur->prev;
+			pvt->next = cur;
+			if (cur->prev) {
+				/* Insert into the middle of the list. */
+				cur->prev->next = pvt;
+			} else {
+				/* Insert at head of list. */
+				pri->no_b_chan_iflist = pvt;
+			}
+			cur->prev = pvt;
+			return;
+		}
+	}
+
+	/* New interface goes onto the end of the list */
+	pvt->prev = pri->no_b_chan_end;
+	pvt->next = NULL;
+	if (pri->no_b_chan_end) {
+		((struct dahdi_pvt *) pri->no_b_chan_end)->next = pvt;
+	}
+	pri->no_b_chan_end = pvt;
+	if (!pri->no_b_chan_iflist) {
+		/* List was empty */
+		pri->no_b_chan_iflist = pvt;
+	}
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Extract the given chan_dahdi interface structure from the no B channel list.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span control structure holding no B channel list.
+ * \param pvt chan_dahdi private interface structure to extract.
+ *
+ * \note
+ * The given interface structure can be either in the interface list or a stand alone
+ * structure that has not been put in the list if the next and prev pointers are NULL.
+ *
+ * \return Nothing
+ */
+static void dahdi_nobch_extract(struct sig_pri_pri *pri, struct dahdi_pvt *pvt)
+{
+	/* Extract from the forward chain. */
+	if (pvt->prev) {
+		pvt->prev->next = pvt->next;
+	} else if (pri->no_b_chan_iflist == pvt) {
+		/* Node is at the head of the list. */
+		pri->no_b_chan_iflist = pvt->next;
+	}
+
+	/* Extract from the reverse chain. */
+	if (pvt->next) {
+		pvt->next->prev = pvt->prev;
+	} else if (pri->no_b_chan_end == pvt) {
+		/* Node is at the end of the list. */
+		pri->no_b_chan_end = pvt->prev;
+	}
+
+	/* Node is no longer in the list. */
+	pvt->which_iflist = DAHDI_IFLIST_NONE;
+	pvt->prev = NULL;
+	pvt->next = NULL;
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
  * \brief Unlink the channel interface from the PRI private pointer array.
  * \since 1.6.3
  *
@@ -4906,6 +5029,13 @@
 	case DAHDI_IFLIST_MAIN:
 		dahdi_iflist_extract(p);
 		break;
+#if defined(HAVE_PRI)
+	case DAHDI_IFLIST_NO_B_CHAN:
+		if (p->pri) {
+			dahdi_nobch_extract(p->pri, p);
+		}
+		break;
+#endif	/* defined(HAVE_PRI) */
 	}
 
 	if (p->sig_pvt) {
@@ -4956,6 +5086,10 @@
 static void destroy_all_channels(void)
 {
 	int chan;
+#if defined(HAVE_PRI)
+	unsigned span;
+	struct sig_pri_pri *pri;
+#endif	/* defined(HAVE_PRI) */
 	struct dahdi_pvt *p;
 
 	while (num_restart_pending) {
@@ -4989,6 +5123,21 @@
 	}
 	ifcount = 0;
 	ast_mutex_unlock(&iflock);
+
+#if defined(HAVE_PRI)
+	/* Destroy all of the no B channel interface lists */
+	for (span = 0; span < NUM_SPANS; ++span) {
+		pri = &pris[span].pri;
+		ast_mutex_lock(&pri->lock);
+		while (pri->no_b_chan_iflist) {
+			p = pri->no_b_chan_iflist;
+
+			/* Free associated memory */
+			destroy_dahdi_pvt(p);
+		}
+		ast_mutex_unlock(&pri->lock);
+	}
+#endif	/* defined(HAVE_PRI) */
 }
 
 #if defined(HAVE_PRI)
@@ -5024,7 +5173,7 @@
 static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
 {
 	/* Data will be our digit string */
-	struct dahdi_pvt *p;
+	struct dahdi_pvt *pvt;
 	char *parse;
 	int res = -1;
 	AST_DECLARE_APP_ARGS(args,
@@ -5037,11 +5186,21 @@
 		ast_log(LOG_DEBUG, "No data sent to application!\n");
 		return -1;
 	}
-
-	p = (struct dahdi_pvt *)chan->tech_pvt;
-
-	if (!p) {
+	if (chan->tech != &dahdi_tech) {
+		ast_log(LOG_DEBUG, "Only DAHDI technology accepted!\n");
+		return -1;
+	}
+	pvt = (struct dahdi_pvt *) chan->tech_pvt;
+	if (!pvt) {
 		ast_log(LOG_DEBUG, "Unable to find technology private\n");
+		return -1;
+	}
+	switch (pvt->sig) {
+	case SIG_PRI_LIB_HANDLE_CASES:
+		break;
+	default:
+		ast_log(LOG_DEBUG, "callrerouting attempted on non-ISDN channel %s\n",
+			chan->name);
 		return -1;
 	}
 
@@ -5063,7 +5222,8 @@
 		args.reason = NULL;
 	}
 
-	pri_send_callrerouting_facility_exec(p->sig_pvt, chan->_state, args.destination, args.original, args.reason);
+	pri_send_callrerouting_facility_exec(pvt->sig_pvt, chan->_state, args.destination,
+		args.original, args.reason);
 
 	return res;
 }
@@ -5865,6 +6025,12 @@
 		ast_dsp_set_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
 		break;
 	case AST_OPTION_AUDIO_MODE:  /* Set AUDIO mode (or not) */
+		if (dahdi_sig_pri_lib_handles(p->sig)
+			&& ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
+			/* PRI nobch pseudo channel.  Does not handle ioctl(DAHDI_AUDIOMODE) */
+			break;
+		}
+
 		cp = (char *) data;
 		if (!*cp) {
 			ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
@@ -5954,6 +6120,7 @@
 		ast_mutex_lock(&p->lock);
 		snprintf(buf, len, "%f", p->txgain);
 		ast_mutex_unlock(&p->lock);
+#if defined(HAVE_PRI)
 #if defined(HAVE_PRI_REVERSE_CHARGE)
 	} else if (!strcasecmp(data, "reversecharge")) {
 		ast_mutex_lock(&p->lock);
@@ -5968,6 +6135,22 @@
 		}
 		ast_mutex_unlock(&p->lock);
 #endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+	} else if (!strcasecmp(data, "keypad_digits")) {
+		ast_mutex_lock(&p->lock);
+		switch (p->sig) {
+		case SIG_PRI_LIB_HANDLE_CASES:
+			ast_copy_string(buf, ((struct sig_pri_chan *) p->sig_pvt)->keypad_digits,
+				len);
+			break;
+		default:
+			*buf = '\0';
+			res = -1;
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
+#endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+#endif	/* defined(HAVE_PRI) */
 	} else {
 		*buf = '\0';
 		res = -1;
@@ -6224,6 +6407,21 @@
 		ast_channel_unlock(c1);
 		ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
 		return AST_BRIDGE_RETRY;
+	}
+
+	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;
 	}
 
 	if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
@@ -11115,6 +11313,10 @@
 #ifdef HAVE_PRI_INBANDDISCONNECT
 						pris[span].pri.inbanddisconnect = conf->pri.pri.inbanddisconnect;
 #endif
+#if defined(HAVE_PRI_CALL_HOLD)
+						pris[span].pri.hold_disconnect_transfer =
+							conf->pri.pri.hold_disconnect_transfer;
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
 						pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
 						ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
 						ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
@@ -11520,6 +11722,16 @@
 			ast_copy_string(pchan->mohinterpret, tmp->mohinterpret, sizeof(pchan->mohinterpret));
 			pchan->stripmsd = tmp->stripmsd;
 		}
+		if (tmp->channel == CHAN_PSEUDO) {
+			/*
+			 * Save off pseudo channel buffer policy values for dynamic creation of
+			 * no B channel interfaces.
+			 */
+			dahdi_pseudo_parms.buf_no = tmp->buf_no;
+			dahdi_pseudo_parms.buf_policy = tmp->buf_policy;
+			dahdi_pseudo_parms.faxbuf_no = tmp->faxbuf_no;
+			dahdi_pseudo_parms.faxbuf_policy = tmp->faxbuf_policy;
+		}
 #endif	/* defined(HAVE_PRI) */
 	}
 	if (tmp && !here) {
@@ -11590,6 +11802,110 @@
 
 	return 0;
 }
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Create a no B channel interface.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to add interface.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
+static int dahdi_new_pri_nobch_channel(struct sig_pri_pri *pri)
+{
+	int pvt_idx;
+	int res;
+	unsigned idx;
+	struct dahdi_pvt *pvt;
+	struct sig_pri_chan *chan;
+	struct dahdi_bufferinfo bi;
+
+	static int nobch_channel = CHAN_PSEUDO;
+
+	/* Find spot in the private pointer array for new interface. */
+	for (pvt_idx = 0; pvt_idx < pri->numchans; ++pvt_idx) {
+		if (!pri->pvts[pvt_idx]) {
+			break;
+		}
+	}
+	if (pri->numchans == pvt_idx) {
+		if (MAX_CHANNELS <= pvt_idx) {
+			ast_log(LOG_ERROR, "Unable to add a no-B-channel interface!\n");
+			return -1;
+		}
+
+		/* Add new spot to the private pointer array. */
+		pri->pvts[pvt_idx] = NULL;
+		++pri->numchans;
+	}
+
+	pvt = ast_calloc(1, sizeof(*pvt));
+	if (!pvt) {
+		return -1;
+	}
+	ast_mutex_init(&pvt->lock);
+	for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
+		pvt->subs[idx].dfd = -1;
+	}
+	pvt->buf_no = dahdi_pseudo_parms.buf_no;
+	pvt->buf_policy = dahdi_pseudo_parms.buf_policy;
+	pvt->faxbuf_no = dahdi_pseudo_parms.faxbuf_no;
+	pvt->faxbuf_policy = dahdi_pseudo_parms.faxbuf_policy;
+
+	chan = sig_pri_chan_new(pvt, &dahdi_pri_callbacks, pri, 0, 0, 0);
+	if (!chan) {
+		destroy_dahdi_pvt(pvt);
+		return -1;
+	}
+	chan->no_b_channel = 1;
+
+	pvt->sig = pri->sig;
+	pvt->pri = pri;
+	pvt->sig_pvt = chan;
+	pri->pvts[pvt_idx] = chan;
+
+	pvt->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
+	if (pvt->subs[SUB_REAL].dfd < 0) {
+		ast_log(LOG_ERROR, "Unable to open no B channel interface pseudo channel: %s\n",
+			strerror(errno));
+		destroy_dahdi_pvt(pvt);
+		return -1;
+	}
+	memset(&bi, 0, sizeof(bi));
+	res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
+	if (!res) {
+		pvt->bufsize = bi.bufsize;
+		bi.txbufpolicy = pvt->buf_policy;
+		bi.rxbufpolicy = pvt->buf_policy;
+		bi.numbufs = pvt->buf_no;
+		res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
+		if (res < 0) {
+			ast_log(LOG_WARNING,
+				"Unable to set buffer policy on no B channel interface: %s\n",
+				strerror(errno));
+		}
+	} else
+		ast_log(LOG_WARNING,
+			"Unable to check buffer policy on no B channel interface: %s\n",
+			strerror(errno));
+
+	--nobch_channel;
+	if (CHAN_PSEUDO < nobch_channel) {
+		nobch_channel = CHAN_PSEUDO - 1;
+	}
+	pvt->channel = nobch_channel;
+	chan->channel = pvt->channel;
+
+	dahdi_nobch_insert(pri, pvt);
+
+	return pvt_idx;
+}
+#endif	/* defined(HAVE_PRI) */
 
 /* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private
    structures; it makes no attempt to safely copy regular channel private
@@ -15771,7 +16087,12 @@
 					confp->chan.sig = SIG_BRI_PTMP;
 					confp->pri.pri.nodetype = PRI_CPE;
 				} else if (!strcasecmp(v->value, "bri_net_ptmp")) {
+#if defined(HAVE_PRI_CALL_HOLD)
+					confp->chan.sig = SIG_BRI_PTMP;
+					confp->pri.pri.nodetype = PRI_NETWORK;
+#else
 					ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode!  For now, sucks for you. (line %d)\n", v->lineno);
+#endif	/* !defined(HAVE_PRI_CALL_HOLD) */
 #endif
 #ifdef HAVE_SS7
 				} else if (!strcasecmp(v->value, "ss7")) {
@@ -16004,6 +16325,10 @@
 #endif /* PRI_GETSET_TIMERS */
 			} else if (!strcasecmp(v->name, "facilityenable")) {
 				confp->pri.pri.facilityenable = ast_true(v->value);
+#if defined(HAVE_PRI_CALL_HOLD)
+			} else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
+				confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #endif /* HAVE_PRI */
 #ifdef HAVE_SS7
 			} else if (!strcasecmp(v->name, "ss7type")) {

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=225692&r1=225691&r2=225692
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Fri Oct 23 11:57:33 2009
@@ -67,9 +67,12 @@
 #define DCHAN_NOTINALARM  (1 << 0)
 #define DCHAN_UP          (1 << 1)
 
-#define PRI_CHANNEL(p) ((p) & 0xff)
-#define PRI_SPAN(p) (((p) >> 8) & 0xff)
-#define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
+/* Defines to help decode the encoded event channel id. */
+#define PRI_CHANNEL(p)	((p) & 0xff)
+#define PRI_SPAN(p)		(((p) >> 8) & 0xff)
+#define PRI_EXPLICIT	(1 << 16)
+#define PRI_CIS_CALL	(1 << 17)	/* Call is using the D channel only. */
+#define PRI_HELD_CALL	(1 << 18)
 
 
 #define DCHAN_AVAILABLE	(DCHAN_NOTINALARM | DCHAN_UP)
@@ -90,7 +93,7 @@
 
 static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
 {
-	int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? 0x10000 : 0));
+	int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
 	ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
 		p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
 
@@ -828,74 +831,152 @@
 	pri_queue_frame(p, &f, pri);
 }
 
-static int pri_find_principle(struct sig_pri_pri *pri, int channel)
+static int pri_find_principle(struct sig_pri_pri *pri, int channel, q931_call *call)
 {
 	int x;
-	int span = PRI_SPAN(channel);
-	int principle = -1;
-	int explicit_ds1 = PRI_EXPLICIT(channel);
+	int span;
+	int principle;
+
+	if (channel < 0) {
+		/* Channel is not picked yet. */
+		return -1;
+	}
+
+	if (channel & PRI_HELD_CALL) {
+		if (!call) {
+			/* Cannot find a held call without a call. */
+			return -1;
+		}
+		principle = -1;
+		for (x = 0; x < pri->numchans; ++x) {
+			if (pri->pvts[x]
+				&& pri->pvts[x]->call == call) {
+				principle = x;
+				break;
+			}
+		}
+		return principle;
+	}
+
+	span = PRI_SPAN(channel);
+	if (!(channel & PRI_EXPLICIT)) {
+		int index;
+
+		index = pri_active_dchan_index(pri);
+		if (index == -1) {
+			return -1;
+		}
+		span = pri->dchan_logical_span[index];
+	}
+
 	channel = PRI_CHANNEL(channel);
-
-	if (!explicit_ds1) {
-		int index = pri_active_dchan_index(pri);
-		if (index == -1)
+	principle = -1;
+	for (x = 0; x < pri->numchans; x++) {
+		if (pri->pvts[x]
+			&& pri->pvts[x]->prioffset == channel
+			&& pri->pvts[x]->logicalspan == span
+			&& !pri->pvts[x]->no_b_channel) {
+			principle = x;
+			break;
+		}
+	}
+
+	return principle;
+}
+
+static int pri_fixup_principle(struct sig_pri_pri *pri, int principle, q931_call *call)
+{
+	int x;
+
+	if (principle < 0 || pri->numchans <= principle) {
+		/* Out of rannge */
+		return -1;
+	}
+	if (!call) {
+		/* No call */
+		return principle;
+	}
+	if (pri->pvts[principle] && pri->pvts[principle]->call == call) {
+		/* Call is already on the specified principle. */
+		return principle;
+	}
+
+	/* Find the old principle location. */
+	for (x = 0; x < pri->numchans; x++) {
+		struct sig_pri_chan *new_chan;
+		struct sig_pri_chan *old_chan;
+
+		if (!pri->pvts[x] || pri->pvts[x]->call != call) {
+			continue;
+		}
+
+		/* Found our call */
+		new_chan = pri->pvts[principle];
+		old_chan = pri->pvts[x];
+
+		ast_verb(3, "Moving call from channel %d to channel %d\n",
+			old_chan->channel, new_chan->channel);
+		if (new_chan->owner) {
+			ast_log(LOG_WARNING,
+				"Can't fix up channel from %d to %d because %d is already in use\n",
+				old_chan->channel, new_chan->channel, new_chan->channel);
 			return -1;
-		span = pri->dchan_logical_span[index];
-	}
-
-	for (x = 0; x < pri->numchans; x++) {
-		if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
-			principle = x;
-			break;
-		}
-	}
-
-	return principle;
-}
-
-static int pri_fixup_principle(struct sig_pri_pri *pri, int principle, q931_call *c)
-{
-	int x;
-
-	if (!c) {
-		if (principle < 0)
-			return -1;
+		}
+
+		sig_pri_fixup_chans(old_chan, new_chan);
+
+		/* Fix it all up now */
+		new_chan->owner = old_chan->owner;
+		old_chan->owner = NULL;
+
+		new_chan->call = old_chan->call;
+		old_chan->call = NULL;
+
+		/* Transfer flags from the old channel. */
+		new_chan->alerting = old_chan->alerting;
+		new_chan->alreadyhungup = old_chan->alreadyhungup;
+		new_chan->isidlecall = old_chan->isidlecall;
+		new_chan->proceeding = old_chan->proceeding;
+		new_chan->progress = old_chan->progress;
+		new_chan->setup_ack = old_chan->setup_ack;
+		new_chan->outgoing = old_chan->outgoing;
+		new_chan->digital = old_chan->digital;
+		old_chan->alerting = 0;
+		old_chan->alreadyhungup = 0;
+		old_chan->isidlecall = 0;
+		old_chan->proceeding = 0;
+		old_chan->progress = 0;
+		old_chan->setup_ack = 0;
+		old_chan->outgoing = 0;
+		old_chan->digital = 0;
+
+		/* More stuff to transfer to the new channel. */
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+		new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
+#endif	/* defined(HAVE_PRI_REVERSE_CHARGE) */
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+		strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
+#endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+		if (new_chan->no_b_channel) {
+			/* Copy the real channel configuration to the no B channel interface. */
+			new_chan->hidecallerid = old_chan->hidecallerid;
+			new_chan->hidecalleridname = old_chan->hidecalleridname;
+			new_chan->immediate = old_chan->immediate;
+			new_chan->priexclusive = old_chan->priexclusive;
+			new_chan->priindication_oob = old_chan->priindication_oob;
+			new_chan->use_callerid = old_chan->use_callerid;
+			new_chan->use_callingpres = old_chan->use_callingpres;
+			new_chan->stripmsd = old_chan->stripmsd;
+			strcpy(new_chan->context, old_chan->context);
+			strcpy(new_chan->mohinterpret, old_chan->mohinterpret);
+
+			/* Become a member of the old channel span/trunk-group. */
+			new_chan->logicalspan = old_chan->logicalspan;
+			new_chan->mastertrunkgroup = old_chan->mastertrunkgroup;
+		}
+
 		return principle;
-	}
-	if ((principle > -1) &&
-		(principle < pri->numchans) &&
-		(pri->pvts[principle]) &&
-		(pri->pvts[principle]->call == c))
-		return principle;
-	/* First, check for other bearers */
-	for (x = 0; x < pri->numchans; x++) {
-		if (!pri->pvts[x])
-			continue;
-		if (pri->pvts[x]->call == c) {
-			/* Found our call */
-			if (principle != x) {
-				struct sig_pri_chan *new_chan = pri->pvts[principle];
-				struct sig_pri_chan *old_chan = pri->pvts[x];
-
-				ast_verb(3, "Moving call from channel %d to channel %d\n",
-					old_chan->channel, new_chan->channel);
-				if (new_chan->owner) {
-					ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
-						old_chan->channel, new_chan->channel, new_chan->channel);
-					return -1;
-				}
-
-				sig_pri_fixup_chans(old_chan, new_chan);
-				/* Fix it all up now */
-				new_chan->owner = old_chan->owner;
-				old_chan->owner = NULL;
-
-				new_chan->call = old_chan->call;
-				old_chan->call = NULL;
-
-			}
-			return principle;
-		}
 	}
 	ast_log(LOG_WARNING, "Call specified, but not found?\n");
 	return -1;
@@ -957,10 +1038,11 @@
 #endif
 	do {
 		pri->resetpos++;
-	} while ((pri->resetpos < pri->numchans) &&
-		(!pri->pvts[pri->resetpos] ||
-		pri->pvts[pri->resetpos]->call ||
-		pri->pvts[pri->resetpos]->resetting));
+	} while (pri->resetpos < pri->numchans
+		&& (!pri->pvts[pri->resetpos]
+			|| pri->pvts[pri->resetpos]->no_b_channel
+			|| pri->pvts[pri->resetpos]->call
+			|| pri->pvts[pri->resetpos]->resetting));
 	if (pri->resetpos < pri->numchans) {
 #ifdef HAVE_PRI_SERVICE_MESSAGES
 		char db_chan_name[20], db_answer[5], state;
@@ -1002,7 +1084,10 @@
 			break;
 		if (!backwards && (x >= pri->numchans))
 			break;
-		if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
+		if (pri->pvts[x]
+			&& !pri->pvts[x]->no_b_channel
+			&& !pri->pvts[x]->inalarm
+			&& !pri->pvts[x]->owner) {
 			ast_debug(1, "Found empty available channel %d/%d\n",
 				pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
 			return x;
@@ -1014,6 +1099,71 @@
 	}
 	return -1;
 }
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Find or create an empty no-B-channel interface to use.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to find interface.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
+static int pri_find_empty_nobch(struct sig_pri_pri *pri)
+{
+	int idx;
+
+	for (idx = 0; idx < pri->numchans; ++idx) {
+		if (pri->pvts[idx]
+			&& pri->pvts[idx]->no_b_channel
+			&& !pri->pvts[idx]->inalarm
+			&& !pri->pvts[idx]->owner) {
+			ast_debug(1, "Found empty available no B channel interface\n");
+			return idx;
+		}
+	}
+
+	/* Need to create a new interface. */
+	if (pri->calls->new_nobch_intf) {
+		idx = pri->calls->new_nobch_intf(pri);
+	} else {
+		idx = -1;
+	}
+	return idx;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Find the channel associated with the libpri call.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to find interface.
+ * \param call LibPRI opaque call pointer to find.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
+static int pri_find_pri_call(struct sig_pri_pri *pri, q931_call *call)
+{
+	int idx;
+
+	for (idx = 0; idx < pri->numchans; ++idx) {
+		if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
+			/* Found the channel */
+			return idx;
+		}
+	}
+	return -1;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
 static void *do_idle_thread(void *vchan)
 {
@@ -1309,6 +1459,10 @@
  * \param event_id PRI event id
  * \param channel PRI encoded span/channel
  * \param subcmds Subcommands to process if any. (Could be NULL).
+ * \param call_rsp libpri opaque call structure to send any responses toward.
+ * Could be NULL either because it is not available or the call is for the
+ * dummy call reference.  However, this should not be NULL in the cases that
+ * need to use the pointer to send a response message back.
  *
  * \note Assumes the pri->lock is already obtained.
  * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
@@ -1316,7 +1470,7 @@
  * \return Nothing
  */
 static void sig_pri_handle_subcmds(struct sig_pri_pri *pri, int chanpos, int event_id,
-	int channel, const struct pri_subcommands *subcmds)
+	int channel, const struct pri_subcommands *subcmds, q931_call *call_rsp)
 {
 	int index;
 	struct ast_channel *owner;
@@ -1403,6 +1557,63 @@
 				ast_channel_unlock(owner);
 			}
 			break;
+#if defined(HAVE_PRI_CALL_REROUTING)
+		case PRI_SUBCMD_REROUTING:
+			sig_pri_lock_owner(pri, chanpos);
+			owner = pri->pvts[chanpos]->owner;
+			if (owner) {
+				struct pri_party_redirecting pri_deflection;
+
+				if (!call_rsp) {
+					ast_channel_unlock(owner);
+					ast_log(LOG_WARNING,
+						"CallRerouting/CallDeflection to '%s' without call!\n",
+						subcmd->u.rerouting.deflection.to.number.str);
+					break;
+				}
+
+				pri_deflection = subcmd->u.rerouting.deflection;
+
+				ast_string_field_set(owner, call_forward, pri_deflection.to.number.str);
+
+				/* Adjust the deflecting to number based upon the subscription option. */
+				switch (subcmd->u.rerouting.subscription_option) {
+				case 0:	/* noNotification */
+				case 1:	/* notificationWithoutDivertedToNr */
+					/* Delete the number because the far end is not supposed to see it. */
+					pri_deflection.to.number.presentation =
+						PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+					pri_deflection.to.number.plan =
+						(PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
+					pri_deflection.to.number.str[0] = '\0';
+					break;
+				case 2:	/* notificationWithDivertedToNr */
+					break;
+				case 3:	/* notApplicable */
+				default:
+					break;
+				}
+				sig_pri_redirecting_convert(&ast_redirecting, &pri_deflection,
+					&owner->redirecting, pri);
+				ast_channel_set_redirecting(owner, &ast_redirecting);
+				ast_party_redirecting_free(&ast_redirecting);
+
+				/*
+				 * Send back positive ACK to CallRerouting/CallDeflection.
+				 *
+				 * Note:  This call will be hungup by the dial application when
+				 * it processes the call_forward string set above.
+				 */
+				pri_rerouting_rsp(pri->pri, call_rsp, subcmd->u.rerouting.invoke_id,
+					PRI_REROUTING_RSP_OK_CLEAR);
+
+				/* This line is BUSY to further attempts by this dialing attempt. */
+				ast_queue_control(owner, AST_CONTROL_BUSY);
+
+				ast_channel_unlock(owner);
+			}
+			break;
+#endif	/* defined(HAVE_PRI_CALL_REROUTING) */
 		default:
 			ast_debug(2,
 				"Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n",
@@ -1412,6 +1623,220 @@
 		}
 	}
 }
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Attempt to transfer the active call to the held call.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param active_call Active call to transfer.
+ * \param held_call Held call to transfer.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_attempt_transfer(struct sig_pri_pri *pri, q931_call *active_call, q931_call *held_call)
+{
+	int retval;
+	int active_chanpos;
+	int held_chanpos;
+	struct ast_channel *active_ast;
+	struct ast_channel *held_ast;
+	struct ast_channel *bridged;
+
+	active_chanpos = pri_find_pri_call(pri, active_call);
+	held_chanpos = pri_find_pri_call(pri, held_call);
+	if (active_chanpos < 0 || held_chanpos < 0) {
+		return -1;
+	}
+
+	sig_pri_lock_private(pri->pvts[active_chanpos]);
+	sig_pri_lock_private(pri->pvts[held_chanpos]);
+	sig_pri_lock_owner(pri, active_chanpos);
+	sig_pri_lock_owner(pri, held_chanpos);
+
+	active_ast = pri->pvts[active_chanpos]->owner;
+	held_ast = pri->pvts[held_chanpos]->owner;
+	if (!active_ast || !held_ast) {
+		if (active_ast) {
+			ast_channel_unlock(active_ast);
+		}
+		if (held_ast) {
+			ast_channel_unlock(held_ast);
+		}
+		sig_pri_unlock_private(pri->pvts[active_chanpos]);
+		sig_pri_unlock_private(pri->pvts[held_chanpos]);
+		return -1;
+	}
+
+	bridged = ast_bridged_channel(held_ast);
+	if (bridged) {
+		ast_queue_control(held_ast, AST_CONTROL_UNHOLD);
+
+		ast_verb(3, "TRANSFERRING %s to %s\n", held_ast->name, active_ast->name);
+		retval = ast_channel_masquerade(active_ast, bridged);
+	} else {
+		/*
+		 * Could not transfer.  Held channel is not bridged anymore.
+		 * Held party probably got tired of waiting and hung up.
+		 */
+		retval = -1;
+	}
+
+	ast_channel_unlock(active_ast);
+	ast_channel_unlock(held_ast);
+	sig_pri_unlock_private(pri->pvts[active_chanpos]);
+	sig_pri_unlock_private(pri->pvts[held_chanpos]);
+
+	return retval;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the hold event from libpri.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Hold event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_handle_hold(struct sig_pri_pri *pri, pri_event *ev)
+{
+	int retval;
+	int chanpos_old;
+	int chanpos_new;
+	struct ast_channel *bridged;
+	struct ast_channel *owner;
+
+	chanpos_old = pri_find_principle(pri, ev->hold.channel, ev->hold.call);
+	if (chanpos_old < 0) {
+		ast_log(LOG_WARNING,
+			"Received HOLD on unconfigured channel %d/%d span %d\n",
+			PRI_SPAN(ev->hold.channel), PRI_CHANNEL(ev->hold.channel), pri->span);
+		return -1;
+	}
+	if (pri->pvts[chanpos_old]->no_b_channel) {
+		/* Call is already on hold or is call waiting call. */
+		return -1;
+	}
+
+	sig_pri_lock_private(pri->pvts[chanpos_old]);
+	sig_pri_lock_owner(pri, chanpos_old);
+	owner = pri->pvts[chanpos_old]->owner;
+	if (!owner) {
+		retval = -1;
+		goto done_with_private;
+	}
+	bridged = ast_bridged_channel(owner);
+	if (!bridged) {
+		/* Cannot hold a call that is not bridged. */
+		retval = -1;
+		goto done_with_owner;
+	}
+	chanpos_new = pri_find_empty_nobch(pri);
+	if (chanpos_new < 0) {
+		/* No hold channel available. */
+		retval = -1;
+		goto done_with_owner;
+	}
+	sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.channel, ev->hold.subcmds,
+		ev->hold.call);
+	chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
+	if (chanpos_new < 0) {
+		/* Should never happen. */
+		retval = -1;
+	} else {
+		struct ast_frame f = { AST_FRAME_CONTROL, };
+
+		f.subclass = AST_CONTROL_HOLD;
+		ast_queue_frame(owner, &f);
+		retval = 0;
+	}
+
+done_with_owner:;
+	ast_channel_unlock(owner);
+done_with_private:;
+	sig_pri_unlock_private(pri->pvts[chanpos_old]);
+
+	return retval;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the retrieve event from libpri.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Retrieve event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_retrieve(struct sig_pri_pri *pri, pri_event *ev)
+{
+	int chanpos;
+
+	if (!(ev->retrieve.channel & PRI_HELD_CALL)
+		|| pri_find_principle(pri, ev->retrieve.channel, ev->retrieve.call) < 0) {
+		/* The call is not currently held. */
+		pri_retrieve_rej(pri->pri, ev->retrieve.call,
+			PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+		return;
+	}
+	if (PRI_CHANNEL(ev->retrieve.channel) == 0xFF) {
+		chanpos = pri_find_empty_chan(pri, 1);
+	} else {
+		chanpos = pri_find_principle(pri,
+			ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
+		if (ev->retrieve.flexible
+			&& (chanpos < 0 || pri->pvts[chanpos]->owner)) {
+			/*
+			 * Channel selection is flexible and the requested channel
+			 * is bad or already in use.  Pick another channel.
+			 */
+			chanpos = pri_find_empty_chan(pri, 1);
+		}
+	}
+	if (chanpos < 0) {
+		pri_retrieve_rej(pri->pri, ev->retrieve.call,
+			ev->retrieve.flexible ? PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION
+			: PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+		return;
+	}
+	chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve.call);
+	if (chanpos < 0) {
+		/* Channel is already in use. */
+		pri_retrieve_rej(pri->pri, ev->retrieve.call,
+			PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+		return;
+	}
+	sig_pri_lock_private(pri->pvts[chanpos]);
+	sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.channel,
+		ev->retrieve.subcmds, ev->retrieve.call);
+	{
+		struct ast_frame f = { AST_FRAME_CONTROL, };
+
+		f.subclass = AST_CONTROL_UNHOLD;
+		pri_queue_frame(pri->pvts[chanpos], &f, pri);
+	}
+	sig_pri_unlock_private(pri->pvts[chanpos]);
+	pri_retrieve_ack(pri->pri, ev->retrieve.call,
+		PVT_TO_CHANNEL(pri->pvts[chanpos]));
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
 static void *pri_dchannel(void *vpri)
 {
@@ -1489,8 +1914,10 @@
 			haveidles = 0;
 			activeidles = 0;
 			for (x = pri->numchans; x >= 0; x--) {
-				if (pri->pvts[x] && !pri->pvts[x]->owner &&
-					!pri->pvts[x]->call) {
+				if (pri->pvts[x]
+					&& !pri->pvts[x]->owner
+					&& !pri->pvts[x]->call
+					&& !pri->pvts[x]->no_b_channel) {
 					if (haveidles < pri->minunused) {
 						haveidles++;
 					} else if (!pri->pvts[x]->resetting) {
@@ -1643,6 +2070,11 @@
 				pri_find_dchan(pri);
 				if (!pri_is_up(pri)) {
 					pri->resetting = 0;
+					if (pri->sig == SIG_BRI_PTMP) {
+						/* For PTMP connections with non persistent layer 2 we want
+						 * to *not* declare inalarm unless there actually is an alarm */
+						break;
+					}
 					/* Hangup active channels and put them in alarm mode */
 					for (i = 0; i < pri->numchans; i++) {
 						struct sig_pri_chan *p = pri->pvts[i];
@@ -1660,18 +2092,14 @@
 								if (p->owner)
 									ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
 							}
-							/* For PTMP connections with non persistent layer 2 we want
-							 * to *not* declare inalarm unless there actually is an alarm */
-							if (p->pri->sig != SIG_BRI_PTMP) {
-								p->inalarm = 1;
-							}
+							p->inalarm = 1;
 						}
 					}
 				}
 				break;
 			case PRI_EVENT_RESTART:
 				if (e->restart.channel > -1) {
-					chanpos = pri_find_principle(pri, e->restart.channel);
+					chanpos = pri_find_principle(pri, e->restart.channel, NULL);
 					if (chanpos < 0)
 						ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
 							PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
@@ -1726,7 +2154,7 @@
 				}
 				break;
 			case PRI_EVENT_KEYPAD_DIGIT:
-				chanpos = pri_find_principle(pri, e->digit.channel);
+				chanpos = pri_find_principle(pri, e->digit.channel, e->digit.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
 						PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
@@ -1735,7 +2163,7 @@
 					if (chanpos > -1) {
 						sig_pri_lock_private(pri->pvts[chanpos]);
 						sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.channel,
-							e->digit.subcmds);
+							e->digit.subcmds, e->digit.call);
 						/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
 						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
 							&& pri->pvts[chanpos]->call == e->digit.call
@@ -1756,7 +2184,7 @@
 				break;
 
 			case PRI_EVENT_INFO_RECEIVED:
-				chanpos = pri_find_principle(pri, e->ring.channel);
+				chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
 						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
@@ -1765,7 +2193,7 @@
 					if (chanpos > -1) {
 						sig_pri_lock_private(pri->pvts[chanpos]);
 						sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
-							e->ring.subcmds);
+							e->ring.subcmds, e->ring.call);
 						/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
 						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
 							&& pri->pvts[chanpos]->call == e->ring.call
@@ -1786,7 +2214,7 @@
 				break;
 #ifdef HAVE_PRI_SERVICE_MESSAGES
 			case PRI_EVENT_SERVICE:
-				chanpos = pri_find_principle(pri, e->service.channel);
+				chanpos = pri_find_principle(pri, e->service.channel, NULL);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Received service change status %d on unconfigured channel %d/%d span %d\n",

[... 553 lines stripped ...]



More information about the svn-commits mailing list