diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index c781f37a62f98337ec61529796fa8f4c9d002d63..ad5ed7013853bf96de53c348df7864f8dca0d7ac 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -786,11 +786,11 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
 
 		/* Set up the iterator we'll be using during this call */
 		if (!ast_strlen_zero(spec)) {
-			iter = ast_channel_iterator_by_name_new(0, spec, strlen(spec));
+			iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
 		} else if (!ast_strlen_zero(exten)) {
-			iter = ast_channel_iterator_by_exten_new(0, exten, context);
+			iter = ast_channel_iterator_by_exten_new(exten, context);
 		} else {
-			iter = ast_channel_iterator_all_new(0);
+			iter = ast_channel_iterator_all_new();
 		}
 
 		if (!iter) {
diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c
index a6ca09ac5f740fd3362f63c1c6f7dfc94f15cf91..bc25defe2dfdf2cb671a2da53695c1f2fa80e7c2 100644
--- a/apps/app_directed_pickup.c
+++ b/apps/app_directed_pickup.c
@@ -210,7 +210,7 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
 	struct ast_channel_iterator *iter;
 	int res = -1;
 
-	if (!(iter = ast_channel_iterator_by_exten_new(0, exten, context))) {
+	if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
 		return -1;
 	}
 
@@ -223,6 +223,8 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
 		target = ast_channel_unref(target);
 	}
 
+	ast_channel_iterator_destroy(iter);
+
 	if (target) {
 		res = pickup_do(chan, target);
 		ast_channel_unlock(target);
diff --git a/apps/app_softhangup.c b/apps/app_softhangup.c
index 50bdb6809dc519c9065bd7f70a6560717640e17b..3513bb775446c635c7893f0d81bc209c43006131 100644
--- a/apps/app_softhangup.c
+++ b/apps/app_softhangup.c
@@ -94,7 +94,7 @@ static int softhangup_exec(struct ast_channel *chan, const char *data)
 		ast_app_parse_options(app_opts, &flags, opts, args.options);
 	lenmatch = strlen(args.channel);
 
-	if (!(iter = ast_channel_iterator_by_name_new(0, args.channel, lenmatch))) {
+	if (!(iter = ast_channel_iterator_by_name_new(args.channel, lenmatch))) {
 		return -1;
 	}
 
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index e82c39a51cf104c549f3b0b3b87bab7ef7437da8..f20bfcaa14454eceee1a6b44b55f39b4877f2d01 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -465,7 +465,7 @@ static int func_channels_read(struct ast_channel *chan, const char *function, ch
 		}
 	}
 
-	if (!(iter = ast_channel_iterator_all_new(0))) {
+	if (!(iter = ast_channel_iterator_all_new())) {
 		if (!ast_strlen_zero(data)) {
 			regfree(&re);
 		}
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index f0393d34f14c382530692efce3b12e4df8a427e7..6caa4a7c4374719c1fd27f07769f7cb6eede50ea 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -18,6 +18,7 @@
 #define _ASTERISK_ASTOBJ2_H
 
 #include "asterisk/compat.h"
+#include "asterisk/linkedlists.h"
 
 /*! \file
  * \ref AstObj2
@@ -547,7 +548,7 @@ Operations on container include:
     can be:
 	OBJ_UNLINK - to remove the object, once found, from the container.
 	OBJ_NODATA - don't return the object if found (no ref count change)
-	OBJ_MULTIPLE - don't stop at first match (not fully implemented)
+	OBJ_MULTIPLE - don't stop at first match
 	OBJ_POINTER	- if set, 'arg' is an object pointer, and a hashtable
                   search will be done. If not, a traversal is done.
 
@@ -559,7 +560,7 @@ Operations on container include:
       - flags can be
 	     OBJ_UNLINK   - to remove the object, once found, from the container.
 	     OBJ_NODATA   - don't return the object if found (no ref count change)
-	     OBJ_MULTIPLE - don't stop at first match (not fully implemented)
+	     OBJ_MULTIPLE - don't stop at first match
 	     OBJ_POINTER  - if set, 'arg' is an object pointer, and a hashtable
                         search will be done. If not, a traversal is done through
                         all the hashtable 'buckets'..
@@ -658,22 +659,21 @@ enum _cb_results {
  */
 enum search_flags {
 	/*! Unlink the object for which the callback function
-	 *  returned CMP_MATCH . This is the only way to extract
-	 *  objects from a container. */
+	 *  returned CMP_MATCH.
+	 */
 	OBJ_UNLINK	 = (1 << 0),
 	/*! On match, don't return the object hence do not increase
-	 *  its refcount. */
+	 *  its refcount.
+	 */
 	OBJ_NODATA	 = (1 << 1),
-	/*! Don't stop at the first match in ao2_callback()
-	 *  \note This is not fully implemented.   Using OBJ_MULTIME with OBJ_NODATA
-	 *  is perfectly fine.  The part that is not implemented is the case where
-	 *  multiple objects should be returned by ao2_callback().
+	/*! Don't stop at the first match in ao2_callback().
 	 */
 	OBJ_MULTIPLE = (1 << 2),
 	/*! obj is an object of the same type as the one being searched for,
 	 *  so use the object's hash function for optimized searching.
 	 *  The search function is unaffected (i.e. use the one passed as
-	 *  argument, or match_by_addr if none specified). */
+	 *  argument, or match_by_addr if none specified).
+	 */
 	OBJ_POINTER	 = (1 << 3),
 	/*! 
 	 * \brief Continue if a match is not found in the hashed out bucket
@@ -817,12 +817,6 @@ void *__ao2_unlink_debug(struct ao2_container *c, void *obj, char *tag, char *fi
 void *__ao2_unlink(struct ao2_container *c, void *obj);
 
 
-/*! \brief Used as return value if the flag OBJ_MULTIPLE is set */
-struct ao2_list {
-	struct ao2_list *next;
-	void *obj;	/* pointer to the user portion of the object */
-};
-
 /*@} */
 
 /*! \brief
@@ -847,21 +841,22 @@ struct ao2_list {
     should immediately stop, or both (via bitwise ORing), if you find a
     match and want to end the traversal, and 0 if the object is not a match,
     but the traversal should continue. This is the function that is applied
-    to each object traversed. It's arguments are:
+    to each object traversed. Its arguments are:
         (void *obj, void *arg, int flags), where:
           obj is an object
           arg is the same as arg passed into ao2_callback
           flags is the same as flags passed into ao2_callback (flags are
            also used by ao2_callback).
  * \param arg passed to the callback.
- * \return 	A pointer to the object found/marked,
- * 		a pointer to a list of objects matching comparison function,
- * 		NULL if not found.
+ * \return when OBJ_MULTIPLE is not included in the flags parameter,
+ *         the return value will be either the object found or NULL if no
+ *         no matching object was found. if OBJ_MULTIPLE is included,
+ *         the return value will be a pointer to an ao2_iterator object,
+ *         which must be destroyed with ao2_iterator_destroy() when the
+ *         caller no longer needs it.
  *
  * If the function returns any objects, their refcount is incremented,
  * and the caller is in charge of decrementing them once done.
- * Also, in case of multiple values returned, the list used
- * to store the objects must be freed by the caller.
  *
  * Typically, ao2_callback() is used for two purposes:
  * - to perform some action (including removal from the container) on one
@@ -881,9 +876,7 @@ struct ao2_list {
  * we can say this looking at flags value.
  * If p points to an object we will search for the object pointed
  * by this value, otherwise we serch for a key value.
- * If the key is not uniq we only find the first matching valued.
- * If we use the OBJ_MARK flags, we mark all the objects matching
- * the condition.
+ * If the key is not unique we only find the first matching valued.
  *
  * The use of flags argument is the follow:
  *
@@ -892,13 +885,9 @@ struct ao2_list {
  *				Callbacks use OBJ_NODATA as a default
  *				functions such as find() do
  *	OBJ_MULTIPLE		return multiple matches
- *				Default for _find() is no.
- *				to a key (not yet supported)
+ *				Default is no.
  *	OBJ_POINTER 		the pointer is an object pointer
  *
- * In case we return a list, the callee must take care to destroy
- * that list when no longer used.
- *
  * \note When the returned object is no longer in use, ao2_ref() should
  * be used to free the additional reference possibly created by this function.
  *
@@ -1078,6 +1067,15 @@ enum ao2_iterator_flags {
 	 * while retrieving the next object from it.
 	 */
 	AO2_ITERATOR_DONTLOCK = (1 << 0),
+	/*! Indicates that the iterator was dynamically allocated by
+	 * astobj2 API and should be freed by ao2_iterator_destroy().
+	 */
+	AO2_ITERATOR_MALLOCD = (1 << 1),
+	/*! Indicates that before the iterator returns an object from
+	 * the container being iterated, the object should be unlinked
+	 * from the container.
+	 */
+	AO2_ITERATOR_UNLINK = (1 << 2),
 };
 
 /*!
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index cab334685dc7da7fd61a029835ed45cfd8b45e7a..2b285ba8d98a31ce995493ae783d63ab5cb41acd 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -2210,7 +2210,6 @@ struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_ite
 /*!
  * \brief Create a new channel iterator based on extension
  *
- * \arg ao2_flags astobj2 iterator flags
  * \arg exten The extension that channels must be in
  * \arg context The context that channels must be in (optional)
  *
@@ -2223,13 +2222,11 @@ struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_ite
  *
  * \since 1.6.3
  */
-struct ast_channel_iterator *ast_channel_iterator_by_exten_new(int ao2_flags, const char *exten,
-	const char *context);
+struct ast_channel_iterator *ast_channel_iterator_by_exten_new(const char *exten, const char *context);
 
 /*!
  * \brief Create a new channel iterator based on name
  *
- * \arg ao2_flags astobj2 iterator flags
  * \arg name channel name or channel uniqueid to match
  * \arg name_len number of characters in the channel name to match on.  This
  *      would be used to match based on name prefix.  If matching on the full
@@ -2244,14 +2241,11 @@ struct ast_channel_iterator *ast_channel_iterator_by_exten_new(int ao2_flags, co
  *
  * \since 1.6.3
  */
-struct ast_channel_iterator *ast_channel_iterator_by_name_new(int ao2_flags, const char *name,
-	size_t name_len);
+struct ast_channel_iterator *ast_channel_iterator_by_name_new(const char *name,	size_t name_len);
 
 /*!
  * \brief Create a new channel iterator
  *
- * \arg ao2_flags astobj2 iterator flags
- *
  * After creating an iterator using this function, the ast_channel_iterator_next()
  * function can be used to iterate through all channels that exist.
  *
@@ -2260,7 +2254,7 @@ struct ast_channel_iterator *ast_channel_iterator_by_name_new(int ao2_flags, con
  *
  * \since 1.6.3
  */
-struct ast_channel_iterator *ast_channel_iterator_all_new(int ao2_flags);
+struct ast_channel_iterator *ast_channel_iterator_all_new(void);
 
 /*!
  * \brief Get the next channel for a channel iterator
diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h
index bfbed1e6f500ec975e459a2e76321c2752878274..4785a7636c6ba18abf46620524b2d594c819505d 100644
--- a/include/asterisk/lock.h
+++ b/include/asterisk/lock.h
@@ -60,7 +60,6 @@
 #endif
 
 #include "asterisk/logger.h"
-#include "asterisk/astobj2.h"
 
 /* internal macro to profile mutexes. Only computes the delay on
  * non-blocking calls.
diff --git a/main/astobj2.c b/main/astobj2.c
index 01fd4b17fcb455eabe8f2cbade9436b407e73c04..cecef7c66f03833ec94258187b497244962a7d63 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -292,7 +292,7 @@ static int internal_ao2_ref(void *user_data, const int delta)
 		 * first word of the user-data, which we make sure is always
 		 * allocated. */
 		memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
-		free(obj);
+		ast_free(obj);
 	}
 
 	return ret;
@@ -609,13 +609,27 @@ static void *internal_ao2_callback(struct ao2_container *c,
 	void *ret = NULL;
 	ao2_callback_fn *cb_default = NULL;
 	ao2_callback_data_fn *cb_withdata = NULL;
+	struct ao2_container *multi_container = NULL;
+	struct ao2_iterator *multi_iterator = NULL;
 
 	if (INTERNAL_OBJ(c) == NULL)	/* safety check on the argument */
 		return NULL;
 
 	if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
-		ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
-		return NULL;
+		/* we need to return an ao2_iterator with the results,
+		 * as there could be more than one. the iterator will
+		 * hold the only reference to a container that has all the
+		 * matching objects linked into it, so when the iterator
+		 * is destroyed, the container will be automatically
+		 * destroyed as well.
+		 */
+		if (!(multi_container = __ao2_container_alloc(1, NULL, NULL))) {
+			return NULL;
+		}
+		if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
+			ao2_ref(multi_container, -1);
+			return NULL;
+		}
 	}
 
 	/* override the match function if necessary */
@@ -627,7 +641,7 @@ static void *internal_ao2_callback(struct ao2_container *c,
 		}
 	} else {
 		/* We do this here to avoid the per object casting penalty (even though
-		   that is probably optimized away anyway. */
+		   that is probably optimized away anyway). */
 		if (type == WITH_DATA) {
 			cb_withdata = cb_fn;
 		} else {
@@ -678,49 +692,51 @@ static void *internal_ao2_callback(struct ao2_container *c,
 				i = last;
 				break;
 			}
+
 			/* we have a match (CMP_MATCH) here */
 			if (!(flags & OBJ_NODATA)) {	/* if must return the object, record the value */
 				/* it is important to handle this case before the unlink */
 				ret = EXTERNAL_OBJ(cur->astobj);
-				if (tag)
-					__ao2_ref_debug(ret, 1, tag, file, line, funcname);
-				else
-					__ao2_ref(ret, 1);
+				if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) {
+					if (tag)
+						__ao2_ref_debug(ret, 1, tag, file, line, funcname);
+					else
+						__ao2_ref(ret, 1);
+				}
 			}
 
-			if (flags & OBJ_UNLINK) {	/* must unlink */
-				struct bucket_list *x = cur;
+			/* if we are in OBJ_MULTIPLE mode, link the object into the
+			 * container that will hold the results
+			 */
+			if (ret && (multi_container != NULL)) {
+				__ao2_link(multi_container, ret);
+				ret = NULL;
+			}
 
+			if (flags & OBJ_UNLINK) {	/* must unlink */
 				/* we are going to modify the container, so update version */
 				ast_atomic_fetchadd_int(&c->version, 1);
 				AST_LIST_REMOVE_CURRENT(entry);
-				/* update number of elements and version */
+				/* update number of elements */
 				ast_atomic_fetchadd_int(&c->elements, -1);
-				if (tag)
-					__ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
-				else
-					__ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
-				free(x);	/* free the link record */
+				if (!(flags & OBJ_NODATA)) {
+					if (tag)
+						__ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname);
+					else
+						__ao2_ref(EXTERNAL_OBJ(cur->astobj), -1);
+				}
+				ast_free(cur);	/* free the link record */
 			}
 
-			if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
+			if ((match & CMP_STOP) || (multi_container == NULL)) {
 				/* We found the only match we need */
 				i = last;	/* force exit from outer loop */
 				break;
 			}
-			if (!(flags & OBJ_NODATA)) {
-#if 0	/* XXX to be completed */
-				/*
-				 * This is the multiple-return case. We need to link
-				 * the object in a list. The refcount is already increased.
-				 */
-#endif
-			}
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
 
 		if (ret) {
-			/* This assumes OBJ_MULTIPLE with !OBJ_NODATA is still not implemented */
 			break;
 		}
 
@@ -731,7 +747,14 @@ static void *internal_ao2_callback(struct ao2_container *c,
 		}
 	}
 	ao2_unlock(c);
-	return ret;
+	if (multi_container != NULL) {
+		*multi_iterator = ao2_iterator_init(multi_container,
+						    AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD);
+		ao2_ref(multi_container, -1);
+		return multi_iterator;
+	} else {
+		return ret;
+	}
 }
 
 void *__ao2_callback_debug(struct ao2_container *c,
@@ -796,7 +819,11 @@ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
 void ao2_iterator_destroy(struct ao2_iterator *i)
 {
 	ao2_ref(i->c, -1);
-	i->c = NULL;
+	if (i->flags & AO2_ITERATOR_MALLOCD) {
+		ast_free(i);
+	} else {
+		i->c = NULL;
+	}
 }
 
 /*
@@ -819,8 +846,8 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_li
 	/* optimization. If the container is unchanged and
 	 * we have a pointer, try follow it
 	 */
-	if (a->c->version == a->c_version && (p = a->obj) ) {
-		if ( (p = AST_LIST_NEXT(p, entry)) )
+	if (a->c->version == a->c_version && (p = a->obj)) {
+		if ((p = AST_LIST_NEXT(p, entry)))
 			goto found;
 		/* nope, start from the next bucket */
 		a->bucket++;
@@ -846,12 +873,24 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_li
 
 found:
 	if (p) {
-		a->version = p->version;
-		a->obj = p;
-		a->c_version = a->c->version;
 		ret = EXTERNAL_OBJ(p->astobj);
-		/* inc refcount of returned object */
-		*q = p;
+		if (a->flags & AO2_ITERATOR_UNLINK) {
+			/* we are going to modify the container, so update version */
+			ast_atomic_fetchadd_int(&a->c->version, 1);
+			AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry);
+			/* update number of elements */
+			ast_atomic_fetchadd_int(&a->c->elements, -1);
+			a->version = 0;
+			a->obj = NULL;
+			a->c_version = a->c->version;
+			ast_free(p);
+		} else {
+			a->version = p->version;
+			a->obj = p;
+			a->c_version = a->c->version;
+			/* inc refcount of returned object */
+			*q = p;
+		}
 	}
 
 	return ret;
diff --git a/main/channel.c b/main/channel.c
index 60ad9638b6570942f8ed6b74c9a608b8d4a5c740..af904692ae5f580adba17796a2533598e8455b6b 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1234,137 +1234,83 @@ struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg,
 }
 
 struct ast_channel_iterator {
-	struct ao2_iterator i;
-	const char *name;
-	size_t name_len;
-	const char *exten;
-	const char *context;
+	/* storage for non-dynamically allocated iterator */
+	struct ao2_iterator simple_iterator;
+	/* pointer to the actual iterator (simple_iterator or a dynamically
+	 * allocated iterator)
+	 */
+	struct ao2_iterator *active_iterator;
 };
 
 struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i)
 {
-	if (i->name) {
-		ast_free((void *) i->name);
-		i->name = NULL;
-	}
-
-	if (i->exten) {
-		ast_free((void *) i->exten);
-		i->exten = NULL;
-	}
-
-	if (i->context) {
-		ast_free((void *) i->context);
-		i->context = NULL;
-	}
-
+	ao2_iterator_destroy(i->active_iterator);
 	ast_free(i);
 
 	return NULL;
 }
 
-static struct ast_channel_iterator *ast_channel_iterator_new(int ao2_flags, const char *name,
-	size_t name_len, const char *exten, const char *context)
+static struct ast_channel_iterator *channel_iterator_search(const char *name,
+							    size_t name_len, const char *exten,
+							    const char *context)
 {
 	struct ast_channel_iterator *i;
+	struct ast_channel tmp_chan = {
+		.name = name,
+		/* This is sort of a hack.  Basically, we're using an arbitrary field
+		 * in ast_channel to pass the name_len for a prefix match.  If this
+		 * gets changed, then the compare callback must be changed, too. */
+		.rings = name_len,
+	};
 
 	if (!(i = ast_calloc(1, sizeof(*i)))) {
 		return NULL;
 	}
 
-	if (!ast_strlen_zero(exten) && !(i->exten = ast_strdup(exten))) {
-		goto return_error;
+	if (exten) {
+		ast_copy_string(tmp_chan.exten, exten, sizeof(tmp_chan.exten));
 	}
 
-	if (!ast_strlen_zero(context) && !(i->context = ast_strdup(context))) {
-		goto return_error;
+	if (context) {
+		ast_copy_string(tmp_chan.context, context, sizeof(tmp_chan.context));
 	}
 
-	if (!ast_strlen_zero(name) && !(i->name = ast_strdup(name))) {
-		goto return_error;
+	if (!(i->active_iterator = ao2_find(channels, &tmp_chan,
+					    OBJ_MULTIPLE | ((!ast_strlen_zero(name) && (name_len == 0)) ? OBJ_POINTER : 0)))) {
+		    ast_free(i);
+		    return NULL;
 	}
 
-	i->name_len = name_len;
-
-	i->i = ao2_iterator_init(channels, ao2_flags);
-
 	return i;
-
-return_error:
-	if (i->exten) {
-		ast_free((void *) i->exten);
-		i->exten = NULL;
-	}
-
-	if (i->context) {
-		ast_free((void *) i->context);
-		i->context = NULL;
-	}
-
-	ast_free(i);
-
-	return NULL;
-}
-
-struct ast_channel_iterator *ast_channel_iterator_by_exten_new(int ao2_flags, const char *exten,
-	const char *context)
-{
-	return ast_channel_iterator_new(ao2_flags, NULL, 0, exten, context);
 }
 
-struct ast_channel_iterator *ast_channel_iterator_by_name_new(int ao2_flags, const char *name,
-	size_t name_len)
+struct ast_channel_iterator *ast_channel_iterator_by_exten_new(const char *exten, const char *context)
 {
-	return ast_channel_iterator_new(ao2_flags, name, name_len, NULL, NULL);
+	return channel_iterator_search(NULL, 0, exten, context);
 }
 
-struct ast_channel_iterator *ast_channel_iterator_all_new(int ao2_flags)
+struct ast_channel_iterator *ast_channel_iterator_by_name_new(const char *name, size_t name_len)
 {
-	return ast_channel_iterator_new(ao2_flags, NULL, 0, NULL, NULL);
+	return channel_iterator_search(name, name_len, NULL, NULL);
 }
 
-/*!
- * \note This function will be reduced to 1 line of code once ao2 supports
- * returning multiple objects from an ao2_callback() using OBJ_MULTIPLE.
- */
-struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i)
+struct ast_channel_iterator *ast_channel_iterator_all_new(void)
 {
-	struct ast_channel *chan = NULL;
-
-	for (; (chan = ao2_iterator_next(&i->i));
-			ast_channel_unlock(chan), ast_channel_unref(chan)) {
-
-		ast_channel_lock(chan);
-
-		if (i->name) { /* match by name */
-			if (!i->name_len) {
-				if (strcasecmp(chan->name, i->name) && strcasecmp(chan->uniqueid, i->name)) {
-					continue; /* name match failed */
-				}
-			} else {
-				if (strncasecmp(chan->name, i->name, i->name_len) &&
-						strncasecmp(chan->uniqueid, i->name, i->name_len)) {
-					continue; /* name match failed */
-				}
-			}
-		} else if (i->exten) {
-			if (i->context && strcasecmp(chan->context, i->context) &&
-					strcasecmp(chan->macrocontext, i->context)) {
-				continue; /* context match failed */
-			}
+	struct ast_channel_iterator *i;
 
-			if (strcasecmp(chan->exten, i->exten) &&
-					strcasecmp(chan->macroexten, i->exten)) {
-				continue; /* exten match failed */
-			}
-		}
+	if (!(i = ast_calloc(1, sizeof(*i)))) {
+		return NULL;
+	}
 
-		ast_channel_unlock(chan);
+	i->simple_iterator = ao2_iterator_init(channels, 0);
+	i->active_iterator = &i->simple_iterator;
 
-		break; /* chan points to the next chan desired. */
-	}
+	return i;
+}
 
-	return chan;
+struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i)
+{
+	return ao2_iterator_next(i->active_iterator);
 }
 
 static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
@@ -1407,7 +1353,7 @@ static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
 }
 
 static struct ast_channel *ast_channel_get_full(const char *name, size_t name_len,
-	const char *exten, const char *context)
+						const char *exten, const char *context)
 {
 	struct ast_channel tmp_chan = {
 		.name = name,
diff --git a/main/cli.c b/main/cli.c
index 5b31bba2b497d4b9ad1b1c94a9d79b966b8f65e3..abfc8f0a9e5560ff2d4afcf65489fd446e991d3d 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -827,7 +827,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 				"CallerID", "Duration", "Accountcode", "PeerAccount", "BridgedTo");
 	}
 
-	if (!count && !(iter = ast_channel_iterator_all_new(0))) {
+	if (!count && !(iter = ast_channel_iterator_all_new())) {
 		return CLI_FAILURE;
 	}
 
@@ -1454,7 +1454,7 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
 		return NULL;
 	}
 
-	if (!(iter = ast_channel_iterator_by_name_new(0, word, strlen(word)))) {
+	if (!(iter = ast_channel_iterator_by_name_new(word, strlen(word)))) {
 		return NULL;
 	}
 
@@ -1467,6 +1467,8 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
 		ast_channel_unref(c);
 	}
 
+	ast_channel_iterator_destroy(iter);
+
 	return ret == &notfound ? NULL : ret;
 }
 
diff --git a/main/manager.c b/main/manager.c
index 1bd2eaeb4fa5712c9a25af8d6352d59b314e268e..a02d06106d2eb52629007e75f16d41c121c9336c 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -2806,7 +2806,7 @@ static int action_status(struct mansession *s, const struct message *m)
 	}
 
 	if (all) {
-		if (!(iter = ast_channel_iterator_all_new(0))) {
+		if (!(iter = ast_channel_iterator_all_new())) {
 			ast_free(str);
 			astman_send_error(s, m, "Memory Allocation Failure");
 			return 1;
@@ -2914,6 +2914,10 @@ static int action_status(struct mansession *s, const struct message *m)
 		}
 	}
 
+	if (iter) {
+		ast_channel_iterator_destroy(iter);
+	}
+
 	astman_append(s,
 		"Event: StatusComplete\r\n"
 		"%s"
@@ -3643,7 +3647,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 		idText[0] = '\0';
 	}
 
-	if (!(iter = ast_channel_iterator_all_new(0))) {
+	if (!(iter = ast_channel_iterator_all_new())) {
 		astman_send_error(s, m, "Memory Allocation Failure");
 		return 1;
 	}
diff --git a/res/snmp/agent.c b/res/snmp/agent.c
index f4d4fc6fd826afecf4903d691071eb569d9c6652..df4523339c0f5ffa16be29ddbf5b22aeb8637213 100644
--- a/res/snmp/agent.c
+++ b/res/snmp/agent.c
@@ -243,7 +243,7 @@ static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *le
 
 	i = name[*length - 1] - 1;
 
-	if (!(iter = ast_channel_iterator_all_new(0))) {
+	if (!(iter = ast_channel_iterator_all_new())) {
 		return NULL;
 	}
 
@@ -588,7 +588,7 @@ static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_
 
 		long_ret = 0;
 
-		if (!(iter = ast_channel_iterator_all_new(0))) {
+		if (!(iter = ast_channel_iterator_all_new())) {
 			return NULL;
 		}
 
@@ -622,7 +622,7 @@ static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *le
 		return NULL;
 	}
 
-	if (!(iter = ast_channel_iterator_all_new(0))) {
+	if (!(iter = ast_channel_iterator_all_new())) {
 		return NULL;
 	}
 
@@ -635,6 +635,8 @@ static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *le
 		chan = ast_channel_unref(chan);
 	}
 
+	ast_channel_iterator_destroy(iter);
+
 	*var_len = sizeof(long_ret);
 
 	return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;