[Pkg-voip-commits] r10065 - in /asterisk/branches/squeeze/debian: changelog patches/AST-2012-015

tzafrir at alioth.debian.org tzafrir at alioth.debian.org
Mon Jan 7 13:29:37 UTC 2013


Author: tzafrir
Date: Mon Jan  7 13:29:36 2013
New Revision: 10065

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=10065
Log:
Patch AST-2012-015 (CVE-2012-5977) - Denial of Service Through
  Exploitation of Device State Caching

Added:
    asterisk/branches/squeeze/debian/patches/AST-2012-015
Modified:
    asterisk/branches/squeeze/debian/changelog

Modified: asterisk/branches/squeeze/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/squeeze/debian/changelog?rev=10065&op=diff
==============================================================================
--- asterisk/branches/squeeze/debian/changelog (original)
+++ asterisk/branches/squeeze/debian/changelog Mon Jan  7 13:29:36 2013
@@ -1,3 +1,12 @@
+asterisk (1:1.6.2.9-2+squeeze9) UNRELEASED; urgency=low
+
+  * Patch AST-2012-014 (CVE-2012-5976) - fixes Crashes due to large stack
+    allocations when using TCP.
+  * Patch AST-2012-015 (CVE-2012-5977) - Denial of Service Through
+    Exploitation of Device State Caching.
+
+ -- Tzafrir Cohen <tzafrir at debian.org>  Mon, 07 Jan 2013 15:28:32 +0200
+
 asterisk (1:1.6.2.9-2+squeeze8) stable-security; urgency=high
 
   * Fix AST-2012-010 backported patch (Closes: #688053)

Added: asterisk/branches/squeeze/debian/patches/AST-2012-015
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/squeeze/debian/patches/AST-2012-015?rev=10065&op=file
==============================================================================
--- asterisk/branches/squeeze/debian/patches/AST-2012-015 (added)
+++ asterisk/branches/squeeze/debian/patches/AST-2012-015 Mon Jan  7 13:29:36 2013
@@ -1,0 +1,822 @@
+From: Tzafrir Cohen <tzafrir at debian.org>
+Subject: Prevent exhaustion of system resources through exploitation of event cache
+CVE: CVE-2012-5977
+Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=378303
+Bug: https://issues.asterisk.org/jira/browse/ASTERISK-20175
+
+Asterisk maintains an internal cache for devices in the event subsystem. The
+device state cache holds the state of each device known to Asterisk, such that
+consumers of device state information can query for the last known state for
+a particular device, even if it is not part of an active call. The concept of
+a device in Asterisk can include entities that do not have a physical
+representation. One way that this occurred was when anonymous calls are allowed
+in Asterisk. A device was automatically created and stored in the cache for
+each anonymous call that occurred; this was possible in the SIP and IAX2
+channel drivers.  These devices are never removed from the system, allowing
+anonymous calls to potentially exhaust a system's resources.
+
+This patch changes the event cache subsystem and device state management to
+no longer cache devices that are not associated with a physical entity.
+
+Reported by: Russell Bryant, Leif Madsen, Joshua Colp
+Tested by: kmoore
+See also: http://downloads.asterisk.org/pub/security/AST-2012-015.html
+
+The following patch is an adaptation of that patch to Asterisk 1.6.2
+
+---
+ apps/app_meetme.c              |   16 ++++++------
+ channels/chan_agent.c          |   18 +++++++-------
+ channels/chan_dahdi.c          |    2 -
+ channels/chan_iax2.c           |   31 ++++++++++++++----------
+ channels/chan_local.c          |    3 ++
+ channels/chan_sip.c            |   16 ++++++++----
+ channels/chan_skinny.c         |   16 ++++++------
+ funcs/func_devstate.c          |    6 ++--
+ include/asterisk/channel.h     |    6 ++++
+ include/asterisk/devicestate.h |   16 ++++++++++--
+ include/asterisk/event_defs.h  |    8 +++++-
+ main/channel.c                 |    6 +++-
+ main/devicestate.c             |   51 ++++++++++++++++++++++++++---------------
+ main/event.c                   |    1 
+ main/features.c                |    2 -
+ 15 files changed, 125 insertions(+), 73 deletions(-)
+
+--- a/apps/app_meetme.c
++++ b/apps/app_meetme.c
+@@ -2279,7 +2279,7 @@ static int conf_run(struct ast_channel *
+ 
+ 	/* This device changed state now - if this is the first user */
+ 	if (conf->users == 1)
+-		ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
++		ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
+ 
+ 	ast_mutex_unlock(&conf->playlock);
+ 
+@@ -3355,7 +3355,7 @@ bailoutandtrynormal:
+ 
+ 		/* Change any states */
+ 		if (!conf->users) {
+-			ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
++			ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
+ 		}
+ 
+ 		/* Return the number of seconds the user was in the conf */
+@@ -4662,8 +4662,8 @@ static void sla_change_trunk_state(const
+ 				|| trunk_ref == exclude)
+ 				continue;
+ 			trunk_ref->state = state;
+-			ast_devstate_changed(sla_state_to_devstate(state), 
+-				"SLA:%s_%s", station->name, trunk->name);
++			ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
++					     "SLA:%s_%s", station->name, trunk->name);
+ 			break;
+ 		}
+ 	}
+@@ -5162,8 +5162,8 @@ static void sla_handle_hold_event(struct
+ {
+ 	ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
+ 	event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
+-	ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
+-		event->station->name, event->trunk_ref->trunk->name);
++	ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
++			     event->station->name, event->trunk_ref->trunk->name);
+ 	sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
+ 		INACTIVE_TRUNK_REFS, event->trunk_ref);
+ 
+@@ -5672,8 +5672,8 @@ static int sla_station_exec(struct ast_c
+ 			sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
+ 		else {
+ 			trunk_ref->state = SLA_TRUNK_STATE_UP;
+-			ast_devstate_changed(AST_DEVICE_INUSE, 
+-				"SLA:%s_%s", station->name, trunk_ref->trunk->name);
++			ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
++					     "SLA:%s_%s", station->name, trunk_ref->trunk->name);
+ 		}
+ 	} else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
+ 		struct sla_ringing_trunk *ringing_trunk;
+--- a/channels/chan_agent.c
++++ b/channels/chan_agent.c
+@@ -563,7 +563,7 @@ static struct ast_frame *agent_read(stru
+ 					p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
+ 			}
+ 			p->chan = NULL;
+-			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
++			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 			p->acknowledged = 0;
+ 		}
+ 	} else {
+@@ -815,7 +815,7 @@ static int agent_call(struct ast_channel
+ 	} else {
+ 		/* Agent hung-up */
+ 		p->chan = NULL;
+-		ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
++		ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 	}
+ 
+ 	if (!res) {
+@@ -936,7 +936,7 @@ static int agent_hangup(struct ast_chann
+ 				/* Recognize the hangup and pass it along immediately */
+ 				ast_hangup(p->chan);
+ 				p->chan = NULL;
+-				ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
++				ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 			}
+ 			ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
+ 			if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
+@@ -970,7 +970,7 @@ static int agent_hangup(struct ast_chann
+ 		if (persistent_agents)
+ 			dump_agents();
+ 	} else {
+-		ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
++		ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 	}
+ 
+ 	if (p->pending) {
+@@ -1675,7 +1675,7 @@ static void agent_logoff_maintenance(str
+ 	set_agentbycallerid(p->logincallerid, NULL);
+ 	p->loginchan[0] ='\0';
+ 	p->logincallerid[0] = '\0';
+-	ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
++	ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 	if (persistent_agents)
+ 		dump_agents();
+ 
+@@ -2187,7 +2187,7 @@ static int login_exec(struct ast_channel
+ 							check_availability(p, 0);
+ 						ast_mutex_unlock(&p->lock);
+ 						AST_LIST_UNLOCK(&agents);
+-						ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
++						ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 						while (res >= 0) {
+ 							ast_mutex_lock(&p->lock);
+ 							if (p->deferlogoff && p->chan) {
+@@ -2208,7 +2208,7 @@ static int login_exec(struct ast_channel
+ 								if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
+ 									ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
+ 									p->lastdisc = ast_tv(0, 0);
+-									ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
++									ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 									if (p->ackcall > 1)
+ 										check_beep(p, 0);
+ 									else
+@@ -2258,7 +2258,7 @@ static int login_exec(struct ast_channel
+ 						ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
+ 						ast_verb(2, "Agent '%s' logged out\n", p->agent);
+ 						/* If there is no owner, go ahead and kill it now */
+-						ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
++						ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
+ 						if (p->dead && !p->owner) {
+ 							ast_mutex_destroy(&p->lock);
+ 							ast_mutex_destroy(&p->app_lock);
+@@ -2424,7 +2424,7 @@ static void reload_agents(void)
+ 				cur_agent->logincallerid[0] = '\0';
+ 			if (cur_agent->loginstart == 0)
+ 				time(&cur_agent->loginstart);
+-			ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent);	
++			ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Agent/%s", cur_agent->agent);	
+ 		}
+ 	}
+ 	AST_LIST_UNLOCK(&agents);
+--- a/channels/chan_iax2.c
++++ b/channels/chan_iax2.c
+@@ -5434,7 +5434,7 @@ static int iax2_getpeertrunk(struct sock
+ }
+ 
+ /*! \brief  Create new call, interface with the PBX core */
+-static struct ast_channel *ast_iax2_new(int callno, int state, int capability)
++static struct ast_channel *ast_iax2_new(int callno, int state, int capability, unsigned int cachable)
+ {
+ 	struct ast_channel *tmp;
+ 	struct chan_iax2_pvt *i;
+@@ -5496,6 +5496,10 @@ static struct ast_channel *ast_iax2_new(
+ 	i->owner = tmp;
+ 	i->capability = capability;
+ 
++	if (!cachable) {
++		tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
++	}
++
+ 	/* Set inherited variables */
+ 	if (i->vars) {
+ 		for (v = i->vars ; v ; v = v->next)
+@@ -7753,7 +7757,7 @@ static int register_verify(int callno, s
+ 		/* if challenge has been sent, but no challenge response if given, reject. */
+ 		goto return_unref;
+ 	}
+-	ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
++	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
+ 
+ 	/* either Authentication has taken place, or a REGAUTH must be sent before verifying registration */
+ 	res = 0;
+@@ -8296,7 +8300,7 @@ static void __expire_registry(const void
+ 	if (!ast_test_flag(peer, IAX_TEMPONLY))
+ 		ast_db_del("IAX/Registry", peer->name);
+ 	register_peer_exten(peer, 0);
+-	ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
++	ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
+ 	if (iax2_regfunk)
+ 		iax2_regfunk(peer->name, 0);
+ 
+@@ -8346,7 +8350,7 @@ static void reg_source_db(struct iax2_pe
+  							peer_unref(p);
+  						}
+  					}
+-  					ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
++  					ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
+  					p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
+  					if (p->expire == -1)
+  						peer_unref(p);
+@@ -8418,14 +8422,14 @@ static int update_registry(struct sockad
+ 					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+ 			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
+ 			register_peer_exten(p, 1);
+-			ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
++			ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
+ 		} else if (!ast_test_flag(p, IAX_TEMPONLY)) {
+ 			ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
+ 					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
+ 			manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
+ 			register_peer_exten(p, 0);
+ 			ast_db_del("IAX/Registry", p->name);
+-			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", p->name); /* Activate notification */
++			ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
+ 		}
+ 		/* Update the host */
+ 		/* Verify that the host is really there */
+@@ -9851,7 +9855,8 @@ static int socket_process(struct iax2_th
+ 		    (f.frametype == AST_FRAME_IAX)) {
+ 			if (ast_test_flag(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
+ 				ast_clear_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
+-				if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat)) {
++				if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat,
++						  ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
+ 					ast_mutex_unlock(&iaxsl[fr->callno]);
+ 					return 1;
+ 				}
+@@ -10440,13 +10445,13 @@ retryowner2:
+ 						if (iaxs[fr->callno]->pingtime <= peer->maxms) {
+ 							ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
+ 							manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
+-							ast_devstate_changed(AST_DEVICE_NOT_INUSE, "IAX2/%s", peer->name); /* Activate notification */
++							ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
+ 						}
+ 					} else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
+ 						if (iaxs[fr->callno]->pingtime > peer->maxms) {
+ 							ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
+ 							manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
+-							ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
++							ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
+ 						}
+ 					}
+ 					peer->lastms = iaxs[fr->callno]->pingtime;
+@@ -10675,7 +10680,7 @@ retryowner2:
+ 											using_prefs);
+ 
+ 							ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
+-							if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format)))
++							if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, 1)))
+ 								iax2_destroy(fr->callno);
+ 							else if (ies.vars) {
+ 								struct ast_datastore *variablestore;
+@@ -10744,7 +10749,7 @@ immediatedial:
+ 						ast_verb(3, "Accepting DIAL from %s, formats = 0x%x\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat);
+ 						ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
+ 						send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
+-						if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat)))
++						if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, 1)))
+ 							iax2_destroy(fr->callno);
+ 						else if (ies.vars) {
+ 							struct ast_datastore *variablestore;
+@@ -11469,7 +11474,7 @@ static void __iax2_poke_noanswer(const v
+ 	if (peer->lastms > -1) {
+ 		ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
+ 		manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
+-		ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
++		ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
+ 	}
+ 	if ((callno = peer->callno) > 0) {
+ 		ast_mutex_lock(&iaxsl[callno]);
+@@ -11633,7 +11638,7 @@ static struct ast_channel *iax2_request(
+ 	if (cai.found)
+ 		ast_string_field_set(iaxs[callno], host, pds.peer);
+ 
+-	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability);
++	c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, cai.found);
+ 
+ 	ast_mutex_unlock(&iaxsl[callno]);
+ 
+--- a/channels/chan_local.c
++++ b/channels/chan_local.c
+@@ -771,6 +771,9 @@ static struct ast_channel *local_new(str
+ 	tmp->tech_pvt = p;
+ 	tmp2->tech_pvt = p;
+ 
++	tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
++	tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
++
+ 	p->owner = tmp;
+ 	p->chan = tmp2;
+ 	p->u_owner = ast_module_user_add(p->owner);
+--- a/channels/chan_sip.c
++++ b/channels/chan_sip.c
+@@ -5911,7 +5911,7 @@ static int update_call_counter(struct si
+ 	}
+ 
+ 	if (p) {
+-		ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name);
++		ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name);
+ 		unref_peer(p, "update_call_counter: unref_peer from call counter");
+ 	} 
+ 	return 0;
+@@ -6964,6 +6964,9 @@ static struct ast_channel *sip_new(struc
+ 	if (i->rtp)
+ 		ast_jb_configure(tmp, &global_jbconf);
+ 
++	if (!i->relatedpeer) {
++		tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
++	}
+ 	/* Set channel variables for this call from configuration */
+ 	for (v = i->chanvars ; v ; v = v->next) {
+ 		char valuebuf[1024];
+@@ -12244,7 +12247,7 @@ static int expire_register(const void *d
+ 
+ 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
+ 	register_peer_exten(peer, FALSE);	/* Remove regexten */
+-	ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
+ 
+ 	/* Do we need to release this peer from memory? 
+ 		Only for realtime peers and autocreated peers
+@@ -12967,7 +12970,8 @@ static void sip_peer_hold(struct sip_pvt
+ 	ast_atomic_fetchadd_int(&peer->onHold, (hold ? +1 : -1));
+ 
+ 	/* Request device state update */
+-	ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++	ast_devstate_changed(AST_DEVICE_UNKNOWN, (p->owner->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE),
++			     "SIP/%s", peer->name);
+ 	unref_peer(peer, "sip_peer_hold: from find_peer operation");
+ 	
+ 	return;
+@@ -13327,7 +13331,7 @@ static enum check_auth_result register_v
+ 		sched_yield();
+ 	}
+ 	if (!res) {
+-		ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++		ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
+ 	}
+ 	if (res < 0) {
+ 		switch (res) {
+@@ -18480,7 +18484,7 @@ static void handle_response_peerpoke(str
+ 
+ 		ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
+ 			peer->name, s, pingtime, peer->maxms);
+-		ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++		ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
+ 		if (sip_cfg.peer_rtupdate) {
+ 			ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL);
+ 		}
+@@ -23134,7 +23138,7 @@ static int sip_poke_noanswer(const void
+ 	}
+ 	
+ 	peer->lastms = -1;
+-	ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
+ 
+ 	/* Try again quickly */
+ 	AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, 
+--- a/channels/chan_skinny.c
++++ b/channels/chan_skinny.c
+@@ -1870,7 +1870,7 @@ static int skinny_register(struct skinny
+ 					register_exten(l);
+ 					/* initialize MWI on line and device */
+ 					mwi_event_cb(0, l);
+-					ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
++					ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 				}
+ 				--instance;
+ 			}
+@@ -1907,7 +1907,7 @@ static int skinny_unregister(struct skin
+ 				ast_parse_allow_disallow(&l->prefs, &l->capability, "all", 0);			
+ 				l->instance = 0;
+ 				unregister_exten(l);
+-				ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name);
++				ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 			}
+ 		}
+ 	}
+@@ -5088,7 +5088,7 @@ static int handle_stimulus_message(struc
+ 			ast_verb(1, "RECEIVED UNKNOWN STIMULUS:  %d(%d/%d)\n", event, instance, callreference);
+ 		break;
+ 	}
+-	ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s@%s", l->name, d->name);
++	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 
+ 	return 1;
+ }
+@@ -5138,7 +5138,7 @@ static int handle_offhook_message(struct
+ 	transmit_ringer_mode(d, SKINNY_RING_OFF);
+ 	l->hookstate = SKINNY_OFFHOOK;
+ 
+-	ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
++	ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 
+ 	if (sub && sub->onhold) {
+ 		return 1;
+@@ -5214,7 +5214,7 @@ static int handle_onhook_message(struct
+ 		return 0;
+ 	}
+ 
+-	ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
++	ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 
+ 	if (sub->onhold) {
+ 		return 0;
+@@ -5742,7 +5742,7 @@ static int handle_soft_key_event_message
+ 		return 0;
+ 	}
+ 
+-	ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
++	ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 
+ 	switch(event) {
+ 	case SOFTKEY_NONE:
+@@ -5948,7 +5948,7 @@ static int handle_soft_key_event_message
+ 			}
+ 
+ 			transmit_callstate(d, l->instance, l->hookstate, sub->callid);
+-			ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
++			ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 			if (skinnydebug)
+ 				ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
+ 			if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
+@@ -5972,7 +5972,7 @@ static int handle_soft_key_event_message
+ 				}
+ 			}
+ 			if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) {
+-				ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
++				ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
+ 			}
+ 		}
+ 		break;
+--- a/funcs/func_devstate.c
++++ b/funcs/func_devstate.c
+@@ -128,7 +128,7 @@ static int devstate_write(struct ast_cha
+ 
+ 	ast_db_put(astdb_family, data, value);
+ 
+-	ast_devstate_changed(state_val, "Custom:%s", data);
++	ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", data);
+ 
+ 	return 0;
+ }
+@@ -290,7 +290,7 @@ static char *handle_cli_devstate_change(
+ 
+ 	ast_db_put(astdb_family, dev, state);
+ 
+-	ast_devstate_changed(state_val, "Custom:%s", dev);
++	ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", dev);
+ 
+ 	return CLI_SUCCESS;
+ }
+@@ -336,7 +336,7 @@ static int load_module(void)
+ 		if (dev_name <= (const char *) 1)
+ 			continue;
+ 		ast_devstate_changed(ast_devstate_val(db_entry->data),
+-			"Custom:%s\n", dev_name);
++			AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name);
+ 	}
+ 	ast_db_freetree(db_tree);
+ 	db_tree = NULL;
+--- a/include/asterisk/channel.h
++++ b/include/asterisk/channel.h
+@@ -569,6 +569,12 @@ enum {
+ 	 *  some non-traditional dialplans (like AGI) to continue to function.
+ 	 */
+ 	AST_FLAG_DISABLE_WORKAROUNDS = (1 << 20),
++	/*! Disable device state event caching.  This allows allows channel
++	 * drivers to selectively prevent device state events from being cached
++	 * by certain channels such as anonymous calls which have no persistent
++	 * represenatation that can be tracked.
++	 */
++	AST_FLAG_DISABLE_DEVSTATE_CACHE = (1 << 21),
+ };
+ 
+ /*! \brief ast_bridge_config flags */
+--- a/include/asterisk/devicestate.h
++++ b/include/asterisk/devicestate.h
+@@ -61,6 +61,14 @@ enum ast_device_state {
+ 	AST_DEVICE_TOTAL,        /*/ Total num of device states, used for testing */
+ };
+ 
++/*! \brief Device State Cachability
++ *  \note This is used to define the cachability of a device state when set.
++ */
++enum ast_devstate_cache {
++	AST_DEVSTATE_NOT_CACHABLE,  /*!< This device state is not cachable */
++	AST_DEVSTATE_CACHABLE,      /*!< This device state is cachable */
++};
++
+ /*! \brief Devicestate provider call back */
+ typedef enum ast_device_state (*ast_devstate_prov_cb_type)(const char *data);
+ 
+@@ -129,6 +137,7 @@ enum ast_device_state ast_device_state(c
+  * \brief Tells Asterisk the State for Device is changed
+  *
+  * \param state the new state of the device
++ * \param cachable whether this device state is cachable
+  * \param fmt device name like a dial string with format parameters
+  *
+  * The new state of the device will be sent off to any subscribers
+@@ -138,13 +147,14 @@ enum ast_device_state ast_device_state(c
+  * \retval 0 on success
+  * \retval -1 on failure
+  */
+-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
+-	__attribute__((format(printf, 2, 3)));
++int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
++	__attribute__((format(printf, 3, 4)));
+ 
+ /*!
+  * \brief Tells Asterisk the State for Device is changed
+  *
+  * \param state the new state of the device
++ * \param cachable whether this device state is cachable
+  * \param device device name like a dial string with format parameters
+  *
+  * The new state of the device will be sent off to any subscribers
+@@ -154,7 +164,7 @@ int ast_devstate_changed(enum ast_device
+  * \retval 0 on success
+  * \retval -1 on failure
+  */
+-int ast_devstate_changed_literal(enum ast_device_state state, const char *device);
++int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device);
+ 
+ /*!
+  * \brief Tells Asterisk the State for Device is changed.
+--- a/include/asterisk/event_defs.h
++++ b/include/asterisk/event_defs.h
+@@ -120,9 +120,15 @@ enum ast_event_ie_type {
+ 	  * This IE indicates which server the event originated from
+ 	  */
+ 	 AST_EVENT_IE_EID      = 0x0A,
++	/*!
++	 * \brief Event non-cachability flag
++	 * Used by: All events
++	 * Payload type: UINT
++	 */
++	AST_EVENT_IE_CACHABLE            = 0x0B,
+ };
+ 
+-#define AST_EVENT_IE_MAX AST_EVENT_IE_EID
++#define AST_EVENT_IE_MAX AST_EVENT_IE_CACHABLE
+ 
+ /*!
+  * \brief Payload types for event information elements
+--- a/main/channel.c
++++ b/main/channel.c
+@@ -1451,6 +1451,7 @@ void ast_channel_free(struct ast_channel
+ #ifdef HAVE_EPOLL
+ 	int i;
+ #endif
++	int flags;
+ 	struct ast_var_t *vardata;
+ 	struct ast_frame *f;
+ 	struct varshead *headp;
+@@ -1493,6 +1494,7 @@ void ast_channel_free(struct ast_channel
+ 		sched_context_destroy(chan->sched);
+ 
+ 	ast_copy_string(name, chan->name, sizeof(name));
++	flags = chan->flags;
+ 	if ((dashptr = strrchr(name, '-'))) {
+ 		*dashptr = '\0';
+ 	}
+@@ -1561,7 +1563,7 @@ void ast_channel_free(struct ast_channel
+ 	/* Queue an unknown state, because, while we know that this particular
+ 	 * instance is dead, we don't know the state of all other possible
+ 	 * instances. */
+-	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name);
++	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
+ }
+ 
+ struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
+@@ -4877,7 +4879,7 @@ int ast_setstate(struct ast_channel *cha
+ 	/* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
+ 	 * for this channel is using the callback method for device state. If we pass in an actual state here
+ 	 * we override what they are saying the state is and things go amuck. */
+-	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name);
++	ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
+ 
+ 	/* setstate used to conditionally report Newchannel; this is no more */
+ 	manager_event(EVENT_FLAG_CALL,
+--- a/main/devicestate.c
++++ b/main/devicestate.c
+@@ -170,6 +170,7 @@ static AST_RWLIST_HEAD_STATIC(devstate_p
+ 
+ struct state_change {
+ 	AST_LIST_ENTRY(state_change) list;
++	enum ast_devstate_cache cachable;
+ 	char device[1];
+ };
+ 
+@@ -187,6 +188,7 @@ struct devstate_change {
+ 	AST_LIST_ENTRY(devstate_change) entry;
+ 	uint32_t state;
+ 	struct ast_eid eid;
++	enum ast_devstate_cache cachable;
+ 	char device[1];
+ };
+ 
+@@ -426,7 +428,7 @@ static int getproviderstate(const char *
+ 	return res;
+ }
+ 
+-static void devstate_event(const char *device, enum ast_device_state state)
++static void devstate_event(const char *device, enum ast_device_state state, int cachable)
+ {
+ 	struct ast_event *event;
+ 	enum ast_event_type event_type;
+@@ -442,18 +444,23 @@ static void devstate_event(const char *d
+ 	ast_debug(3, "device '%s' state '%d'\n", device, state);
+ 
+ 	if (!(event = ast_event_new(event_type,
+-			AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+-			AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+-			AST_EVENT_IE_END))) {
++				    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
++				    AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
++				    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
++				    AST_EVENT_IE_END))) {
+ 		return;
+ 	}
+ 
+-	ast_event_queue_and_cache(event);
++	if (cachable) {
++		ast_event_queue_and_cache(event);
++	} else {
++		ast_event_queue(event);
++	}
+ }
+ 
+ /*! Called by the state change thread to find out what the state is, and then
+  *  to queue up the state change event */
+-static void do_state_change(const char *device)
++static void do_state_change(const char *device, int cachable)
+ {
+ 	enum ast_device_state state;
+ 
+@@ -461,10 +468,10 @@ static void do_state_change(const char *
+ 
+ 	ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state));
+ 
+-	devstate_event(device, state);
++	devstate_event(device, state, cachable);
+ }
+ 
+-int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
++int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
+ {
+ 	struct state_change *change;
+ 
+@@ -485,14 +492,15 @@ int ast_devstate_changed_literal(enum as
+ 	 */
+ 
+ 	if (state != AST_DEVICE_UNKNOWN) {
+-		devstate_event(device, state);
++		devstate_event(device, state, cachable);
+ 	} else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
+ 		/* we could not allocate a change struct, or */
+ 		/* there is no background thread, so process the change now */
+-		do_state_change(device);
++		do_state_change(device, cachable);
+ 	} else {
+ 		/* queue the change */
+ 		strcpy(change->device, device);
++		change->cachable = cachable;
+ 		AST_LIST_LOCK(&state_changes);
+ 		AST_LIST_INSERT_TAIL(&state_changes, change, list);
+ 		ast_cond_signal(&change_pending);
+@@ -504,10 +512,10 @@ int ast_devstate_changed_literal(enum as
+ 
+ int ast_device_state_changed_literal(const char *dev)
+ {
+-	return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
++	return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, dev);
+ }
+ 
+-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...) 
++int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
+ {
+ 	char buf[AST_MAX_EXTENSION];
+ 	va_list ap;
+@@ -516,7 +524,7 @@ int ast_devstate_changed(enum ast_device
+ 	vsnprintf(buf, sizeof(buf), fmt, ap);
+ 	va_end(ap);
+ 
+-	return ast_devstate_changed_literal(state, buf);
++	return ast_devstate_changed_literal(state, cachable, buf);
+ }
+ 
+ int ast_device_state_changed(const char *fmt, ...) 
+@@ -528,7 +536,7 @@ int ast_device_state_changed(const char
+ 	vsnprintf(buf, sizeof(buf), fmt, ap);
+ 	va_end(ap);
+ 
+-	return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
++	return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, buf);
+ }
+ 
+ /*! \brief Go through the dev state change queue and update changes in the dev state thread */
+@@ -548,7 +556,7 @@ static void *do_devstate_changes(void *d
+ 		/* Process each state change */
+ 		while ((current = next)) {
+ 			next = AST_LIST_NEXT(current, list);
+-			do_state_change(current->device);
++			do_state_change(current->device, current->cachable);
+ 			ast_free(current);
+ 		}
+ 	}
+@@ -592,7 +600,7 @@ static void devstate_cache_cb(const stru
+ 	collection->num_states++;
+ }
+ 
+-static void process_collection(const char *device, struct change_collection *collection)
++static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
+ {
+ 	int i;
+ 	struct ast_devstate_aggregate agg;
+@@ -642,7 +650,11 @@ static void process_collection(const cha
+ 		return;
+ 	}
+ 
+-	ast_event_queue_and_cache(event);
++	if (cachable) {
++		ast_event_queue_and_cache(event);
++	} else {
++		ast_event_queue(event);
++	}
+ }
+ 
+ static void handle_devstate_change(struct devstate_change *sc)
+@@ -668,7 +680,7 @@ static void handle_devstate_change(struc
+ 	/* Populate the collection of device states from the cache */
+ 	ast_event_dump_cache(tmp_sub);
+ 
+-	process_collection(sc->device, &collection);
++	process_collection(sc->device, sc->cachable, &collection);
+ 
+ 	ast_event_sub_destroy(tmp_sub);
+ }
+@@ -697,10 +709,12 @@ static void devstate_change_collector_cb
+ 	const char *device;
+ 	const struct ast_eid *eid;
+ 	uint32_t state;
++	enum ast_devstate_cache cachable = AST_DEVSTATE_CACHABLE;
+ 
+ 	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+ 	eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
+ 	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
++	cachable = ast_event_get_ie_uint(event, AST_EVENT_IE_CACHABLE);
+ 
+ 	if (ast_strlen_zero(device) || !eid) {
+ 		ast_log(LOG_ERROR, "Invalid device state change event received\n");
+@@ -713,6 +727,7 @@ static void devstate_change_collector_cb
+ 	strcpy(sc->device, device);
+ 	sc->eid = *eid;
+ 	sc->state = state;
++	sc->cachable = cachable;
+ 
+ 	ast_mutex_lock(&devstate_collector.lock);
+ 	AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
+--- a/main/event.c
++++ b/main/event.c
+@@ -216,6 +216,7 @@ static struct ie_map {
+ 	{ AST_EVENT_IE_STATE,     AST_EVENT_IE_PLTYPE_UINT, "State" },
+ 	{ AST_EVENT_IE_CONTEXT,   AST_EVENT_IE_PLTYPE_STR,  "Context" },
+ 	{ AST_EVENT_IE_EID,       AST_EVENT_IE_PLTYPE_RAW,  "EntityID" },
++	{ AST_EVENT_IE_CACHABLE,  AST_EVENT_IE_PLTYPE_UINT, "Cachable" },
+ };
+ 
+ const char *ast_event_get_type_name(const struct ast_event *event)
+--- a/main/features.c
++++ b/main/features.c
+@@ -513,7 +513,7 @@ static void notify_metermaids(const char
+ 	ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
+ 		exten, context, ast_devstate2str(state));
+ 
+-	ast_devstate_changed(state, "park:%s@%s", exten, context);
++	ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context);
+ }
+ 
+ /*! \brief metermaids callback from devicestate.c */
+--- a/channels/chan_dahdi.c
++++ b/channels/chan_dahdi.c
+@@ -7665,7 +7665,7 @@ static struct ast_channel *dahdi_new(str
+ 	/* Configure the new channel jb */
+ 	ast_jb_configure(tmp, &global_jbconf);
+ 
+-	ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
++	ast_devstate_changed_literal(ast_state_chan2dev(state), AST_DEVSTATE_CACHABLE, tmp->name);
+ 
+ 	for (v = i->vars ; v ; v = v->next)
+ 		pbx_builtin_setvar_helper(tmp, v->name, v->value);




More information about the Pkg-voip-commits mailing list