[asterisk-commits] rmudgett: branch 1.4 r312573 - in /branches/1.4: ./ channels/ include/asterisk/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 4 10:49:40 CDT 2011


Author: rmudgett
Date: Mon Apr  4 10:49:30 2011
New Revision: 312573

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=312573
Log:
Issues with ISDN calls changing B channels during call negotiations.

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

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

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

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

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

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

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

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

Modified:
    branches/1.4/channels/chan_dahdi.c
    branches/1.4/configure
    branches/1.4/configure.ac
    branches/1.4/include/asterisk/autoconfig.h.in

Modified: branches/1.4/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/channels/chan_dahdi.c?view=diff&rev=312573&r1=312572&r2=312573
==============================================================================
--- branches/1.4/channels/chan_dahdi.c (original)
+++ branches/1.4/channels/chan_dahdi.c Mon Apr  4 10:49:30 2011
@@ -126,6 +126,21 @@
 #undef SUPPORT_USERUSER
 
 /*! 
+ * Define to make always pick a channel if allowed.  Useful for
+ * testing channel shifting.
+ */
+//#define ALWAYS_PICK_CHANNEL	1
+
+/*!
+ * Define to force a RESTART on a channel that returns a cause
+ * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
+ * is because of a stuck channel on the peer and the channel is
+ * always the next channel we pick for an outgoing call then
+ * this can help.
+ */
+#define FORCE_RESTART_UNAVAIL_CHANS		1
+
+/*!
  * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
  * the user hangs up to reset the state machine so ring works properly.
  * This is used to be able to support kewlstart by putting the zhone in
@@ -145,8 +160,6 @@
 
 /*! \brief Typically, how many rings before we should send Caller*ID */
 #define DEFAULT_CIDRINGS 1
-
-#define CHANNEL_PSEUDO -12
 
 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
 
@@ -257,6 +270,9 @@
 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);
+
+#define SIG_PRI_LIB_HANDLE_CASES	\
+	SIG_PRI
 
 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
 static inline int dahdi_get_event(int fd)
@@ -592,6 +608,19 @@
 	unsigned int unknown_alarm:1;
 	/*! \brief TRUE if TDD in MATE mode */
 	unsigned int mate:1;
+#if defined(HAVE_PRI)
+	/*!
+	 * \brief TRUE when this channel is allocated.
+	 *
+	 * \details
+	 * Needed to hold an outgoing channel allocation before the
+	 * owner pointer is created.
+	 *
+	 * \note This is one of several items to check to see if a
+	 * channel is available for use.
+	 */
+	unsigned int allocated:1;
+#endif	/* defined(HAVE_PRI) */
 	/*! \brief TRUE if we originated the call leg. */
 	unsigned int outgoing:1;
 	/* unsigned int overlapdial:1; 			unused and potentially confusing */
@@ -3060,7 +3089,6 @@
 	}
 
 	if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
-		p->owner = NULL;
 		p->ringt = 0;
 		p->distinctivering = 0;
 		p->confirmanswer = 0;
@@ -3101,59 +3129,58 @@
 		if (res < 0) 
 			ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
 		/* Perform low level hangup if no owner left */
-#ifdef HAVE_PRI
+#if defined(HAVE_PRI)
 		if (p->pri) {
 #ifdef SUPPORT_USERUSER
 			const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
 #endif
 
 			/* Make sure we have a call (or REALLY have a call in the case of a PRI) */
+			pri_grab(p, p->pri);
 			if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
-				if (!pri_grab(p, p->pri)) {
-					if (p->alreadyhungup) {
-						ast_log(LOG_DEBUG, "Already hungup...  Calling hangup once, and clearing call\n");
+				if (p->alreadyhungup) {
+					ast_log(LOG_DEBUG, "Already hungup...  Calling hangup once, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
-						pri_call_set_useruser(p->call, useruser);
+					pri_call_set_useruser(p->call, useruser);
 #endif
 
-						pri_hangup(p->pri->pri, p->call, -1);
-						p->call = NULL;
-						if (p->bearer) 
-							p->bearer->call = NULL;
-					} else {
-						const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
-						int icause = ast->hangupcause ? ast->hangupcause : -1;
-						ast_log(LOG_DEBUG, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
+					pri_hangup(p->pri->pri, p->call, -1);
+					p->call = NULL;
+					if (p->bearer)
+						p->bearer->call = NULL;
+				} else {
+					const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
+					int icause = ast->hangupcause ? ast->hangupcause : -1;
+					ast_log(LOG_DEBUG, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
 
 #ifdef SUPPORT_USERUSER
-						pri_call_set_useruser(p->call, useruser);
+					pri_call_set_useruser(p->call, useruser);
 #endif
 
-						p->alreadyhungup = 1;
-						if (p->bearer)
-							p->bearer->alreadyhungup = 1;
-						if (cause) {
-							if (atoi(cause))
-								icause = atoi(cause);
-						}
-						pri_hangup(p->pri->pri, p->call, icause);
+					p->alreadyhungup = 1;
+					if (p->bearer)
+						p->bearer->alreadyhungup = 1;
+					if (cause) {
+						if (atoi(cause))
+							icause = atoi(cause);
 					}
-					if (res < 0) 
-						ast_log(LOG_WARNING, "pri_disconnect failed\n");
-					pri_rel(p->pri);			
-				} else {
-					ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
-					res = -1;
+					pri_hangup(p->pri->pri, p->call, icause);
 				}
 			} else {
 				if (p->bearer)
 					ast_log(LOG_DEBUG, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
 				p->call = NULL;
-				res = 0;
-			}
-		}
-#endif
+			}
+			p->allocated = 0;
+			p->owner = NULL;
+			pri_rel(p->pri);
+			res = 0;
+		} else
+#endif	/* defined(HAVE_PRI) */
+		{
+			p->owner = NULL;
+		}
 		if (p->sig && (p->sig != SIG_PRI))
 			res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
 		if (res < 0) {
@@ -3233,12 +3260,10 @@
 	p->oprmode = 0;
 	ast->tech_pvt = NULL;
 	ast_mutex_unlock(&p->lock);
-	ast_module_unref(ast_module_info->self);
 	if (option_verbose > 2) 
 		ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
 
 	ast_mutex_lock(&iflock);
-
 	if (p->restartpending) {
 		num_restart_pending--;
 	}
@@ -3257,6 +3282,8 @@
 		}
 	}
 	ast_mutex_unlock(&iflock);
+
+	ast_module_unref(ast_module_info->self);
 	return 0;
 }
 
@@ -4512,27 +4539,30 @@
 		case DAHDI_EVENT_ALARM:
 #ifdef HAVE_PRI
 			if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
-				/* T309 is not enabled : hangup calls when alarm occurs */
+				/* T309 is not enabled : destroy calls when alarm occurs */
 				if (p->call) {
 					if (p->pri && p->pri->pri) {
-						if (!pri_grab(p, p->pri)) {
-							pri_hangup(p->pri->pri, p->call, -1);
-							pri_destroycall(p->pri->pri, p->call);
-							p->call = NULL;
-							pri_rel(p->pri);
-						} else
-							ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+						pri_grab(p, p->pri);
+						pri_destroycall(p->pri->pri, p->call);
+						p->call = NULL;
+						pri_rel(p->pri);
 					} else
 						ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
 				}
 				if (p->owner)
 					p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 			}
-			if (p->bearer)
+			if (p->bearer) {
 				p->bearer->inalarm = 1;
-			else
+				p->bearer->resetting = 0;
+			} else
 #endif
-			p->inalarm = 1;
+			{
+				p->inalarm = 1;
+#if defined(HAVE_PRI)
+				p->resetting = 0;
+#endif	/* defined(HAVE_PRI) */
+			}
 			res = get_alarms(p);
 			handle_alarms(p, res);
 #ifdef HAVE_PRI
@@ -4872,9 +4902,12 @@
 		case DAHDI_EVENT_NOALARM:
 			p->inalarm = 0;
 #ifdef HAVE_PRI
+			p->resetting = 0;
 			/* Extremely unlikely but just in case */
-			if (p->bearer)
+			if (p->bearer) {
 				p->bearer->inalarm = 0;
+				p->bearer->resetting = 0;
+			}
 #endif				
 			if (!p->unknown_alarm) {
 				ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
@@ -5389,14 +5422,27 @@
 
 static struct ast_frame  *dahdi_read(struct ast_channel *ast)
 {
-	struct dahdi_pvt *p = ast->tech_pvt;
+	struct dahdi_pvt *p;
 	int res;
 	int index;
 	void *readbuf;
 	struct ast_frame *f;
 
+	/*
+	 * For analog channels, we must do deadlock avoidance because
+	 * analog ports can have more than one Asterisk channel using
+	 * the same private structure.
+	 */
+	p = ast->tech_pvt;
 	while (ast_mutex_trylock(&p->lock)) {
 		DEADLOCK_AVOIDANCE(&ast->lock);
+
+		/*
+		 * For PRI channels, we must refresh the private pointer because
+		 * the call could move to another B channel while the Asterisk
+		 * channel is unlocked.
+		 */
+		p = ast->tech_pvt;
 	}
 
 	index = dahdi_get_index(ast, p, 0);
@@ -7614,6 +7660,9 @@
 		break;
 	case DAHDI_EVENT_NOALARM:
 		i->inalarm = 0;
+#if defined(HAVE_PRI)
+		i->resetting = 0;
+#endif	/* defined(HAVE_PRI) */
 		if (!i->unknown_alarm) {
 			ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
 			manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
@@ -7624,6 +7673,9 @@
 		break;
 	case DAHDI_EVENT_ALARM:
 		i->inalarm = 1;
+#if defined(HAVE_PRI)
+		i->resetting = 0;
+#endif	/* defined(HAVE_PRI) */
 		res = get_alarms(i);
 		handle_alarms(i, res);
 		/* fall thru intentionally */
@@ -8509,10 +8561,14 @@
 			/* the dchannel is down so put the channel in alarm */
 			if (tmp->pri && !pri_is_up(tmp->pri)) {
 				tmp->inalarm = 1;
+				tmp->resetting = 0;
 			}
 #endif				
 			if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
 				tmp->inalarm = 1;
+#if defined(HAVE_PRI)
+				tmp->resetting = 0;
+#endif	/* defined(HAVE_PRI) */
 				handle_alarms(tmp, res);
 			} else {
 				/* yes, this looks strange... the unknown_alarm flag is only used to
@@ -8582,6 +8638,86 @@
 	return tmp;
 }
 
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Determine if a private channel structure is in use.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if in use.
+ *
+ * \return TRUE if the channel is in use.
+ */
+static int sig_pri_is_chan_in_use(struct dahdi_pvt *pvt)
+{
+	return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Determine if a private channel structure is available.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if available.
+ *
+ * \return TRUE if the channel is available.
+ */
+static int sig_pri_is_chan_available(struct dahdi_pvt *pvt)
+{
+	return !sig_pri_is_chan_in_use(pvt);
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Simple check if the channel is available to use.
+ * \since 1.8
+ *
+ * \param pvt Private channel control structure.
+ *
+ * \retval 0 Interface not available.
+ * \retval 1 Interface is available.
+ */
+static int sig_pri_available_check(struct dahdi_pvt *pvt)
+{
+	/*
+	 * If interface is available for use
+	 * then the channel is available.
+	 */
+	if (sig_pri_is_chan_available(pvt)) {
+		return 1;
+	}
+	return 0;
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+static int sig_pri_available(struct dahdi_pvt *pvt)
+{
+	struct dahdi_pvt *p = pvt;
+	struct dahdi_pri *pri;
+
+	if (!p->pri) {
+		/* Something is wrong here.  A PRI channel without the pri pointer? */
+		return 0;
+	}
+	pri = p->pri;
+
+	ast_mutex_lock(&pri->lock);
+	if (sig_pri_available_check(p)) {
+		p->allocated = 1;
+		ast_mutex_unlock(&pri->lock);
+		return 1;
+	}
+
+	ast_mutex_unlock(&pri->lock);
+	return 0;
+}
+#endif	/* defined(HAVE_PRI) */
+
 static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
 {
 	int res;
@@ -8599,6 +8735,16 @@
 			return 0;
 		*channelmatched = 1;
 	}
+
+#if defined(HAVE_PRI)
+	switch (p->sig) {
+	case SIG_PRI_LIB_HANDLE_CASES:
+		return sig_pri_available(p);
+	default:
+		break;
+	}
+#endif	/* defined(HAVE_PRI) */
+
 	/* We're at least busy at this point */
 	if (busy) {
 		if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
@@ -8616,10 +8762,8 @@
 #ifdef HAVE_PRI
 		/* Trust PRI */
 		if (p->pri) {
-			if (p->resetting || p->call)
-				return 0;
-			else
-				return 1;
+			/* Likely only GR-303 gets here. */
+			return sig_pri_available(p);
 		}
 #endif
 		if (!(p->radio || (p->oprmode < 0)))
@@ -8726,6 +8870,18 @@
 	
 
 #ifdef HAVE_PRI
+/*!
+ * \internal
+ * \brief Find an empty B-channel interface to use.
+ *
+ * \param pri PRI span control structure.
+ * \param backwards TRUE if the search starts from higher channels.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
 static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
 {
 	int x;
@@ -8738,7 +8894,8 @@
 			break;
 		if (!backwards && (x >= pri->numchans))
 			break;
-		if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
+		if (pri->pvts[x]
+			&& sig_pri_is_chan_available(pri->pvts[x])) {
 			ast_log(LOG_DEBUG, "Found empty available channel %d/%d\n", 
 				pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
 			return x;
@@ -8929,10 +9086,34 @@
 					break;
 				}
 			}
+#if defined(HAVE_PRI)
+			switch (p->sig) {
+			case SIG_GR303FXOKS:
+			case SIG_GR303FXSKS:
+			case SIG_PRI_LIB_HANDLE_CASES:
+				/*
+				 * We already have the B channel reserved for this call.  We
+				 * just need to make sure that dahdi_hangup() has completed
+				 * cleaning up before continuing.
+				 */
+				ast_mutex_lock(&p->lock);
+				ast_mutex_unlock(&p->lock);
+				break;
+			default:
+				break;
+			}
+#endif	/* defined(HAVE_PRI) */
 			p->outgoing = 1;
 			tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
 			if (!tmp) {
 				p->outgoing = 0;
+#if defined(HAVE_PRI)
+				/*
+				 * This should be the last thing to clear when we are done with
+				 * the channel.
+				 */
+				p->allocated = 0;
+#endif	/* defined(HAVE_PRI) */
 			}
 #ifdef HAVE_PRI
 			if (p->bearer) {
@@ -9016,7 +9197,7 @@
  * \brief Obtain the DAHDI owner channel lock if the owner exists.
  * \since 1.8
  *
- * \param pri DAHDI PRI control structure.
+ * \param pri PRI span control structure.
  * \param chanpos Channel position in the span.
  *
  * \note Assumes the pri->lock is already obtained.
@@ -9046,9 +9227,126 @@
 #if defined(HAVE_PRI)
 /*!
  * \internal
+ * \brief Queue the given frame onto the owner channel.
+ * \since 1.8
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param frame Frame to queue onto the owner channel.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_queue_frame(struct dahdi_pri *pri, int chanpos, struct ast_frame *frame)
+{
+	sig_pri_lock_owner(pri, chanpos);
+	if (pri->pvts[chanpos]->owner) {
+		ast_queue_frame(pri->pvts[chanpos]->owner, frame);
+		ast_channel_unlock(pri->pvts[chanpos]->owner);
+	}
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Queue a control frame of the specified subclass onto the owner channel.
+ * \since 1.8
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ * \param subclass Control frame subclass to queue onto the owner channel.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_queue_control(struct dahdi_pri *pri, int chanpos, int subclass)
+{
+	struct ast_frame f = {AST_FRAME_CONTROL, };
+
+	f.subclass = subclass;
+	pri_queue_frame(pri, chanpos, &f);
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Find the channel associated with the libpri call.
+ * \since 1.10
+ *
+ * \param pri PRI span control structure.
+ * \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_principle_by_call(struct dahdi_pri *pri, q931_call *call)
+{
+	int idx;
+
+	if (!call) {
+		/* Cannot find a call without a call. */
+		return -1;
+	}
+	for (idx = 0; idx < pri->numchans; ++idx) {
+		if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
+			/* Found the principle */
+			return idx;
+		}
+	}
+	return -1;
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Kill the call.
+ * \since 1.10
+ *
+ * \param pri PRI span control structure.
+ * \param call LibPRI opaque call pointer to find.
+ * \param cause Reason call was killed.
+ *
+ * \note Assumes the pvt->pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_kill_call(struct dahdi_pri *pri, q931_call *call, int cause)
+{
+	int chanpos;
+
+	chanpos = pri_find_principle_by_call(pri, call);
+	if (chanpos < 0) {
+		pri_hangup(pri->pri, call, cause);
+		return;
+	}
+	ast_mutex_lock(&pri->pvts[chanpos]->lock);
+	if (!pri->pvts[chanpos]->owner) {
+		pri_hangup(pri->pri, call, cause);
+		pri->pvts[chanpos]->call = NULL;
+		ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+		return;
+	}
+	pri->pvts[chanpos]->owner->hangupcause = cause;
+	pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
+	ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
  * \brief Find the private structure for the libpri call.
  *
- * \param pri Span controller structure.
+ * \param pri PRI span control structure.
  * \param channel LibPRI encoded channel ID.
  *
  * \note Assumes the pri->lock is already obtained.
@@ -9090,7 +9388,7 @@
  * \internal
  * \brief Fixup the private structure associated with the libpri call.
  *
- * \param pri Span controller structure.
+ * \param pri PRI span control structure.
  * \param principle Array-index into private array to move call to if not already there.
  * \param c LibPRI opaque call pointer to find if need to move call.
  *
@@ -9133,7 +9431,7 @@
 						old->owner ? old->owner->name : "",
 						old->channel, new->channel);
 				}
-				if (new->owner) {
+				if (!sig_pri_is_chan_available(new)) {
 					ast_log(LOG_WARNING,
 						"Can't move call (%s) from channel %d to %d.  It is already in use.\n",
 						old->owner ? old->owner->name : "",
@@ -9170,11 +9468,13 @@
 				new->alreadyhungup = old->alreadyhungup;
 				new->isidlecall = old->isidlecall;
 				new->progress = old->progress;
+				new->allocated = old->allocated;
 				new->outgoing = old->outgoing;
 				new->digital = old->digital;
 				old->alreadyhungup = 0;
 				old->isidlecall = 0;
 				old->progress = 0;
+				old->allocated = 0;
 				old->outgoing = 0;
 				old->digital = 0;
 
@@ -9217,6 +9517,54 @@
 	}
 	ast_log(LOG_WARNING, "Call specified, but not found?\n");
 	return -1;
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Find and fixup the private structure associated with the libpri call.
+ *
+ * \param pri PRI span control structure.
+ * \param channel LibPRI encoded channel ID.
+ * \param call LibPRI opaque call pointer.
+ *
+ * \details
+ * This is a combination of pri_find_principle() and pri_fixup_principle()
+ * to reduce code redundancy and to make handling several PRI_EVENT_xxx's
+ * consistent for the current architecture.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
+static int pri_find_fixup_principle(struct dahdi_pri *pri, int channel, q931_call *call)
+{
+	int chanpos;
+
+	chanpos = pri_find_principle(pri, channel);
+	if (chanpos < 0) {
+		ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is unconfigured.\n",
+			pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
+		sig_pri_kill_call(pri, call, PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST);
+		return -1;
+	}
+	chanpos = pri_fixup_principle(pri, chanpos, call);
+	if (chanpos < 0) {
+		ast_log(LOG_WARNING, "Span %d: PRI requested channel %d/%d is not available.\n",
+			pri->span, PRI_SPAN(channel), PRI_CHANNEL(channel));
+		/*
+		 * Using Q.931 section 5.2.3.1 b) as the reason for picking
+		 * PRI_CAUSE_CHANNEL_UNACCEPTABLE.  Receiving a
+		 * PRI_CAUSE_REQUESTED_CHAN_UNAVAIL would cause us to restart
+		 * that channel (which is not specified by Q.931) and kill some
+		 * other call which would be bad.
+		 */
+		sig_pri_kill_call(pri, call, PRI_CAUSE_CHANNEL_UNACCEPTABLE);
+		return -1;
+	}
+	return chanpos;
 }
 #endif	/* defined(HAVE_PRI) */
 
@@ -9360,14 +9708,25 @@
 	ast_mutex_unlock(&pridebugfdlock);
 }
 
-static int pri_check_restart(struct dahdi_pri *pri)
-{
-	do {
-		pri->resetpos++;
-	} while ((pri->resetpos < pri->numchans) &&
-		 (!pri->pvts[pri->resetpos] ||
-		  pri->pvts[pri->resetpos]->call ||
-		  pri->pvts[pri->resetpos]->resetting));
+/*!
+ * \internal
+ * \brief Restart the next channel we think is idle on the span.
+ *
+ * \param pri PRI span control structure.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_check_restart(struct dahdi_pri *pri)
+{
+	for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
+		if (!pri->pvts[pri->resetpos]
+			|| sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
+			continue;
+		}
+		break;
+	}
 	if (pri->resetpos < pri->numchans) {
 		/* Mark the channel as resetting and restart it */
 		pri->pvts[pri->resetpos]->resetting = 1;
@@ -9376,7 +9735,6 @@
 		pri->resetting = 0;
 		time(&pri->lastreset);
 	}
-	return 0;
 }
 
 static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
@@ -9489,7 +9847,8 @@
 	char plancallingnum[256];
 	char plancallingani[256];
 	char calledtonstr[10];
-	
+	unsigned int len;
+
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
 	gettimeofday(&lastidle, NULL);
@@ -9523,8 +9882,9 @@
 		ast_mutex_lock(&pri->lock);
 		if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
 			if (pri->resetting && pri_is_up(pri)) {
-				if (pri->resetpos < 0)
+				if (pri->resetpos < 0) {
 					pri_check_restart(pri);
+				}
 			} else {
 				if (!pri->resetting	&& (t - pri->lastreset) >= pri->resetinterval) {
 					pri->resetting = 1;
@@ -9538,30 +9898,41 @@
 			haveidles = 0;
 			activeidles = 0;
 			for (x = pri->numchans; x >= 0; x--) {
-				if (pri->pvts[x] && !pri->pvts[x]->owner && 
-				    !pri->pvts[x]->call) {
-					if (haveidles < pri->minunused) {
-						haveidles++;
-					} else if (!pri->pvts[x]->resetting) {
-						nextidle = x;
-						break;
+				if (pri->pvts[x]) {
+					if (sig_pri_is_chan_available(pri->pvts[x])) {
+						if (haveidles < pri->minunused) {
+							haveidles++;
+						} else {
+							nextidle = x;
+							break;
+						}
+					} else if (pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
+						activeidles++;
 					}
-				} else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
-					activeidles++;
+				}
 			}
 			if (nextidle > -1) {
 				if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
 					/* Don't create a new idle call more than once per second */
 					snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
+					/*
+					 * Release the PRI lock while we create the channel so other
+					 * threads can send D channel messages.
+					 */
+					ast_mutex_unlock(&pri->lock);
 					idle = dahdi_request(dahdi_chan_name, AST_FORMAT_ULAW, idlen, &cause);
+					ast_mutex_lock(&pri->lock);
 					if (idle) {
 						pri->pvts[nextidle]->isidlecall = 1;
 						if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
 							ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
-							dahdi_hangup(idle);
+							ast_mutex_unlock(&pri->lock);
+							ast_hangup(idle);
+							ast_mutex_lock(&pri->lock);
 						}
-					} else
+					} else {
 						ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
+					}
 					gettimeofday(&lastidle, NULL);
 				}
 			} else if ((haveidles < pri->minunused) &&
@@ -9699,30 +10070,31 @@
 					pri->lastreset -= pri->resetinterval;
 					pri->lastreset += 5;
 				}
+				/* Take the channels from inalarm condition */
 				pri->resetting = 0;
-				/* Take the channels from inalarm condition */
-				for (i = 0; i < pri->numchans; i++)
+				for (i = 0; i < pri->numchans; i++) {
 					if (pri->pvts[i]) {
 						pri->pvts[i]->inalarm = 0;
+						pri->pvts[i]->resetting = 0;
 					}
+				}
 				break;
 			case PRI_EVENT_DCHAN_DOWN:
 				pri_find_dchan(pri);
 				if (!pri_is_up(pri)) {
+					/* Hangup active channels and put them in alarm mode */
 					pri->resetting = 0;
-					/* Hangup active channels and put them in alarm mode */
 					for (i = 0; i < pri->numchans; i++) {
 						struct dahdi_pvt *p = pri->pvts[i];
 						if (p) {
 							if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
-								/* T309 is not enabled : hangup calls when alarm occurs */
+								/* T309 is not enabled : destroy calls when alarm occurs */
 								if (p->call) {
 									if (p->pri && p->pri->pri) {
-										pri_hangup(p->pri->pri, p->call, -1);
 										pri_destroycall(p->pri->pri, p->call);
 										p->call = NULL;
 									} else
-										ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
+										ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
 								}
 								if (p->realcall) {
 									pri_hangup_all(p->realcall, pri);
@@ -9730,20 +10102,24 @@
 									p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 							}
 							p->inalarm = 1;
+							p->resetting = 0;
 						}
 					}
 				}
 				break;
 			case PRI_EVENT_RESTART:
-				if (e->restart.channel > -1) {
+				if (e->restart.channel > -1 && PRI_CHANNEL(e->ring.channel) != 0xFF) {
 					chanpos = pri_find_principle(pri, e->restart.channel);
 					if (chanpos < 0)
-						ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", 
-							PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+						ast_log(LOG_WARNING,
+							"Span %d: Restart requested on odd/unavailable channel number %d/%d\n",
+							pri->span, PRI_SPAN(e->restart.channel),
+							PRI_CHANNEL(e->restart.channel));
 					else {
 						if (option_verbose > 2)
-							ast_verbose(VERBOSE_PREFIX_3 "B-channel %d/%d restarted on span %d\n", 
-								PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+							ast_verbose(VERBOSE_PREFIX_3 "Span %d: Channel %d/%d restarted\n",
+								pri->span, PRI_SPAN(e->restart.channel),
+								PRI_CHANNEL(e->restart.channel));
 						ast_mutex_lock(&pri->pvts[chanpos]->lock);
 						if (pri->pvts[chanpos]->call) {
 							pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
@@ -9758,7 +10134,8 @@
 					}
 				} else {
 					if (option_verbose > 2)
-						ast_verbose(VERBOSE_PREFIX_2 "Restart on requested on entire span %d\n", pri->span);
+						ast_verbose(VERBOSE_PREFIX_2 "Restart requested on entire span %d\n",
+							pri->span);
 					for (x = 0; x < pri->numchans; x++)
 						if (pri->pvts[x]) {
 							ast_mutex_lock(&pri->pvts[x]->lock);
@@ -9775,748 +10152,818 @@
 				}
 				break;
 			case PRI_EVENT_KEYPAD_DIGIT:
-				chanpos = pri_find_principle(pri, e->digit.channel);
+				chanpos = pri_find_principle_by_call(pri, e->digit.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", 
-						PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
-					if (chanpos > -1) {
-						ast_mutex_lock(&pri->pvts[chanpos]->lock);
-						/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
-						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
-							/* how to do that */
-							int digitlen = strlen(e->digit.digits);
-							char digit;
-							int i;					
-							for (i = 0; i < digitlen; i++) {	
-								digit = e->digit.digits[i];
-								{
-									struct ast_frame f = { AST_FRAME_DTMF, digit, };
-									dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
-								}
-							}
+					ast_log(LOG_WARNING,
+						"Span %d: Received keypad digits for unknown call.\n", pri->span);
+					break;
+				}
+				ast_mutex_lock(&pri->pvts[chanpos]->lock);
+				/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
+				if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+					&& pri->pvts[chanpos]->owner) {
+					/* how to do that */
+					int digitlen = strlen(e->digit.digits);
+					char digit;
+					int i;
+					for (i = 0; i < digitlen; i++) {
+						digit = e->digit.digits[i];
+						{
+							struct ast_frame f = { AST_FRAME_DTMF, digit, };
+							dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
 						}
-						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
 					}
 				}
+				ast_mutex_unlock(&pri->pvts[chanpos]->lock);
 				break;
 				
 			case PRI_EVENT_INFO_RECEIVED:
-				chanpos = pri_find_principle(pri, e->ring.channel);
+				chanpos = pri_find_principle_by_call(pri, e->ring.call);
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", 
-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
-					if (chanpos > -1) {
-						ast_mutex_lock(&pri->pvts[chanpos]->lock);
-						/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
-						if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
-							/* how to do that */
-							int digitlen = strlen(e->ring.callednum);
-							char digit;
-							int i;					
-							for (i = 0; i < digitlen; i++) {	
-								digit = e->ring.callednum[i];
-								{
-									struct ast_frame f = { AST_FRAME_DTMF, digit, };
-									dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
-								}
-							}
+					ast_log(LOG_WARNING,
+						"Span %d: Received INFORMATION for unknown call.\n", pri->span);
+					break;
+				}
+				ast_mutex_lock(&pri->pvts[chanpos]->lock);
+				/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
+				if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+					&& pri->pvts[chanpos]->owner) {
+					/* how to do that */
+					int digitlen = strlen(e->ring.callednum);
+					char digit;
+					int i;
+					for (i = 0; i < digitlen; i++) {
+						digit = e->ring.callednum[i];
+						{
+							struct ast_frame f = { AST_FRAME_DTMF, digit, };
+							dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
 						}
-						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
 					}
 				}
+				ast_mutex_unlock(&pri->pvts[chanpos]->lock);
 				break;
 			case PRI_EVENT_RING:
 				crv = NULL;
-				if (e->ring.channel == -1)
+				chanpos = pri_find_principle_by_call(pri, e->ring.call);
+				if (-1 < chanpos) {
+					/* Libpri has already filtered out duplicate SETUPs. */
+					ast_log(LOG_WARNING,
+						"Span %d: Got SETUP with duplicate call ptr.  Dropping call.\n",
+						pri->span);
+					pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_TEMPORARY_FAILURE);
+					break;
+				}
+				if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
+					/* Any channel requested. */
 					chanpos = pri_find_empty_chan(pri, 1);
-				else
+				} else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
+					/* No channel specified. */
+					{
+						/* We will not accept incoming call waiting calls. */
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INCOMPATIBLE_DESTINATION);
+						break;
+					}
+				} else {
+					/* A channel is specified. */
 					chanpos = pri_find_principle(pri, e->ring.channel);
-				/* if no channel specified find one empty */
+					if (chanpos < 0) {
+						ast_log(LOG_WARNING,
+							"Span %d: SETUP on unconfigured channel %d/%d\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+					} else if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+						/* This is where we handle initial glare */
+						ast_log(LOG_DEBUG,
+							"Span %d: SETUP requested unavailable channel %d/%d.  Attempting to renegotiate.\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+						chanpos = -1;
+					}
+#if defined(ALWAYS_PICK_CHANNEL)
+					if (e->ring.flexible) {
+						chanpos = -1;
+					}
+#endif	/* defined(ALWAYS_PICK_CHANNEL) */
+					if (chanpos < 0 && e->ring.flexible) {
+						/* We can try to pick another channel. */
+						chanpos = pri_find_empty_chan(pri, 1);
+					}
+				}
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+					if (e->ring.flexible) {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+					} else {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+					}
+					break;
+				}
+
+				ast_mutex_lock(&pri->pvts[chanpos]->lock);
+				if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+					/* Should be safe to lock CRV AFAIK while bearer is still locked */
+					crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
+					if (crv)
+						ast_mutex_lock(&crv->lock);
+					if (!crv || crv->owner) {
+						pri->pvts[chanpos]->call = NULL;
+						if (crv) {
+							if (crv->owner)
+								crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+							ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
+						} else
+							ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
+						if (crv)
+							ast_mutex_unlock(&crv->lock);
+						ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+						break;
+					}
+				}
+
+				/* Mark channel as in use so noone else will steal it. */
+				pri->pvts[chanpos]->call = e->ring.call;
+
+				apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+				if (pri->pvts[chanpos]->use_callerid) {
+					ast_shrink_phone_number(plancallingnum);
+					ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
+#ifdef PRI_ANI
+					if (!ast_strlen_zero(e->ring.callingani)) {
+						apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
+						ast_shrink_phone_number(plancallingani);
+						ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
+					} else {
+						pri->pvts[chanpos]->cid_ani[0] = '\0';
+					}
+#endif
+					ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
+					pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
 				} else {
-					ast_mutex_lock(&pri->pvts[chanpos]->lock);
-					if (pri->pvts[chanpos]->owner) {
-						if (pri->pvts[chanpos]->call == e->ring.call) {
-							ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
-								PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-							ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-							break;
+					pri->pvts[chanpos]->cid_num[0] = '\0';
+					pri->pvts[chanpos]->cid_ani[0] = '\0';
+					pri->pvts[chanpos]->cid_name[0] = '\0';
+					pri->pvts[chanpos]->cid_ton = 0;
+				}
+				apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
+							 e->ring.redirectingnum, e->ring.callingplanrdnis);
+
+				/* Set DNID on all incoming calls -- even immediate */
+				ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+
+				/* If immediate=yes go to s|1 */
+				if (pri->pvts[chanpos]->immediate) {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of immediate=yes\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* Get called number */
+				else if (!ast_strlen_zero(e->ring.callednum)) {
+					ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+				} else if (pri->overlapdial)
+					pri->pvts[chanpos]->exten[0] = '\0';
+				else {
+					/* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* No number yet, but received "sending complete"? */
+				if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of Complete received\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+
+				/* Make sure extension exists (or in overlap dial mode, can exist) */
+				if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+					ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+					/* Setup law */
+					int law;
+					if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
+						/* Set to audio mode at this point */
+						law = 1;
+						if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
+							ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
+					}
+					if (e->ring.layer1 == PRI_LAYER_1_ALAW)
+						law = DAHDI_LAW_ALAW;
+					else
+						law = DAHDI_LAW_MULAW;
+					res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
+					if (res < 0) 
+						ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);

[... 1506 lines stripped ...]



More information about the asterisk-commits mailing list