diff --git a/channels/chan_console.c b/channels/chan_console.c
index 23931a8c34bfc1d850d05a306e2f6b287b46198d..4c8576db5e802840ed95a63d40d89aaaf02f4445 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -393,7 +393,7 @@ return_unlock:
 
 static int stop_stream(struct console_pvt *pvt)
 {
-	if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
+	if (!pvt->streamstate)
 		return 0;
 
 	pthread_cancel(pvt->thread);
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index bd2a86f067a7b0e6d390b1d790b02b555a31c3af..a41f6cf3f1327fb5e09c5b125b248f09ec3c7064 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -87,6 +87,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/netsock.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/dlinkedlists.h"
 #include "asterisk/event.h"
 #include "asterisk/astobj2.h"
 
@@ -639,6 +640,8 @@ struct chan_iax2_pvt {
 	int frames_dropped;
 	/*! received frame count: (just for stats) */
 	int frames_received;
+
+	AST_DLLIST_ENTRY(chan_iax2_pvt) entry;
 };
 
 /*!
@@ -838,6 +841,17 @@ static void __attribute__((format (printf, 1, 2))) jb_debug_output(const char *f
  */
 static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
 
+/*!
+ * \brief Another container of iax2_pvt structures
+ *
+ * Active IAX2 pvt structs are also stored in this container, if they are a part
+ * of an active call where we know the remote side's call number.  The reason
+ * for this is that incoming media frames do not contain our call number.  So,
+ * instead of having to iterate the entire iaxs array, we use this container to
+ * look up calls where the remote side is using a given call number.
+ */
+static struct ao2_container *iax_peercallno_pvts;
+
 /*!
  * \brief chan_iax2_pvt structure locks
  *
@@ -846,6 +860,7 @@ static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
  * local call number for the associated pvt struct.
  */
 static ast_mutex_t iaxsl[ARRAY_LEN(iaxs)];
+
 /*!
  * \brief The last time a call number was used
  *
@@ -1329,16 +1344,88 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 	return res;
 }
 
+static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
+{
+	/* Decrement AUTHREQ count if needed */
+	if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
+		struct iax2_user *user;
+		struct iax2_user tmp_user = {
+			.name = pvt->username,
+		};
+
+		user = ao2_find(users, &tmp_user, OBJ_POINTER);
+		if (user) {
+			ast_atomic_fetchadd_int(&user->curauthreq, -1);
+			user_unref(user);	
+		}
+
+		ast_clear_flag(pvt, IAX_MAXAUTHREQ);
+	}
+	/* No more pings or lagrq's */
+	AST_SCHED_DEL(sched, pvt->pingid);
+	AST_SCHED_DEL(sched, pvt->lagid);
+	AST_SCHED_DEL(sched, pvt->autoid);
+	AST_SCHED_DEL(sched, pvt->authid);
+	AST_SCHED_DEL(sched, pvt->initid);
+	AST_SCHED_DEL(sched, pvt->jbid);
+}
+
+static void iax2_frame_free(struct iax_frame *fr)
+{
+	AST_SCHED_DEL(sched, fr->retrans);
+	iax_frame_free(fr);
+}
+
+static void pvt_destructor(void *obj)
+{
+	struct chan_iax2_pvt *pvt = obj;
+	struct iax_frame *cur = NULL;
+
+	iax2_destroy_helper(pvt);
+
+	/* Already gone */
+	ast_set_flag(pvt, IAX_ALREADYGONE);	
+
+	AST_LIST_LOCK(&frame_queue);
+	AST_LIST_TRAVERSE(&frame_queue, cur, list) {
+		/* Cancel any pending transmissions */
+		if (cur->callno == pvt->callno) { 
+			cur->retries = -1;
+		}
+	}
+	AST_LIST_UNLOCK(&frame_queue);
+
+	if (pvt->reg) {
+		pvt->reg->callno = 0;
+	}
+
+	if (!pvt->owner) {
+		jb_frame frame;
+		if (pvt->vars) {
+		    ast_variables_destroy(pvt->vars);
+		    pvt->vars = NULL;
+		}
+
+		while (jb_getall(pvt->jb, &frame) == JB_OK) {
+			iax2_frame_free(frame.data);
+		}
+
+		jb_destroy(pvt->jb);
+		ast_string_field_free_memory(pvt);
+	}
+}
+
 static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
 {
 	struct chan_iax2_pvt *tmp;
 	jb_conf jbconf;
 
-	if (!(tmp = ast_calloc(1, sizeof(*tmp))))
+	if (!(tmp = ao2_alloc(sizeof(*tmp), pvt_destructor))) {
 		return NULL;
+	}
 
 	if (ast_string_field_init(tmp, 32)) {
-		ast_free(tmp);
+		ao2_ref(tmp, -1);
 		tmp = NULL;
 		return NULL;
 	}
@@ -1481,6 +1568,26 @@ static int make_trunk(unsigned short callno, int locked)
 	return res;
 }
 
+static void store_by_peercallno(struct chan_iax2_pvt *pvt)
+{
+	if (!pvt->peercallno) {
+		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
+		return;
+	}
+
+	ao2_link(iax_peercallno_pvts, pvt);
+}
+
+static void remove_by_peercallno(struct chan_iax2_pvt *pvt)
+{
+	if (!pvt->peercallno) {
+		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
+		return;
+	}
+
+	ao2_unlink(iax_peercallno_pvts, pvt);
+}
+
 /*!
  * \todo XXX Note that this function contains a very expensive operation that
  * happens for *every* incoming media frame.  It iterates through every
@@ -1505,6 +1612,28 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
 	char host[80];
 
 	if (new <= NEW_ALLOW) {
+		if (callno) {
+			struct chan_iax2_pvt *pvt;
+			struct chan_iax2_pvt tmp_pvt = {
+				.callno = dcallno,
+				.peercallno = callno,
+				/* hack!! */
+				.frames_received = full_frame,
+			};
+
+			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
+
+			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
+				if (return_locked) {
+					ast_mutex_lock(&iaxsl[pvt->callno]);
+				}
+				res = pvt->callno;
+				ao2_ref(pvt, -1);
+				pvt = NULL;
+				return res;
+			}
+		}
+
 		for (x = 1; !res && x < maxnontrunkcall; x++) {
 			ast_mutex_lock(&iaxsl[x]);
 			if (iaxs[x]) {
@@ -1587,6 +1716,10 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
 			ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
 			ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
 			ast_string_field_set(iaxs[x], parkinglot, default_parkinglot);
+
+			if (iaxs[x]->peercallno) {
+				store_by_peercallno(iaxs[x]);
+			}
 		} else {
 			ast_log(LOG_WARNING, "Out of resources\n");
 			ast_mutex_unlock(&iaxsl[x]);
@@ -1609,12 +1742,6 @@ static int find_callno_locked(unsigned short callno, unsigned short dcallno, str
 	return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
 }
 
-static void iax2_frame_free(struct iax_frame *fr)
-{
-	AST_SCHED_DEL(sched, fr->retrans);
-	iax_frame_free(fr);
-}
-
 /*!
  * \brief Queue a frame to a call's owning asterisk channel
  *
@@ -2064,32 +2191,6 @@ static int send_packet(struct iax_frame *f)
 	return res;
 }
 
-static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
-{
-	/* Decrement AUTHREQ count if needed */
-	if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
-		struct iax2_user *user;
-		struct iax2_user tmp_user = {
-			.name = pvt->username,
-		};
-
-		user = ao2_find(users, &tmp_user, OBJ_POINTER);
-		if (user) {
-			ast_atomic_fetchadd_int(&user->curauthreq, -1);
-			user_unref(user);	
-		}
-
-		ast_clear_flag(pvt, IAX_MAXAUTHREQ);
-	}
-	/* No more pings or lagrq's */
-	AST_SCHED_DEL(sched, pvt->pingid);
-	AST_SCHED_DEL(sched, pvt->lagid);
-	AST_SCHED_DEL(sched, pvt->autoid);
-	AST_SCHED_DEL(sched, pvt->authid);
-	AST_SCHED_DEL(sched, pvt->initid);
-	AST_SCHED_DEL(sched, pvt->jbid);
-}
-
 /*!
  * \note Since this function calls iax2_queue_hangup(), the pvt struct
  *       for the given call number may disappear during its execution.
@@ -2120,7 +2221,6 @@ static int iax2_predestroy(int callno)
 static void iax2_destroy(int callno)
 {
 	struct chan_iax2_pvt *pvt = NULL;
-	struct iax_frame *cur = NULL;
 	struct ast_channel *owner = NULL;
 
 retry:
@@ -2138,53 +2238,38 @@ retry:
 			goto retry;
 		}
 	}
-	if (!owner)
+
+	if (!owner) {
 		iaxs[callno] = NULL;
+	}
+
 	if (pvt) {
-		if (!owner)
+		if (!owner) {
 			pvt->owner = NULL;
-		iax2_destroy_helper(pvt);
-
-		/* Already gone */
-		ast_set_flag(pvt, IAX_ALREADYGONE);	
-
-		if (owner) {
+		} else {
 			/* If there's an owner, prod it to give up */
 			/* It is ok to use ast_queue_hangup() here instead of iax2_queue_hangup()
 			 * because we already hold the owner channel lock. */
 			ast_queue_hangup(owner, -1);
 		}
 
-		AST_LIST_LOCK(&frame_queue);
-		AST_LIST_TRAVERSE(&frame_queue, cur, list) {
-			/* Cancel any pending transmissions */
-			if (cur->callno == pvt->callno) 
-				cur->retries = -1;
+		if (pvt->peercallno) {
+			remove_by_peercallno(pvt);
 		}
-		AST_LIST_UNLOCK(&frame_queue);
 
-		if (pvt->reg)
-			pvt->reg->callno = 0;
 		if (!owner) {
-			jb_frame frame;
-			if (pvt->vars) {
-			    ast_variables_destroy(pvt->vars);
-			    pvt->vars = NULL;
-			}
-
-			while (jb_getall(pvt->jb, &frame) == JB_OK)
-				iax2_frame_free(frame.data);
-			jb_destroy(pvt->jb);
-			/* gotta free up the stringfields */
-			ast_string_field_free_memory(pvt);
-			ast_free(pvt);
+			ao2_ref(pvt, -1);
+			pvt = NULL;
 		}
 	}
+
 	if (owner) {
 		ast_channel_unlock(owner);
 	}
-	if (callno & 0x4000)
+
+	if (callno & 0x4000) {
 		update_max_trunk();
+	}
 }
 
 static int update_packet(struct iax_frame *f)
@@ -6386,7 +6471,13 @@ static int complete_transfer(int callno, struct iax_ies *ies)
 	pvt->rseqno = 0;
 	pvt->iseqno = 0;
 	pvt->aseqno = 0;
+
+	if (pvt->peercallno) {
+		remove_by_peercallno(pvt);
+	}
 	pvt->peercallno = peercallno;
+	store_by_peercallno(pvt);
+
 	pvt->transferring = TRANSFER_NONE;
 	pvt->svoiceformat = -1;
 	pvt->voiceformat = 0;
@@ -7904,7 +7995,16 @@ static int socket_process(struct iax2_thread *thread)
 	if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
 		f.subclass != IAX_COMMAND_TXCNT &&		/* for attended transfer */
 		f.subclass != IAX_COMMAND_TXACC) {		/* for attended transfer */
-		iaxs[fr->callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
+		unsigned short new_peercallno;
+		
+		new_peercallno = (unsigned short) (ntohs(mh->callno) & ~IAX_FLAG_FULL);
+		if (new_peercallno && new_peercallno != iaxs[fr->callno]->peercallno) {
+			if (iaxs[fr->callno]->peercallno) {
+				remove_by_peercallno(iaxs[fr->callno]);
+			}
+			iaxs[fr->callno]->peercallno = new_peercallno;
+			store_by_peercallno(iaxs[fr->callno]);
+		}
 	}
 	if (ntohs(mh->callno) & IAX_FLAG_FULL) {
 		if (iaxdebug)
@@ -11782,6 +11882,7 @@ static int __unload_module(void)
 
 	ao2_ref(peers, -1);
 	ao2_ref(users, -1);
+	ao2_ref(iax_peercallno_pvts, -1);
 	
 	con = ast_context_find(regcontext);
 	if (con)
@@ -11807,6 +11908,24 @@ static int peer_set_sock_cb(void *obj, void *arg, int flags)
 	return 0;
 }
 
+static int pvt_hash_cb(const void *obj, const int flags)
+{
+	const struct chan_iax2_pvt *pvt = obj;
+
+	return pvt->peercallno;
+}
+
+static int pvt_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;
+
+	/* The frames_received field is used to hold whether we're matching
+	 * against a full frame or not ... */
+
+	return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt, 
+		pvt2->frames_received) ? CMP_MATCH : 0;
+}
+
 /*! \brief Load IAX2 module, load configuraiton ---*/
 static int load_module(void)
 {
@@ -11822,6 +11941,12 @@ static int load_module(void)
 		ao2_ref(peers, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
+	iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);
+	if (!iax_peercallno_pvts) {
+		ao2_ref(peers, -1);
+		ao2_ref(users, -1);
+		return AST_MODULE_LOAD_FAILURE;
+	}
 
 	ast_custom_function_register(&iaxpeer_function);
 	ast_custom_function_register(&iaxvar_function);