[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