diff --git a/apps/app_dial.c b/apps/app_dial.c
index 0390cfe7f9c0fc4597e29d18a680c491afd46ee4..895d4b883315c49a782f450d24b968853bb74abb 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -58,7 +58,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/manager.h"
 #include "asterisk/privacy.h"
 #include "asterisk/stringfields.h"
-#include "asterisk/global_datastores.h"
 #include "asterisk/dsp.h"
 #include "asterisk/aoc.h"
 #include "asterisk/ccss.h"
@@ -68,6 +67,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/stasis_channels.h"
 #include "asterisk/bridge_after.h"
 #include "asterisk/features_config.h"
+#include "asterisk/max_forwards.h"
 
 /*** DOCUMENTATION
 	<application name="Dial" language="en_US">
@@ -881,6 +881,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
 			ast_channel_lock_both(in, o->chan);
 			ast_channel_inherit_variables(in, o->chan);
 			ast_channel_datastore_inherit(in, o->chan);
+			ast_max_forwards_decrement(o->chan);
 			ast_channel_unlock(in);
 			ast_channel_unlock(o->chan);
 			/* When a call is forwarded, we don't want to track new interfaces
@@ -2074,7 +2075,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	);
 	struct ast_flags64 opts = { 0, };
 	char *opt_args[OPT_ARG_ARRAY_SIZE];
-	struct ast_datastore *datastore = NULL;
 	int fulldial = 0, num_dialed = 0;
 	int ignore_cc = 0;
 	char device_name[AST_CHANNEL_NAME];
@@ -2101,6 +2101,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	 * \note This will not have any malloced strings so do not free it.
 	 */
 	struct ast_party_caller caller;
+	int max_forwards;
 
 	/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
 	ast_channel_lock(chan);
@@ -2111,8 +2112,16 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
 	pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
 	ast_channel_stage_snapshot_done(chan);
+	max_forwards = ast_max_forwards_get(chan);
 	ast_channel_unlock(chan);
 
+	if (max_forwards <= 0) {
+		ast_log(LOG_WARNING, "Cannot place outbound call from channel '%s'. Max forwards exceeded\n",
+				ast_channel_name(chan));
+		pbx_builtin_setvar_helper(chan, "DIALSTATUS", "BUSY");
+		return -1;
+	}
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
 		pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
@@ -2314,9 +2323,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		char *tech = strsep(&number, "/");
 		size_t tech_len;
 		size_t number_len;
-		/* find if we already dialed this interface */
-		struct ast_dialed_interface *di;
-		AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
 
 		num_dialed++;
 		if (ast_strlen_zero(number)) {
@@ -2360,7 +2366,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		/* Request the peer */
 
 		ast_channel_lock(chan);
-		datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
 		/*
 		 * Seed the chanlist's connected line information with previously
 		 * acquired connected line info from the incoming channel.  The
@@ -2370,61 +2375,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(chan));
 		ast_channel_unlock(chan);
 
-		if (datastore)
-			dialed_interfaces = datastore->data;
-		else {
-			if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
-				ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
-				chanlist_free(tmp);
-				goto out;
-			}
-			datastore->inheritance = DATASTORE_INHERIT_FOREVER;
-
-			if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
-				ast_datastore_free(datastore);
-				chanlist_free(tmp);
-				goto out;
-			}
-
-			datastore->data = dialed_interfaces;
-			AST_LIST_HEAD_INIT(dialed_interfaces);
-
-			ast_channel_lock(chan);
-			ast_channel_datastore_add(chan, datastore);
-			ast_channel_unlock(chan);
-		}
-
-		AST_LIST_LOCK(dialed_interfaces);
-		AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
-			if (!strcasecmp(di->interface, tmp->interface)) {
-				ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
-					di->interface);
-				break;
-			}
-		}
-		AST_LIST_UNLOCK(dialed_interfaces);
-		if (di) {
-			fulldial++;
-			chanlist_free(tmp);
-			continue;
-		}
-
-		/* It is always ok to dial a Local interface.  We only keep track of
-		 * which "real" interfaces have been dialed.  The Local channel will
-		 * inherit this list so that if it ends up dialing a real interface,
-		 * it won't call one that has already been called. */
-		if (strcasecmp(tmp->tech, "Local")) {
-			if (!(di = ast_calloc(1, sizeof(*di) + strlen(tmp->interface)))) {
-				chanlist_free(tmp);
-				goto out;
-			}
-			strcpy(di->interface, tmp->interface);
-
-			AST_LIST_LOCK(dialed_interfaces);
-			AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
-			AST_LIST_UNLOCK(dialed_interfaces);
-		}
-
 		tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), NULL, chan, tmp->number, &cause);
 		if (!tc) {
 			/* If we can't, just go on to the next call */
@@ -2465,6 +2415,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 		/* Inherit specially named variables from parent channel */
 		ast_channel_inherit_variables(chan, tc);
 		ast_channel_datastore_inherit(chan, tc);
+		ast_max_forwards_decrement(tc);
 
 		ast_channel_appl_set(tc, "AppDial");
 		ast_channel_data_set(tc, "(Outgoing Line)");
@@ -2680,18 +2631,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
 		dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
 
-	/* The ast_channel_datastore_remove() function could fail here if the
-	 * datastore was moved to another channel during a masquerade. If this is
-	 * the case, don't free the datastore here because later, when the channel
-	 * to which the datastore was moved hangs up, it will attempt to free this
-	 * datastore again, causing a crash
-	 */
-	ast_channel_lock(chan);
-	datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); /* make sure we weren't cleaned up already */
-	if (datastore && !ast_channel_datastore_remove(chan, datastore)) {
-		ast_datastore_free(datastore);
-	}
-	ast_channel_unlock(chan);
 	if (!peer) {
 		if (result) {
 			res = result;
diff --git a/apps/app_followme.c b/apps/app_followme.c
index 4a2e569df00dccaf51f74b6533cb76880755637e..5fd5d15ba50d2ba1d04bf7e02bb6cb93419d39fe 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -64,6 +64,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/dsp.h"
 #include "asterisk/app.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/max_forwards.h"
 
 /*** DOCUMENTATION
 	<application name="FollowMe" language="en_US">
@@ -1069,6 +1070,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
 			ast_connected_line_copy_from_caller(ast_channel_connected(outbound), ast_channel_caller(caller));
 			ast_channel_inherit_variables(caller, outbound);
 			ast_channel_datastore_inherit(caller, outbound);
+			ast_max_forwards_decrement(outbound);
 			ast_channel_language_set(outbound, ast_channel_language(caller));
 			ast_channel_req_accountcodes(outbound, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
 			ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
@@ -1304,12 +1306,23 @@ static int app_exec(struct ast_channel *chan, const char *data)
 		AST_APP_ARG(options);
 	);
 	char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
+	int max_forwards;
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
 		return -1;
 	}
 
+	ast_channel_lock(chan);
+	max_forwards = ast_max_forwards_get(chan);
+	ast_channel_unlock(chan);
+
+	if (max_forwards <= 0) {
+		ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
+				ast_channel_name(chan));
+		return -1;
+	}
+
 	argstr = ast_strdupa((char *) data);
 
 	AST_STANDARD_APP_ARGS(args, argstr);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index a82632d8e506baa6f3d8f8c85e9771bd62f7d6dc..0b8204c33b4eec345a2d6c4a6086bd0a9a924c10 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -98,7 +98,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/stringfields.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/strings.h"
-#include "asterisk/global_datastores.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/aoc.h"
 #include "asterisk/callerid.h"
@@ -113,6 +112,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/mixmonitor.h"
 #include "asterisk/core_unreal.h"
 #include "asterisk/bridge_basic.h"
+#include "asterisk/max_forwards.h"
 
 /*!
  * \par Please read before modifying this file.
@@ -4301,6 +4301,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 	/* Inherit specially named variables from parent channel */
 	ast_channel_inherit_variables(qe->chan, tmp->chan);
 	ast_channel_datastore_inherit(qe->chan, tmp->chan);
+	ast_max_forwards_decrement(tmp->chan);
 
 	/* Presense of ADSI CPE on outgoing channel follows ours */
 	ast_channel_adsicpe_set(tmp->chan, ast_channel_adsicpe(qe->chan));
@@ -4794,6 +4795,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 						ast_channel_lock_both(o->chan, in);
 						ast_channel_inherit_variables(in, o->chan);
 						ast_channel_datastore_inherit(in, o->chan);
+						ast_max_forwards_decrement(o->chan);
 
 						if (o->pending_connected_update) {
 							/*
@@ -6275,10 +6277,7 @@ static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
  *
  * Here is the process of this function
  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
- * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
- *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
- *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
- *    during each iteration, we call calc_metric to determine which members should be rung when.
+ * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member.
  * 3. Call ring_one to place a call to the appropriate member(s)
  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
@@ -6331,13 +6330,8 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	int block_connected_line = 0;
 	int callcompletedinsl;
 	struct ao2_iterator memi;
-	struct ast_datastore *datastore;
 	struct queue_end_bridge *queue_end_bridge = NULL;
 
-	ast_channel_lock(qe->chan);
-	datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
-	ast_channel_unlock(qe->chan);
-
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	tmpid[0] = 0;
 	time(&now);
@@ -6424,73 +6418,12 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	memi = ao2_iterator_init(qe->parent->members, 0);
 	while ((cur = ao2_iterator_next(&memi))) {
 		struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
-		struct ast_dialed_interface *di;
-		AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
 		if (!tmp) {
 			ao2_ref(cur, -1);
 			ao2_iterator_destroy(&memi);
 			ao2_unlock(qe->parent);
 			goto out;
 		}
-		if (!datastore) {
-			if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
-				callattempt_free(tmp);
-				ao2_ref(cur, -1);
-				ao2_iterator_destroy(&memi);
-				ao2_unlock(qe->parent);
-				goto out;
-			}
-			datastore->inheritance = DATASTORE_INHERIT_FOREVER;
-			if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
-				callattempt_free(tmp);
-				ao2_ref(cur, -1);
-				ao2_iterator_destroy(&memi);
-				ao2_unlock(qe->parent);
-				goto out;
-			}
-			datastore->data = dialed_interfaces;
-			AST_LIST_HEAD_INIT(dialed_interfaces);
-
-			ast_channel_lock(qe->chan);
-			ast_channel_datastore_add(qe->chan, datastore);
-			ast_channel_unlock(qe->chan);
-		} else
-			dialed_interfaces = datastore->data;
-
-		AST_LIST_LOCK(dialed_interfaces);
-		AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
-			if (!strcasecmp(cur->interface, di->interface)) {
-				ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
-					di->interface);
-				break;
-			}
-		}
-		AST_LIST_UNLOCK(dialed_interfaces);
-
-		if (di) {
-			callattempt_free(tmp);
-			ao2_ref(cur, -1);
-			continue;
-		}
-
-		/* It is always ok to dial a Local interface.  We only keep track of
-		 * which "real" interfaces have been dialed.  The Local channel will
-		 * inherit this list so that if it ends up dialing a real interface,
-		 * it won't call one that has already been called. */
-		if (strncasecmp(cur->interface, "Local/", 6)) {
-			if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
-				callattempt_free(tmp);
-				ao2_ref(cur, -1);
-				ao2_iterator_destroy(&memi);
-				ao2_unlock(qe->parent);
-				goto out;
-			}
-			strcpy(di->interface, cur->interface);
-
-			AST_LIST_LOCK(dialed_interfaces);
-			AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
-			AST_LIST_UNLOCK(dialed_interfaces);
-		}
 
 		/*
 		 * Seed the callattempt's connected line information with previously
@@ -6549,16 +6482,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 	lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
 		ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
 		forwardsallowed, ringing);
-	/* The ast_channel_datastore_remove() function could fail here if the
-	 * datastore was moved to another channel during a masquerade. If this is
-	 * the case, don't free the datastore here because later, when the channel
-	 * to which the datastore was moved hangs up, it will attempt to free this
-	 * datastore again, causing a crash
-	 */
-	ast_channel_lock(qe->chan);
-	if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
-		ast_datastore_free(datastore);
-	}
+
 	ast_channel_unlock(qe->chan);
 	ao2_lock(qe->parent);
 	if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
@@ -7750,12 +7674,22 @@ static int queue_exec(struct ast_channel *chan, const char *data)
 	struct queue_ent qe = { 0 };
 	struct ast_flags opts = { 0, };
 	char *opt_args[OPT_ARG_ARRAY_SIZE];
+	int max_forwards;
 
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
 		return -1;
 	}
 
+	ast_channel_lock(chan);
+	max_forwards = ast_max_forwards_get(chan);
+	ast_channel_unlock(chan);
+
+	if (max_forwards <= 0) {
+		ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
+		return -1;
+	}
+
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index 77e18aefa6698199542d94b94ef5737a22c36396..b051d892450c0782e9e49e78564615e48f515083 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -46,6 +46,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/global_datastores.h"
 #include "asterisk/bridge_basic.h"
 #include "asterisk/bridge_after.h"
+#include "asterisk/max_forwards.h"
 
 /*** DOCUMENTATION
 	<function name="CHANNELS" language="en_US">
@@ -391,6 +392,16 @@ ASTERISK_REGISTER_FILE()
 					<enum name="caller_url">
 						<para>R/0 Returns caller URL</para>
 					</enum>
+					<enum name="max_forwards">
+						<para>R/W Get or set the maximum number of call forwards for this channel.
+
+						This number describes the number of times a call may be forwarded by this channel
+						before the call fails. "Forwards" in this case refers to redirects by phones as well
+						as calls to local channels.
+
+						Note that this has no relation to the SIP Max-Forwards header.
+						</para>
+					</enum>
 				</enumlist>
 			</parameter>
 		</syntax>
@@ -583,6 +594,10 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 			}
 		}
 		ast_channel_unlock(chan);
+	} else if (!strcasecmp(data, "max_forwards")) {
+		ast_channel_lock(chan);
+		snprintf(buf, len, "%d", ast_max_forwards_get(chan));
+		ast_channel_unlock(chan);
 	} else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
 		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
 		ret = -1;
@@ -743,6 +758,16 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
 			store->media = ast_true(value) ? 1 : 0;
 		}
 		ast_channel_unlock(chan);
+	} else if (!strcasecmp(data, "max_forwards")) {
+		int max_forwards;
+		if (sscanf(value, "%d", &max_forwards) != 1) {
+			ast_log(LOG_WARNING, "Unable to set max forwards to '%s'\n", value);
+			ret = -1;
+		} else {
+			ast_channel_lock(chan);
+			ret = ast_max_forwards_set(chan, max_forwards);
+			ast_channel_unlock(chan);
+		}
 	} else if (!ast_channel_tech(chan)->func_channel_write
 		 || ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
 		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
diff --git a/include/asterisk/global_datastores.h b/include/asterisk/global_datastores.h
index 16267a894e95ee2193a855b488ae41e798aaee82..2946ede8496e15d07c0dc2f1cf58bb016d27cbec 100644
--- a/include/asterisk/global_datastores.h
+++ b/include/asterisk/global_datastores.h
@@ -26,14 +26,8 @@
 
 #include "asterisk/channel.h"
 
-extern const struct ast_datastore_info dialed_interface_info;
 extern const struct ast_datastore_info secure_call_info;
 
-struct ast_dialed_interface {
-	AST_LIST_ENTRY(ast_dialed_interface) list;
-	char interface[1];
-};
-
 struct ast_secure_call_store {
 	unsigned int signaling:1;
 	unsigned int media:1;
diff --git a/include/asterisk/max_forwards.h b/include/asterisk/max_forwards.h
new file mode 100644
index 0000000000000000000000000000000000000000..3130b4b64dc100aafc8823603c26958ef47f565f
--- /dev/null
+++ b/include/asterisk/max_forwards.h
@@ -0,0 +1,78 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef MAX_FORWARDS_H
+
+struct ast_channel;
+
+/*!
+ * \brief Set the starting max forwards for a particular channel.
+ *
+ * \pre chan is locked
+ *
+ * \param starting_count The value to set the max forwards to.
+ * \param chan The channel on which to set the max forwards.
+ * \retval 0 Success
+ * \retval 1 Failure
+ */
+int ast_max_forwards_set(struct ast_channel *chan, int starting_count);
+
+/*!
+ * \brief Get the current max forwards for a particular channel.
+ *
+ * If the channel has not had max forwards set on it, then the channel
+ * will have the default max forwards set on it and that value will
+ * be returned.
+ *
+ * \pre chan is locked
+ *
+ * \param chan The channel to get the max forwards for.
+ * \return The current max forwards count on the channel
+ */
+int ast_max_forwards_get(struct ast_channel *chan);
+
+/*!
+ * \brief Decrement the max forwards count for a particular channel.
+ *
+ * If the channel has not had max forwards set on it, then the channel
+ * will have the default max forwards set on it and that value will
+ * not be decremented.
+ *
+ * \pre chan is locked
+ *
+ * \chan The channel for which the max forwards value should be decremented
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_max_forwards_decrement(struct ast_channel *chan);
+
+/*!
+ * \brief Reset the max forwards on a channel to its starting value.
+ *
+ * If the channel has not had max forwards set on it, then the channel
+ * will have the default max forwards set on it.
+ *
+ * \pre chan is locked.
+ *
+ * \param chan The channel on which to reset the max forwards count.
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_max_forwards_reset(struct ast_channel *chan);
+
+#endif /* MAX_FORWARDS_H */
diff --git a/main/ccss.c b/main/ccss.c
index c1b3372dce4a3b7c932f8e5aa066306f1c8a9591..51edae745bac165d62168dab00b10f0ffabb70c6 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -2237,9 +2237,7 @@ static void call_destructor_with_no_monitor(const char * const monitor_type, voi
  * Note that it is not necessarily erroneous to add the same
  * device to the tree twice. If the same device is called by
  * two different extension during the same call, then
- * that is a legitimate situation. Of course, I'm pretty sure
- * the dialed_interfaces global datastore will not allow that
- * to happen anyway.
+ * that is a legitimate situation.
  *
  * \param device_name The name of the device being added to the tree
  * \param dialstring The dialstring used to dial the device being added
diff --git a/main/channel.c b/main/channel.c
index 4e418b6ea92527e0001d72ab382cbc7624af950b..db126db7636e60acd54e518bba02b572d82ce853 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -75,6 +75,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/bridge.h"
 #include "asterisk/test.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/max_forwards.h"
 
 /*** DOCUMENTATION
  ***/
@@ -5621,6 +5622,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
 	ast_channel_lock_both(parent, new_chan);
 	ast_channel_inherit_variables(parent, new_chan);
 	ast_channel_datastore_inherit(parent, new_chan);
+	ast_max_forwards_decrement(new_chan);
 	ast_channel_unlock(new_chan);
 	ast_channel_unlock(parent);
 }
@@ -5740,6 +5742,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
 			ast_channel_lock_both(oh->parent_channel, chan);
 			ast_channel_inherit_variables(oh->parent_channel, chan);
 			ast_channel_datastore_inherit(oh->parent_channel, chan);
+			ast_max_forwards_decrement(chan);
 			ast_channel_unlock(oh->parent_channel);
 			ast_channel_unlock(chan);
 		}
diff --git a/main/dial.c b/main/dial.c
index f0cf127375f0cec5386b08bd49038ebc06692c7c..b935b6d8b693b2fff4fc51a399e3745556395507 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -44,6 +44,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/app.h"
 #include "asterisk/causes.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/max_forwards.h"
 
 /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
 struct ast_dial {
@@ -299,6 +300,19 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 		.uniqueid2 = channel->assignedid2,
 	};
 
+	if (chan) {
+		int max_forwards;
+
+		ast_channel_lock(chan);
+		max_forwards = ast_max_forwards_get(chan);
+		ast_channel_unlock(chan);
+
+		if (max_forwards <= 0) {
+			ast_log(LOG_WARNING, "Cannot dial from channel '%s'. Max forwards exceeded\n",
+					ast_channel_name(chan));
+		}
+	}
+
 	/* Copy device string over */
 	ast_copy_string(numsubst, channel->device, sizeof(numsubst));
 
@@ -337,6 +351,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 	if (chan) {
 		ast_channel_inherit_variables(chan, channel->owner);
 		ast_channel_datastore_inherit(chan, channel->owner);
+		ast_max_forwards_decrement(channel->owner);
 
 		/* Copy over callerid information */
 		ast_party_redirecting_copy(ast_channel_redirecting(channel->owner), ast_channel_redirecting(chan));
diff --git a/main/features.c b/main/features.c
index 971fb4a025308ac55a4b146f35e9d136e4a786af..4acd8aab25ddcadcbea9069a79512c3308da6add 100644
--- a/main/features.c
+++ b/main/features.c
@@ -78,6 +78,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/features_config.h"
+#include "asterisk/max_forwards.h"
 
 /*** DOCUMENTATION
 	<application name="Bridge" language="en_US">
@@ -420,22 +421,6 @@ static void add_features_datastores(struct ast_channel *caller, struct ast_chann
 	add_features_datastore(callee, &config->features_callee, &config->features_caller);
 }
 
-static void clear_dialed_interfaces(struct ast_channel *chan)
-{
-	struct ast_datastore *di_datastore;
-
-	ast_channel_lock(chan);
-	if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
-		if (option_debug) {
-			ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
-		}
-		if (!ast_channel_datastore_remove(chan, di_datastore)) {
-			ast_datastore_free(di_datastore);
-		}
-	}
-	ast_channel_unlock(chan);
-}
-
 static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
 {
 	if (config->end_sound) {
@@ -572,20 +557,13 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer,
 	ast_channel_log("Pre-bridge PEER Channel info", peer);
 #endif
 
-	/*
-	 * If we are bridging a call, stop worrying about forwarding
-	 * loops.  We presume that if a call is being bridged, that the
-	 * humans in charge know what they're doing.  If they don't,
-	 * well, what can we do about that?
-	 */
-	clear_dialed_interfaces(chan);
-	clear_dialed_interfaces(peer);
-
 	res = 0;
 	ast_channel_lock(chan);
+	ast_max_forwards_reset(chan);
 	res |= ast_bridge_features_ds_append(chan, &config->features_caller);
 	ast_channel_unlock(chan);
 	ast_channel_lock(peer);
+	ast_max_forwards_reset(peer);
 	res |= ast_bridge_features_ds_append(peer, &config->features_callee);
 	ast_channel_unlock(peer);
 
diff --git a/main/global_datastores.c b/main/global_datastores.c
index dd1e0278e495a7268c6acec94e112c185015db72..8ba769d3d2f8175113c32c7fc762035a44027dec 100644
--- a/main/global_datastores.c
+++ b/main/global_datastores.c
@@ -32,62 +32,6 @@
 ASTERISK_REGISTER_FILE()
 
 #include "asterisk/global_datastores.h"
-#include "asterisk/linkedlists.h"
-
-static void dialed_interface_destroy(void *data)
-{
-	struct ast_dialed_interface *di = NULL;
-	AST_LIST_HEAD(, ast_dialed_interface) *dialed_interface_list = data;
-	
-	if (!dialed_interface_list) {
-		return;
-	}
-
-	AST_LIST_LOCK(dialed_interface_list);
-	while ((di = AST_LIST_REMOVE_HEAD(dialed_interface_list, list)))
-		ast_free(di);
-	AST_LIST_UNLOCK(dialed_interface_list);
-
-	AST_LIST_HEAD_DESTROY(dialed_interface_list);
-	ast_free(dialed_interface_list);
-}
-
-static void *dialed_interface_duplicate(void *data)
-{
-	struct ast_dialed_interface *di = NULL;
-	AST_LIST_HEAD(, ast_dialed_interface) *old_list;
-	AST_LIST_HEAD(, ast_dialed_interface) *new_list = NULL;
-
-	if(!(old_list = data)) {
-		return NULL;
-	}
-
-	if(!(new_list = ast_calloc(1, sizeof(*new_list)))) {
-		return NULL;
-	}
-
-	AST_LIST_HEAD_INIT(new_list);
-	AST_LIST_LOCK(old_list);
-	AST_LIST_TRAVERSE(old_list, di, list) {
-		struct ast_dialed_interface *di2 = ast_calloc(1, sizeof(*di2) + strlen(di->interface));
-		if(!di2) {
-			AST_LIST_UNLOCK(old_list);
-			dialed_interface_destroy(new_list);
-			return NULL;
-		}
-		strcpy(di2->interface, di->interface);
-		AST_LIST_INSERT_TAIL(new_list, di2, list);
-	}
-	AST_LIST_UNLOCK(old_list);
-
-	return new_list;
-}
-
-const struct ast_datastore_info dialed_interface_info = {
-	.type = "dialed-interface",
-	.destroy = dialed_interface_destroy,
-	.duplicate = dialed_interface_duplicate,
-};
 
 static void secure_call_store_destroy(void *data)
 {
diff --git a/main/max_forwards.c b/main/max_forwards.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f1d4eed1c88ec03a7b6d68c086478d4af67d5b1
--- /dev/null
+++ b/main/max_forwards.c
@@ -0,0 +1,165 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not mfrectly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, mfstributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include "asterisk/max_forwards.h"
+#include "asterisk/channel.h"
+
+#define DEFAULT_MAX_FORWARDS 20
+
+/*!
+ * \brief Channel datastore data for max forwards
+ */
+struct max_forwards {
+	/*! The starting count. Used to allow resetting to the original value */
+	int starting_count;
+	/*! The current count. When this reaches 0, you're outta luck */
+	int current_count;
+};
+
+static struct max_forwards *max_forwards_alloc(int starting_count, int current_count)
+{
+	struct max_forwards *mf;
+
+	mf = ast_malloc(sizeof(*mf));
+	if (!mf) {
+		return NULL;
+	}
+
+	mf->starting_count = starting_count;
+	mf->current_count = current_count;
+
+	return mf;
+}
+
+static void *max_forwards_duplicate(void *data)
+{
+	struct max_forwards *mf = data;
+
+	return max_forwards_alloc(mf->starting_count, mf->current_count);
+}
+
+static void max_forwards_destroy(void *data)
+{
+	ast_free(data);
+}
+
+const struct ast_datastore_info max_forwards_info = {
+	.type = "mfaled-interface",
+	.duplicate = max_forwards_duplicate,
+	.destroy = max_forwards_destroy,
+};
+
+static struct ast_datastore *max_forwards_datastore_alloc(struct ast_channel *chan,
+		int starting_count)
+{
+	struct ast_datastore *mf_datastore;
+	struct max_forwards *mf;
+
+	mf_datastore = ast_datastore_alloc(&max_forwards_info, NULL);
+	if (!mf_datastore) {
+		return NULL;
+	}
+	mf_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
+
+	mf = max_forwards_alloc(starting_count, starting_count);
+	if (!mf) {
+		ast_datastore_free(mf_datastore);
+		return NULL;
+	}
+	mf_datastore->data = mf;
+
+	ast_channel_datastore_add(chan, mf_datastore);
+
+	return mf_datastore;
+}
+
+static struct ast_datastore *max_forwards_datastore_find_or_alloc(struct ast_channel *chan)
+{
+	struct ast_datastore *mf_datastore;
+
+	mf_datastore = ast_channel_datastore_find(chan, &max_forwards_info, NULL);
+	if (!mf_datastore) {
+		mf_datastore = max_forwards_datastore_alloc(chan, DEFAULT_MAX_FORWARDS);
+	}
+
+	return mf_datastore;
+}
+
+int ast_max_forwards_set(struct ast_channel *chan, int starting_count)
+{
+	struct ast_datastore *mf_datastore;
+	struct max_forwards *mf;
+
+	mf_datastore = max_forwards_datastore_find_or_alloc(chan);
+	if (!mf_datastore) {
+		return -1;
+	}
+
+	mf = mf_datastore->data;
+	mf->starting_count = mf->current_count = starting_count;
+
+	return 0;
+}
+
+int ast_max_forwards_get(struct ast_channel *chan)
+{
+	struct ast_datastore *mf_datastore;
+	struct max_forwards *mf;
+
+	mf_datastore = max_forwards_datastore_find_or_alloc(chan);
+	if (!mf_datastore) {
+		return -1;
+	}
+
+	mf = mf_datastore->data;
+	return mf->current_count;
+}
+
+int ast_max_forwards_decrement(struct ast_channel *chan)
+{
+	struct ast_datastore *mf_datastore;
+	struct max_forwards *mf;
+
+	mf_datastore = max_forwards_datastore_find_or_alloc(chan);
+	if (!mf_datastore) {
+		return -1;
+	}
+
+	mf = mf_datastore->data;
+	--mf->current_count;
+
+	return 0;
+}
+
+int ast_max_forwards_reset(struct ast_channel *chan)
+{
+	struct ast_datastore *mf_datastore;
+	struct max_forwards *mf;
+
+	mf_datastore = max_forwards_datastore_find_or_alloc(chan);
+	if (!mf_datastore) {
+		return -1;
+	}
+
+	mf = mf_datastore->data;
+	mf->current_count = mf->starting_count;
+
+	return 0;
+}
diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c
index a4ac157e4ee3c99335368f964e1d26dc97aad12c..49f78921209c61324bef2cccbd68b8c9c08dbd87 100644
--- a/res/res_pjsip_diversion.c
+++ b/res/res_pjsip_diversion.c
@@ -248,6 +248,7 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect
 	pjsip_name_addr *name_addr;
 	pjsip_sip_uri *uri;
 	pjsip_param *param;
+	pjsip_fromto_hdr *old_hdr;
 
 	struct ast_party_id *id = &data->from;
 	pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
@@ -273,6 +274,10 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect
 	pj_list_insert_before(&hdr->other_param, param);
 
 	hdr->uri = (pjsip_uri *) name_addr;
+	old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
+	if (old_hdr) {
+		pj_list_erase(old_hdr);
+	}
 	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
 }