Merge "[netlink] Updating netlink interface"
diff --git a/Makefile b/Makefile
index 676e283..49de9fe 100755
--- a/Makefile
+++ b/Makefile
@@ -80,15 +80,26 @@
 ccflags-$(ECM_INTERFACE_L2TPV2_ENABLE) += -DECM_INTERFACE_L2TPV2_ENABLE
 
 # #############################################################################
-# if pppoe, l2tpv2 acceleration is enabled, ppp should
+# Define ECM_INTERFACE_PPTP_ENABLE=y in order
+# to enable support for pptp acceleration.
+# #############################################################################
+ifneq ($(findstring 3.4, $(KERNELVERSION)),)
+ECM_INTERFACE_PPTP_ENABLE=y
+endif
+ccflags-$(ECM_INTERFACE_PPTP_ENABLE) += -DECM_INTERFACE_PPTP_ENABLE
+
+# #############################################################################
+# if pppoe, l2tpv2, pptp acceleration is enabled, ppp should
 # be enabled automatically
 # #############################################################################
 ECM_INTERFACE_PPP_ENABLE=y
 ifeq "$(ECM_INTERFACE_PPPOE_ENABLE)" "n"
 ifeq "$(ECM_INTERFACE_L2TPV2_ENABLE)" "n"
+ifeq "$(ECM_INTERFACE_PPTP_ENABLE)" "n"
 ECM_INTERFACE_PPP_ENABLE=n
 endif
 endif
+endif
 ccflags-$(ECM_INTERFACE_PPP_ENABLE) += -DECM_INTERFACE_PPP_ENABLE
 
 # #############################################################################
@@ -109,13 +120,10 @@
 # Define ECM_MULTICAST_ENABLE=y in order to enable support for ECM Multicast
 # #############################################################################
 ifeq ($(ECM_FRONT_END_NSS_ENABLE), y)
-ifneq ($(findstring 3.4, $(KERNELVERSION)),)
-ECM_MULTICAST_ENABLE=y
-endif
-endif
 ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv4.o
 ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv6.o
 ccflags-$(ECM_MULTICAST_ENABLE) += -DECM_MULTICAST_ENABLE
+endif
 
 # #############################################################################
 # Define ECM_INTERFACE_VLAN_ENABLE=y in order to enable support for VLAN
diff --git a/ecm_classifier.h b/ecm_classifier.h
index d3068dd..19a386f 100644
--- a/ecm_classifier.h
+++ b/ecm_classifier.h
@@ -152,6 +152,12 @@
 #endif
 
 /*
+ * Determines if a connection should be kept.
+ */
+typedef bool (*ecm_classifier_should_keep_connection_t)
+	(struct ecm_classifier_instance *ci, uint8_t *mac);
+
+/*
  * Base class for all types of classifiers
  */
 struct ecm_classifier_instance {
@@ -172,6 +178,8 @@
 							/* Reclassify */
 	ecm_classifier_last_process_response_get_callback_t last_process_response_get;
 							/* Return last process response */
+	ecm_classifier_should_keep_connection_t should_keep_connection;
+							/* Check if connection should be kept when FDB updates */
 #ifdef ECM_STATE_OUTPUT_ENABLE
 	ecm_classifier_state_get_callback_t state_get;
 							/* Return its state */
diff --git a/ecm_classifier_hyfi.c b/ecm_classifier_hyfi.c
index 23fe114..656cc36 100644
--- a/ecm_classifier_hyfi.c
+++ b/ecm_classifier_hyfi.c
@@ -69,7 +69,7 @@
 #include "ecm_tracker_tcp.h"
 #include "ecm_db.h"
 #include "ecm_classifier_hyfi.h"
-
+#include "ecm_front_end_ipv4.h"
 /*
  * Magic numbers
  */
@@ -220,6 +220,7 @@
 	struct ecm_front_end_connection_instance *feci;
 	ecm_front_end_acceleration_mode_t accel_mode;
 	uint32_t became_relevant = 0;
+	uint32_t flag = 0;
 
 	chfi = (struct ecm_classifier_hyfi_instance *)aci;
 	DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed\n", chfi);
@@ -285,13 +286,21 @@
 	}
 
 	/*
-	 * Compute the hash
+	 * Compute the hashes in both forward and reverse directions
 	 */
-	if (unlikely(hyfi_hash_skbuf(skb, &chfi->flow.hash, &chfi->flow.flag, &chfi->flow.priority, &chfi->flow.seq))) {
+	if (unlikely(hyfi_hash_skbuf(skb, &chfi->flow.hash, &flag,
+		&chfi->flow.priority, &chfi->flow.seq)))
 		goto hyfi_classifier_done;
-	}
+
+	if (unlikely(hyfi_hash_skbuf_reverse(skb, &chfi->flow.reverse_hash)))
+		goto hyfi_classifier_done;
 
 	chfi->flow.ecm_serial = chfi->ci_serial;
+	if (flag & ECM_HYFI_IS_IPPROTO_UDP)
+		hyfi_ecm_set_flag(&chfi->flow, ECM_HYFI_IS_IPPROTO_UDP);
+	else
+		hyfi_ecm_clear_flag(&chfi->flow, ECM_HYFI_IS_IPPROTO_UDP);
+
 	memcpy(&chfi->flow.sa, eth_hdr(skb)->h_source, ETH_ALEN);
 	memcpy(&chfi->flow.da, eth_hdr(skb)->h_dest, ETH_ALEN);
 
@@ -315,9 +324,25 @@
 {
 	struct ecm_classifier_hyfi_instance *chfi;
 	struct ecm_db_connection_instance *ci;
-	uint64_t num_packets = 0;
-	uint64_t num_bytes = 0;
-	int32_t ret;
+	uint64_t from_packets = 0;
+	uint64_t from_bytes = 0;
+	uint64_t to_packets = 0;
+	uint64_t to_bytes = 0;
+	uint64_t from_packets_dropped = 0;
+	uint64_t from_bytes_dropped = 0;
+	uint64_t to_packets_dropped = 0;
+	uint64_t to_bytes_dropped = 0;
+	int32_t ret_fwd, ret_rev;
+	u_int32_t time_now, time_elapsed_fwd, time_elapsed_rev;
+	uint8_t flow_dest_addr[ETH_ALEN];
+	uint64_t fwd_bytes, rev_bytes, fwd_packets, rev_packets;
+	bool should_keep_on_fdb_update_fwd, should_keep_on_fdb_update_rev;
+
+	if (sync->reason != ECM_FRONT_END_IPV4_RULE_SYNC_REASON_STATS) {
+		DEBUG_TRACE("%p: Update not due to stats: %d\n",
+			aci, sync->reason);
+		return;
+	}
 
 	chfi = (struct ecm_classifier_hyfi_instance *)aci;
 	DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed", chfi);
@@ -336,39 +361,106 @@
 	/*
 	 * Update the stats on Hy-Fi side
 	 */
-	ecm_db_connection_data_stats_get(ci, NULL, &num_bytes,
-			NULL, &num_packets,
-			NULL, NULL,
-			NULL, NULL );
+	ecm_db_connection_to_node_address_get(ci, &flow_dest_addr[0]);
+	ecm_db_connection_data_stats_get(ci, &from_bytes, &to_bytes,
+			&from_packets, &to_packets,
+			&from_bytes_dropped, &to_bytes_dropped,
+			&from_packets_dropped, &to_packets_dropped);
 	ecm_db_connection_deref(ci);
 
-	DEBUG_INFO("UPDATE STATS: Flow serial: %d\nFlow hash: 0x%02x, priority 0x%08x, flag: %d\nSA: %pM\nDA: %pM\n\n",
-			chfi->flow.ecm_serial, chfi->flow.hash, chfi->flow.priority, chfi->flow.flag,
+	DEBUG_INFO("UPDATE STATS: Flow serial: %d\npriority 0x%08x, flag: %d\nSA: %pM\nDA: %pM\n\n",
+			chfi->flow.ecm_serial, chfi->flow.priority, chfi->flow.flag,
 			chfi->flow.sa, chfi->flow.da);
 
-	DEBUG_INFO("num_bytes = %lld, num_packets = %lld\n", num_bytes, num_packets);
+	time_now = jiffies;
+	/*
+	 * Make sure destination address still matches
+	 */
+	if (memcmp(&flow_dest_addr[0], &chfi->flow.da[0], ETH_ALEN)) {
+		DEBUG_INFO("UPDATE STATS: Direction of flow is "
+			"reverse of expectation\n");
+		fwd_bytes = (to_bytes - to_bytes_dropped);
+		fwd_packets = (to_packets - to_packets_dropped);
+		rev_bytes = (from_bytes - from_bytes_dropped);
+		rev_packets = (from_packets - from_packets_dropped);
+	} else {
+		fwd_bytes = (from_bytes - from_bytes_dropped);
+		fwd_packets = (from_packets - from_packets_dropped);
+		rev_bytes = (to_bytes - to_bytes_dropped);
+		rev_packets = (to_packets - to_packets_dropped);
+	}
 
-	ret = hyfi_ecm_update_stats(&chfi->flow, num_bytes, num_packets);
+	/*
+	 * Update forward direction 'from' bytes
+	 */
+	ret_fwd = hyfi_ecm_update_stats(&chfi->flow, chfi->flow.hash,
+		&chfi->flow.da[0], &chfi->flow.sa[0],
+		fwd_bytes, fwd_packets, time_now,
+		&should_keep_on_fdb_update_fwd,
+		&time_elapsed_fwd);
+	DEBUG_INFO("ret_fwd %d Forward hash: 0x%02x, from_bytes = %lld, from_packets = %lld, "
+		"num_bytes_dropped = %lld, num_packets_dropped = %lld\n",
+		ret_fwd, chfi->flow.hash, from_bytes, from_packets,
+		from_bytes_dropped, from_packets_dropped);
 
-	if (ret < 0) {
-		printk("%s: Fatal error\n", __func__);
+	/*
+	 * Update reverse direction 'to' bytes
+	 */
+	ret_rev = hyfi_ecm_update_stats(&chfi->flow, chfi->flow.reverse_hash,
+		&chfi->flow.sa[0], &chfi->flow.da[0],
+		rev_bytes, rev_packets, time_now,
+		&should_keep_on_fdb_update_rev,
+		&time_elapsed_rev);
+
+	DEBUG_INFO("ret_rev %d Reverse hash: 0x%02x, to_bytes = %lld, to_packets = %lld, "
+		"num_bytes_dropped = %lld, num_packets_dropped = %lld\n",
+		ret_rev, chfi->flow.reverse_hash, to_bytes, to_packets,
+		to_bytes_dropped, to_packets_dropped);
+
+	chfi->flow.last_update = time_now;
+	chfi->flow.last_elapsed_time = time_elapsed_fwd >= time_elapsed_rev ?
+		time_elapsed_fwd : time_elapsed_rev;
+
+	if (!time_elapsed_fwd) {
+		if (should_keep_on_fdb_update_fwd) {
+			hyfi_ecm_set_flag(&chfi->flow,
+				ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_FWD);
+		} else {
+			hyfi_ecm_clear_flag(&chfi->flow,
+				ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_FWD);
+		}
+	}
+
+	if (!time_elapsed_rev) {
+		if (should_keep_on_fdb_update_rev) {
+			hyfi_ecm_set_flag(&chfi->flow,
+				ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_REV);
+		} else {
+			hyfi_ecm_clear_flag(&chfi->flow,
+				ECM_HYFI_SHOULD_KEEP_ON_FDB_UPDATE_REV);
+		}
+	}
+
+	if (ret_fwd < 0 || ret_rev < 0) {
+		DEBUG_ERROR("%p: Error updating stats", aci);
 		return;
 	}
 
-	switch(ret)
-	{
-	case 0: /* OK */
+	/*
+	 * Only need to be interested in forward or reverse direction
+	 */
+	if (ret_fwd == 0 || ret_rev == 0) {
 		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_REGISTERED;
-		break;
-
-	case 1: /* Not interested */
-		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
-		break;
-
-	case 2: /* Not attached, may be interested in the future */
-	default:
+	} else if (ret_fwd == 2 || ret_rev == 2) {
+		/*
+		 * Not attached, may be interested in the future
+		 */
 		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_INIT;
-		break;
+	} else {
+		/*
+		 * Not interested
+		 */
+		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
 	}
 }
 
@@ -390,57 +482,8 @@
  */
 static void ecm_classifier_hyfi_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
 {
-	struct ecm_classifier_hyfi_instance *chfi;
-	struct ecm_db_connection_instance *ci;
-	uint64_t num_packets = 0;
-	uint64_t num_bytes = 0;
-	int32_t ret;
-
-	chfi = (struct ecm_classifier_hyfi_instance *)aci;
-	DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC, "%p: magic failed", chfi);
-
-	if (chfi->hyfi_state &
-			(ECM_CLASSIFIER_HYFI_STATE_IGNORE)) {
-		return;
-	}
-
-	ci = ecm_db_connection_serial_find_and_ref(chfi->ci_serial);
-	if (!ci) {
-		DEBUG_TRACE("%p: No ci found for %u\n", chfi, chfi->ci_serial);
-		return;
-	}
-
-	/*
-	 * Update the stats on Hy-Fi side
-	 */
-	ecm_db_connection_data_stats_get(ci, NULL, &num_bytes,
-			NULL, &num_packets,
-			NULL, NULL,
-			NULL, NULL );
-	ecm_db_connection_deref(ci);
-
-	ret = hyfi_ecm_update_stats(&chfi->flow, num_bytes, num_packets);
-
-	if (ret < 0) {
-		DEBUG_ERROR("%s: Fatal error\n", __func__);
-		return;
-	}
-
-	switch(ret)
-	{
-	case 0: /* OK */
-		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_REGISTERED;
-		break;
-
-	case 1: /* Not interested */
-		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_IGNORE;
-		break;
-
-	case 2: /* Not attached, may be interested in the future */
-	default:
-		chfi->hyfi_state = ECM_CLASSIFIER_HYFI_STATE_INIT;
-		break;
-	}
+	/* Same processing as v4 */
+	ecm_classifier_hyfi_sync_to_v4(aci, sync);
 }
 
 /*
@@ -543,6 +586,24 @@
 }
 #endif
 
+static bool ecm_classifier_hyfi_should_keep_connection(
+	struct ecm_classifier_instance *aci, uint8_t *mac)
+{
+	struct ecm_classifier_hyfi_instance *chfi;
+
+	chfi = (struct ecm_classifier_hyfi_instance *)aci;
+	DEBUG_CHECK_MAGIC(chfi, ECM_CLASSIFIER_HYFI_INSTANCE_MAGIC,
+		"%p: magic failed", chfi);
+
+	if (chfi->hyfi_state &
+			(ECM_CLASSIFIER_HYFI_STATE_IGNORE)) {
+		/* HyFi doesn't care if connection deleted */
+		return false;
+	}
+
+	return hyfi_ecm_should_keep(&chfi->flow, mac);
+}
+
 /*
  * ecm_classifier_hyfi_instance_alloc()
  *	Allocate an instance of the HyFi classifier
@@ -571,6 +632,8 @@
 	chfi->base.last_process_response_get = ecm_classifier_hyfi_last_process_response_get;
 	chfi->base.reclassify_allowed = ecm_classifier_hyfi_reclassify_allowed;
 	chfi->base.reclassify = ecm_classifier_hyfi_reclassify;
+	chfi->base.should_keep_connection =
+		ecm_classifier_hyfi_should_keep_connection;
 #ifdef ECM_STATE_OUTPUT_ENABLE
 	chfi->base.state_get = ecm_classifier_hyfi_state_get;
 #endif
@@ -628,7 +691,6 @@
 	uint32_t serial = ecm_db_connection_serial_get(ci);
 	DEBUG_INFO("%p: HYFI LISTENER: added conn with serial: %u\n", ci, serial);
 #endif
-//	Add your own code here
 }
 
 /*
@@ -637,11 +699,34 @@
  */
 static void ecm_classifier_hyfi_connection_removed(void *arg, struct ecm_db_connection_instance *ci)
 {
-#if (DEBUG_LEVEL > 2)
+	struct ecm_classifier_instance *aci;
+	struct ecm_classifier_hyfi_instance *chfi;
 	uint32_t serial = ecm_db_connection_serial_get(ci);
+
 	DEBUG_INFO("%p: HYFI LISTENER: removed conn with serial: %u\n", ci, serial);
-#endif
-//	Add your own code here
+
+	/*
+	 * Only handle events if there is an HyFi classifier attached
+	 */
+	aci = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_HYFI);
+	if (!aci) {
+		DEBUG_TRACE("%p: Connection removed ignored"
+			" - no HyFi classifier\n", ci);
+		return;
+	}
+
+	chfi = (struct ecm_classifier_hyfi_instance *)aci;
+	DEBUG_INFO("%p: removed conn with serial: %u, "
+		"hash 0x%x, rev hash 0x%x\n",
+		aci, serial, chfi->flow.hash, chfi->flow.reverse_hash);
+
+	/*
+	 * Mark as decelerated
+	 */
+	hyfi_ecm_decelerate(chfi->flow.hash, serial);
+	hyfi_ecm_decelerate(chfi->flow.reverse_hash, serial);
+
+	aci->deref(aci);
 }
 
 /*
diff --git a/ecm_db.c b/ecm_db.c
index 5d825c8..b2d3550 100644
--- a/ecm_db.c
+++ b/ecm_db.c
@@ -256,6 +256,9 @@
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 		struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2;	/* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+		struct ecm_db_interface_info_pptp pptp;			/* type == ECM_DB_IFACE_TYPE_PPTP */
+#endif
 		struct ecm_db_interface_info_unknown unknown;		/* type == ECM_DB_IFACE_TYPE_UNKNOWN */
 		struct ecm_db_interface_info_loopback loopback;		/* type == ECM_DB_IFACE_TYPE_LOOPBACK */
 #ifdef ECM_INTERFACE_IPSEC_ENABLE
@@ -882,7 +885,8 @@
 	"UNKNOWN",
 	"SIT",
 	"TUNIPIP6",
-	"PPPoL2TPV2"
+	"PPPoL2TPV2",
+	"PPTP"
 };
 
 /*
@@ -3958,6 +3962,18 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_generate_hash_index_pptp()
+ *	Calculate the hash index.
+ */
+static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pptp(uint16_t pptp_src_call_id, uint16_t pptp_dst_call_id)
+{
+	uint32_t hash_val;
+	hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
+	return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
+}
+#endif
 /*
  * ecm_db_iface_generate_hash_index_unknown()
  * 	Calculate the hash index.
@@ -4538,6 +4554,65 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_pptp_session_info_get
+ *	get pptp specific info
+ */
+void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
+{
+	DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
+	DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%p: Bad type, expected pptp, actual: %d\n", ii, ii->type);
+	spin_lock_bh(&ecm_db_lock);
+	memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
+	spin_unlock_bh(&ecm_db_lock);
+}
+EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
+
+/*
+ * ecm_db_iface_find_and_ref_pptp()
+ *	Lookup and return a iface reference if any
+ */
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id)
+{
+	ecm_db_iface_hash_t hash_index;
+	struct ecm_db_iface_instance *ii;
+
+	/*
+	 * Compute the hash chain index and prepare to walk the chain
+	 */
+	hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
+
+	DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
+									pptp_dst_call_id, hash_index);
+
+	/*
+	 * Iterate the chain looking for a host with matching details
+	 */
+	spin_lock_bh(&ecm_db_lock);
+	ii = ecm_db_iface_table[hash_index];
+
+	while (ii) {
+		if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
+				|| (ii->type_info.pptp.src_call_id != pptp_src_call_id)
+				|| (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)) {
+			ii = ii->hash_next;
+			continue;
+		}
+
+		_ecm_db_iface_ref(ii);
+		spin_unlock_bh(&ecm_db_lock);
+		DEBUG_TRACE("iface found %p\n", ii);
+		return ii;
+	}
+	spin_unlock_bh(&ecm_db_lock);
+
+	DEBUG_TRACE("Iface not found\n");
+	return NULL;
+}
+EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
+#endif
+
 /*
  * ecm_db_iface_find_and_ref_unknown()
  *	Lookup and return a iface reference if any
@@ -7710,6 +7785,45 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_pptp_state_get()
+ *	Return interface type specific state
+ */
+static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
+{
+	int result;
+	struct ecm_db_interface_info_pptp type_info;
+
+	DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+	spin_lock_bh(&ecm_db_lock);
+	memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
+	spin_unlock_bh(&ecm_db_lock);
+
+	result = ecm_state_prefix_add(sfi, "pptp");
+	if (result) {
+		return result;
+	}
+
+	result = ecm_db_iface_state_get_base(ii, sfi);
+	if (result) {
+		return result;
+	}
+
+	result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
+	if (result) {
+		return result;
+	}
+
+	result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
+	if (result) {
+		return result;
+	}
+
+	return ecm_state_prefix_remove(sfi);
+}
+#endif
+
 /*
  * ecm_db_iface_unknown_state_get()
  * 	Return interface type specific state
@@ -9547,6 +9661,123 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_db_iface_add_pptp()
+ *	Add a iface instance into the database
+ */
+void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
+					char *name, int32_t mtu, int32_t interface_identifier,
+					int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
+					void *arg)
+{
+	ecm_db_iface_hash_t hash_index;
+	ecm_db_iface_id_hash_t iface_id_hash_index;
+	struct ecm_db_listener_instance *li;
+	struct ecm_db_interface_info_pptp *type_info;
+
+	DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+	spin_lock_bh(&ecm_db_lock);
+#ifdef ECM_DB_XREF_ENABLE
+	DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
+#endif
+	DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
+	DEBUG_ASSERT(name, "%p: no name given\n", ii);
+	spin_unlock_bh(&ecm_db_lock);
+
+	/*
+	 * Record general info
+	 */
+	ii->type = ECM_DB_IFACE_TYPE_PPTP;
+#ifdef ECM_STATE_OUTPUT_ENABLE
+	ii->state_get = ecm_db_iface_pptp_state_get;
+#endif
+	ii->arg = arg;
+	ii->final = final;
+	strlcpy(ii->name, name, IFNAMSIZ);
+	ii->mtu = mtu;
+	ii->interface_identifier = interface_identifier;
+	ii->ae_interface_identifier = ae_interface_identifier;
+
+	/*
+	 * Type specific info
+	 */
+	type_info = &ii->type_info.pptp;
+	memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
+
+	/*
+	 * Compute hash chain for insertion
+	 */
+	hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
+							  type_info->dst_call_id);
+	ii->hash_index = hash_index;
+
+	iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
+	ii->iface_id_hash_index = iface_id_hash_index;
+	/*
+	 * Add into the global list
+	 */
+	spin_lock_bh(&ecm_db_lock);
+	ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
+	ii->prev = NULL;
+	ii->next = ecm_db_interfaces;
+	if (ecm_db_interfaces) {
+		ecm_db_interfaces->prev = ii;
+	}
+	ecm_db_interfaces = ii;
+
+	/*
+	 * Insert into chain
+	 */
+	ii->hash_next = ecm_db_iface_table[hash_index];
+	if (ecm_db_iface_table[hash_index]) {
+		ecm_db_iface_table[hash_index]->hash_prev = ii;
+	}
+	ecm_db_iface_table[hash_index] = ii;
+	ecm_db_iface_table_lengths[hash_index]++;
+	DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
+
+	DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
+
+	/*
+	 * Insert into interface identifier chain
+	 */
+	ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
+	if (ecm_db_iface_id_table[iface_id_hash_index]) {
+		ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
+	}
+	ecm_db_iface_id_table[iface_id_hash_index] = ii;
+	ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
+	DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
+
+	/*
+	 * Set time of addition
+	 */
+	ii->time_added = ecm_db_time;
+	spin_unlock_bh(&ecm_db_lock);
+
+	/*
+	 * Throw add event to the listeners
+	 */
+	DEBUG_TRACE("%p: Throw iface added event\n", ii);
+	li = ecm_db_listeners_get_and_ref_first();
+	while (li) {
+		struct ecm_db_listener_instance *lin;
+		if (li->iface_added) {
+			li->iface_added(li->arg, ii);
+		}
+
+		/*
+		 * Get next listener
+		 */
+		lin = ecm_db_listener_get_and_ref_next(li);
+		ecm_db_listener_deref(li);
+		li = lin;
+	}
+}
+EXPORT_SYMBOL(ecm_db_iface_add_pptp);
+#endif
+
 /*
  * ecm_db_iface_add_unknown()
  *	Add a iface instance into the database
@@ -11297,11 +11528,41 @@
 }
 
 /*
+ * ecm_db_should_keep_connection()
+ *	check if any classifier believes this connection should
+ *	be kept
+ */
+static bool ecm_db_should_keep_connection(
+	struct ecm_db_connection_instance *ci, uint8_t *mac)
+{
+	bool should_keep_connection = false;
+	int assignment_count;
+	int aci_index;
+	struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
+
+	assignment_count =
+		ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
+	for (aci_index = 0; aci_index < assignment_count; ++aci_index) {
+		struct ecm_classifier_instance *aci;
+		aci = assignments[aci_index];
+		if (aci->should_keep_connection &&
+			aci->should_keep_connection(aci, mac)) {
+			should_keep_connection = true;
+			break;
+		}
+	}
+	ecm_db_connection_assignments_release(assignment_count, assignments);
+
+	return should_keep_connection;
+}
+
+/*
  * ecm_db_traverse_node_from_connection_list_and_decelerate()
  *	traverse from_list of a node and calls ecm_db_connection_decelerate_and_defunct()
  *	for each entry
  */
-void ecm_db_traverse_node_from_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_from_connection_list_and_decelerate(
+	struct ecm_db_node_instance *node)
 {
 	struct ecm_db_connection_instance *ci = NULL;
 
@@ -11312,8 +11573,12 @@
 	while (ci) {
 		struct ecm_db_connection_instance *cin;
 
-		DEBUG_TRACE("%p: defunct\n", ci);
-		ecm_db_connection_decelerate_and_defunct(ci);
+		if (!ecm_db_should_keep_connection(ci, node->address)) {
+			DEBUG_TRACE("%p: defunct\n", ci);
+			ecm_db_connection_decelerate_and_defunct(ci);
+		} else {
+			DEBUG_TRACE("%p: keeping connection\n", ci);
+		}
 
 		cin = ecm_db_node_from_connection_get_and_ref_next(ci);
 		ecm_db_connection_deref(ci);
@@ -11327,7 +11592,8 @@
  *	traverse to_list of a node and calls ecm_db_connection_decelerate_and_defunct()
  *	for each entry
  */
-void ecm_db_traverse_node_to_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_to_connection_list_and_decelerate(
+	struct ecm_db_node_instance *node)
 {
 	struct ecm_db_connection_instance *ci = NULL;
 
@@ -11338,8 +11604,12 @@
 	while (ci) {
 		struct ecm_db_connection_instance *cin;
 
-		DEBUG_TRACE("%p: defunct\n", ci);
-		ecm_db_connection_decelerate_and_defunct(ci);
+		if (!ecm_db_should_keep_connection(ci, node->address)) {
+			DEBUG_TRACE("%p: defunct\n", ci);
+			ecm_db_connection_decelerate_and_defunct(ci);
+		} else {
+			DEBUG_TRACE("%p: keeping connection\n", ci);
+		}
 
 		cin = ecm_db_node_to_connection_get_and_ref_next(ci);
 		ecm_db_connection_deref(ci);
@@ -11353,7 +11623,8 @@
  *	traverse from_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
  *	for each entry
  */
-void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(
+	struct ecm_db_node_instance *node)
 {
 	struct ecm_db_connection_instance *ci = NULL;
 
@@ -11364,8 +11635,12 @@
 	while (ci) {
 		struct ecm_db_connection_instance *cin;
 
-		DEBUG_TRACE("%p: defunct\n", ci);
-		ecm_db_connection_decelerate_and_defunct(ci);
+		if (!ecm_db_should_keep_connection(ci, node->address)) {
+			DEBUG_TRACE("%p: defunct\n", ci);
+			ecm_db_connection_decelerate_and_defunct(ci);
+		} else {
+			DEBUG_TRACE("%p: keeping connection\n", ci);
+		}
 
 		cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
 		ecm_db_connection_deref(ci);
@@ -11379,7 +11654,8 @@
  *	traverse to_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
  *	for each entry
  */
-void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
+void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(
+	struct ecm_db_node_instance *node)
 {
 	struct ecm_db_connection_instance *ci = NULL;
 
@@ -11390,8 +11666,12 @@
 	while (ci) {
 		struct ecm_db_connection_instance *cin;
 
-		DEBUG_TRACE("%p: defunct\n", ci);
-		ecm_db_connection_decelerate_and_defunct(ci);
+		if (!ecm_db_should_keep_connection(ci, node->address)) {
+			DEBUG_TRACE("%p: defunct\n", ci);
+			ecm_db_connection_decelerate_and_defunct(ci);
+		} else {
+			DEBUG_TRACE("%p: keeping connection\n", ci);
+		}
 
 		cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
 		ecm_db_connection_deref(ci);
diff --git a/ecm_db.h b/ecm_db.h
index 68871dc..c4f5e84 100644
--- a/ecm_db.h
+++ b/ecm_db.h
@@ -154,6 +154,10 @@
 void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info);
 struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id);
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id);
+void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info);
+#endif
 struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident);
 #ifdef ECM_INTERFACE_IPSEC_ENABLE
 struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident);
@@ -278,6 +282,11 @@
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
 #endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
+#endif
+
 void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
 void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu, int32_t interface_identifier, int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final, void *arg);
 #ifdef ECM_INTERFACE_IPSEC_ENABLE
diff --git a/ecm_db_types.h b/ecm_db_types.h
index 69e526d..cc8cd05 100644
--- a/ecm_db_types.h
+++ b/ecm_db_types.h
@@ -242,6 +242,7 @@
 	ECM_DB_IFACE_TYPE_SIT,				/* IPv6 in IPv4 tunnel (SIT) interface */
 	ECM_DB_IFACE_TYPE_TUNIPIP6,			/* IPIP6 Tunnel (TUNNEL6) interface */
 	ECM_DB_IFACE_TYPE_PPPOL2TPV2,			/* Interface is a PPPoL2TPV2 interface (a specific form of PPP that we recognise in the ECM) */
+	ECM_DB_IFACE_TYPE_PPTP,				/* Interface is a PPTP interface */
 	ECM_DB_IFACE_TYPE_COUNT,			/* Number of interface types */
 };
 typedef enum ecm_db_iface_types ecm_db_iface_type_t;
@@ -301,6 +302,15 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+struct ecm_db_interface_info_pptp {
+	uint32_t src_ip;
+	uint32_t dst_ip;
+	uint16_t src_call_id;
+	uint16_t dst_call_id;
+};
+#endif
+
 struct ecm_db_interface_info_unknown {			/* type == ECM_DB_IFACE_TYPE_UNKNOWN */
 	uint32_t os_specific_ident;			/* Operating system specific identifier (known only by front end) */
 };
diff --git a/ecm_interface.c b/ecm_interface.c
index bb4bd2e..ca84ebf 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -74,6 +74,9 @@
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 #include <linux/if_pppol2tp.h>
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+#include <linux/netfilter/nf_conntrack_proto_gre.h>
+#endif
 #endif
 
 /*
@@ -785,15 +788,14 @@
 #endif
 
 #ifdef ECM_INTERFACE_PPP_ENABLE
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
 /*
- * ecm_interface_skip_l2tpv3_pptp()
+ * ecm_interface_skip_pptp()
  *	skip pptp tunnel encapsulated traffic
  *
- * ECM does not handle  PPTP and l2tpv3,
+ * ECM does not handle PPTP,
  * this function detects packets of that type so they can be skipped over to improve their throughput.
  */
-bool ecm_interface_skip_l2tpv3_pptp(struct sk_buff *skb, const struct net_device *out)
+bool ecm_interface_skip_pptp(struct sk_buff *skb, const struct net_device *out)
 {
 	struct ppp_channel *ppp_chan[1];
 	int px_proto;
@@ -814,25 +816,6 @@
 			return true;
 		}
 
-		/*
-		 * Check for L2TPv3 packets
-		 */
-		if (px_proto == PX_PROTO_OL2TP) {
-			struct pppol2tp_common_addr info;
-			if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
-				ppp_release_channels(ppp_chan, 1);
-				return true;
-			}
-
-			if (info.tunnel_version == 2) {
-				ppp_release_channels(ppp_chan, 1);
-				return false;
-			}
-			if (info.tunnel_version == 3) {
-				ppp_release_channels(ppp_chan, 1);
-				return true;
-			}
-		}
 		ppp_release_channels(ppp_chan, 1);
 	}
 
@@ -858,6 +841,64 @@
 			return true;
 		}
 
+		ppp_release_channels(ppp_chan, 1);
+	}
+
+	dev_put(in);
+	return false;
+}
+
+/*
+ * ecm_interface_skip_l2tp_packet_by_version()
+ *	Check version of l2tp tunnel encapsulated traffic
+ *
+ * ECM does not handle l2tp,
+ * this function detects packets of that type so they can be skipped over to improve their throughput.
+ */
+bool ecm_interface_skip_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver)
+{
+	struct ppp_channel *ppp_chan[1];
+	int px_proto;
+	struct net_device *in;
+
+	if (out->type == ARPHRD_PPP) {
+		if (ppp_hold_channels((struct net_device *)out, ppp_chan, 1) != 1) {
+			return true;
+		}
+
+		px_proto = ppp_channel_get_protocol(ppp_chan[0]);
+
+		/*
+		 * Check for L2TPv3 packets
+		 */
+		if (px_proto == PX_PROTO_OL2TP) {
+			struct pppol2tp_common_addr info;
+			if (pppol2tp_channel_addressing_get(ppp_chan[0], &info)) {
+				ppp_release_channels(ppp_chan, 1);
+				return true;
+			}
+
+			if (info.tunnel_version == ver) {
+				ppp_release_channels(ppp_chan, 1);
+				return true;
+			}
+		}
+		ppp_release_channels(ppp_chan, 1);
+	}
+
+	in = dev_get_by_index(&init_net, skb->skb_iif);
+	if (!in) {
+		return true;
+	}
+
+	if (in->type == ARPHRD_PPP) {
+		if (__ppp_hold_channels((struct net_device *)in, ppp_chan, 1) != 1) {
+			dev_put(in);
+			return true;
+		}
+
+		px_proto = ppp_channel_get_protocol(ppp_chan[0]);
+
 		/*
 		 * Check for L2TPv3 pkts
 		 */
@@ -868,12 +909,8 @@
 				dev_put(in);
 				return true;
 			}
-			if (info.tunnel_version == 2) {
-				ppp_release_channels(ppp_chan, 1);
-				dev_put(in);
-				return false;
-			}
-			if (info.tunnel_version == 3) {
+
+			if (info.tunnel_version == ver) {
 				ppp_release_channels(ppp_chan, 1);
 				dev_put(in);
 				return true;
@@ -885,7 +922,6 @@
 	dev_put(in);
 	return false;
 }
-#endif
 
 /*
  * ecm_interface_skip_l2tp_pptp()
@@ -1240,6 +1276,59 @@
 
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+/*
+ * ecm_interface_pptp_interface_establish()
+ *	Returns a reference to a iface of the PPTP type, possibly creating one if necessary.
+ *	Returns NULL on failure or a reference to interface.
+ */
+static struct ecm_db_iface_instance *ecm_interface_pptp_interface_establish(struct ecm_db_interface_info_pptp *type_info,
+							char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
+{
+	struct ecm_db_iface_instance *nii;
+	struct ecm_db_iface_instance *ii;
+
+	DEBUG_INFO("Establish PPTP iface: %s with local call id %u peer call id %u\n", dev_name, type_info->src_call_id,
+				type_info->dst_call_id);
+	/*
+	 * Locate the iface
+	 */
+	ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
+	if (ii) {
+		DEBUG_TRACE("%p: iface established\n", ii);
+		ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+		return ii;
+	}
+
+	/*
+	 * No iface - create one
+	 */
+	nii = ecm_db_iface_alloc();
+	if (!nii) {
+		DEBUG_WARN("Failed to establish iface\n");
+		return NULL;
+	}
+
+	/*
+	 * Add iface into the database, atomically to avoid races creating the same thing
+	 */
+	spin_lock_bh(&ecm_interface_lock);
+	ii = ecm_db_iface_find_and_ref_pptp(type_info->src_call_id, type_info->dst_call_id);
+	if (ii) {
+		spin_unlock_bh(&ecm_interface_lock);
+		ecm_db_iface_deref(nii);
+		ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+		return ii;
+	}
+
+	ecm_db_iface_add_pptp(nii, type_info, dev_name, mtu, dev_interface_num, ae_interface_num, NULL, nii);
+	spin_unlock_bh(&ecm_interface_lock);
+
+	DEBUG_TRACE("%p: pptp iface established\n", nii);
+	return nii;
+}
+#endif
+
 /*
  * ecm_interface_unknown_interface_establish()
  *	Returns a reference to a iface of the UNKNOWN type, possibly creating one if necessary.
@@ -1530,6 +1619,9 @@
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 		struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2;		/* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+		struct ecm_db_interface_info_pptp pptp;			/* type == ECM_DB_IFACE_TYPE_PPTP */
+#endif
 		struct ecm_db_interface_info_unknown unknown;		/* type == ECM_DB_IFACE_TYPE_UNKNOWN */
 		struct ecm_db_interface_info_loopback loopback;		/* type == ECM_DB_IFACE_TYPE_LOOPBACK */
 #ifdef ECM_INTERFACE_IPSEC_ENABLE
@@ -1552,8 +1644,16 @@
 #ifdef ECM_INTERFACE_PPPOE_ENABLE
 	struct pppoe_opt addressing;
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+	int protocol = IPPROTO_IP;
+	struct pptp_opt opt;
+	struct iphdr *v4_hdr = NULL;
+	if (skb) {
+		v4_hdr = ip_hdr(skb);
+		protocol = v4_hdr->protocol;
+	}
 #endif
-
+#endif
 	/*
 	 * Get basic information about the given device
 	 */
@@ -1852,6 +1952,53 @@
 	}
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+	if ((protocol == IPPROTO_GRE) && skb && v4_hdr) {
+		struct gre_hdr_pptp *gre_hdr;
+		uint16_t proto;
+		int ret;
+
+		skb_pull(skb, sizeof(struct iphdr));
+		gre_hdr = (struct gre_hdr_pptp *)(skb->data);
+		proto = ntohs(gre_hdr->protocol);
+		if ((gre_hdr->version == GRE_VERSION_PPTP) && (proto == GRE_PROTOCOL_PPTP)) {
+			ret = pptp_session_find(&opt, gre_hdr->call_id, v4_hdr->daddr);
+			if (ret < 0) {
+				skb_push(skb, sizeof(struct iphdr));
+				DEBUG_WARN("PPTP session info not found\n");
+				return NULL;
+			}
+
+			/*
+			 * Get PPTP session info
+			 */
+			type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
+			type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
+			type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
+			type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
+
+			skb_push(skb, sizeof(struct iphdr));
+
+			/*
+			 * Establish this type of interface
+			 */
+			ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+			return ii;
+		}
+
+		skb_push(skb, sizeof(struct iphdr));
+
+		DEBUG_TRACE("Unknown GRE protocol \n");
+		type_info.unknown.os_specific_ident = dev_interface_num;
+
+		/*
+		 * Establish this type of interface
+		 */
+		ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+		return ii;
+	}
+#endif
+
 	/*
 	 * PPP - but what is the channel type?
 	 * First: If this is multi-link then we do not support it
@@ -1955,6 +2102,29 @@
 		return ii;
 	}
 #endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+	if (channel_protocol == PX_PROTO_PPTP) {
+		pptp_channel_addressing_get(&opt, ppp_chan[0]);
+
+		/*
+		 * Get PPTP session info
+		 */
+		type_info.pptp.src_call_id = ntohs(opt.src_addr.call_id);
+		type_info.pptp.dst_call_id = ntohs(opt.dst_addr.call_id);
+		type_info.pptp.src_ip = ntohl(opt.src_addr.sin_addr.s_addr);
+		type_info.pptp.dst_ip = ntohl(opt.dst_addr.sin_addr.s_addr);
+
+		DEBUG_TRACE("Net device: %p PPTP source call id: %d,n", dev, type_info.pptp.src_call_id);
+		ppp_release_channels(ppp_chan, 1);
+
+		/*
+		 * Establish this type of interface
+		 */
+		ii = ecm_interface_pptp_interface_establish(&type_info.pptp, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+		return ii;
+	}
+#endif
 	DEBUG_TRACE("Net device: %p PPP channel protocol: %d - Unknown to the ECM\n", dev, channel_protocol);
 	type_info.unknown.os_specific_ident = dev_interface_num;
 
@@ -1968,7 +2138,6 @@
 	 */
 	ii = ecm_interface_unknown_interface_establish(&type_info.unknown, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
 	return ii;
-
 #endif
 }
 EXPORT_SYMBOL(ecm_interface_establish_and_ref);
@@ -2381,7 +2550,8 @@
 	if (in_dev && !mfc_update) {
 		if (ecm_front_end_is_bridge_port(in_dev)) {
 			src_dev_is_bridge = true;
-			br_dev_src = in_dev->master;
+			br_dev_src = ecm_interface_get_and_hold_dev_master(in_dev);
+			DEBUG_ASSERT(br_dev_src, "Expected a master\n");
 
 			/*
 	 		 * The source net_dev found as bridge slave. In case of routed interface
@@ -2431,8 +2601,9 @@
 				 */
 				return 0;
 			}
+
 			dest_dev = br_dev_src;
-			dev_hold(dest_dev);
+
 		}
 
 		dest_dev_type = dest_dev->type;
@@ -2815,6 +2986,20 @@
 	}
 #endif
 
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+	/*
+	 * if the address is a local address and indev=PPTP.
+	 */
+	if (protocol == IPPROTO_GRE && given_dest_dev && given_dest_dev->type == ARPHRD_PPP) {
+		dev_put(dest_dev);
+		dest_dev = given_dest_dev;
+		if (dest_dev) {
+			dev_hold(dest_dev);
+			DEBUG_TRACE("PPTP packet tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
+		}
+	}
+#endif
+
 	if (!dest_dev) {
 		DEBUG_WARN("dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(dest_addr));
 		return ECM_DB_IFACE_HEIRARCHY_MAX;
@@ -2934,7 +3119,6 @@
 	while (current_interface_index > 0) {
 		struct ecm_db_iface_instance *ii;
 		struct net_device *next_dev;
-
 		/*
 		 * Get the ecm db interface instance for the device at hand
 		 */
@@ -3258,6 +3442,13 @@
 				}
 			}
 #endif
+
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+			if (protocol == IPPROTO_GRE && dest_dev && dest_dev->type == ARPHRD_PPP) {
+				DEBUG_TRACE("Net device: %p PPP channel is PPTP\n", dest_dev);
+				break;
+			}
+#endif
 			/*
 			 * PPP - but what is the channel type?
 			 * First: If this is multi-link then we do not support it
@@ -3834,10 +4025,10 @@
 	node = ecm_db_node_find_and_ref(mac);
 
 	if(unlikely(!node)) {
-		DEBUG_WARN("node address is null \n");
+		DEBUG_WARN("node address is null\n");
 		return NOTIFY_DONE;
 	}
-
+	DEBUG_INFO("FDB updated for node %pM\n", mac);
 	ecm_db_traverse_node_from_connection_list_and_decelerate(node);
 	ecm_db_traverse_node_to_connection_list_and_decelerate(node);
 	ecm_db_traverse_node_from_nat_connection_list_and_decelerate(node);
diff --git a/ecm_interface.h b/ecm_interface.h
index 78b05ed..adc903d 100644
--- a/ecm_interface.h
+++ b/ecm_interface.h
@@ -51,7 +51,8 @@
 #ifdef ECM_IPV6_ENABLE
 struct neighbour *ecm_interface_ipv6_neigh_get(ip_addr_t addr);
 #endif
-bool ecm_interface_skip_l2tpv3_pptp(struct sk_buff *skb, const struct net_device *out);
+bool ecm_interface_skip_pptp(struct sk_buff *skb, const struct net_device *out);
+bool ecm_interface_skip_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver);
 bool ecm_interface_skip_l2tp_pptp(struct sk_buff *skb, const struct net_device *out);
 struct ecm_db_iface_instance *ecm_interface_establish_and_ref(struct ecm_front_end_connection_instance *feci, struct net_device *dev, struct sk_buff *skb);
 
diff --git a/frontends/nss/ecm_nss_ipv4.c b/frontends/nss/ecm_nss_ipv4.c
index 815e1ca..9f9037f 100644
--- a/frontends/nss/ecm_nss_ipv4.c
+++ b/frontends/nss/ecm_nss_ipv4.c
@@ -188,7 +188,7 @@
 	int i;
 	bool done;
 	uint8_t node_addr[ETH_ALEN];
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) || defined(ECM_INTERFACE_PPTP_ENABLE)
 	ip_addr_t local_ip, remote_ip;
 #endif
 
@@ -222,6 +222,9 @@
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 		struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2_info;
 #endif
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+		struct ecm_db_interface_info_pptp pptp_info;
+#endif
 		type = ecm_db_connection_iface_type_get(interface_list[i]);
 		DEBUG_INFO("Lookup node address, interface @ %d is type: %d\n", i, type);
 
@@ -271,6 +274,30 @@
 			return NULL;
 #endif
 
+		case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+			ecm_db_iface_pptp_session_info_get(interface_list[i], &pptp_info);
+			ECM_HIN4_ADDR_TO_IP_ADDR(local_ip, pptp_info.src_ip);
+			ECM_HIN4_ADDR_TO_IP_ADDR(remote_ip, pptp_info.dst_ip);
+			if (ECM_IP_ADDR_MATCH(local_ip, addr)) {
+				if (unlikely(!ecm_interface_mac_addr_get(local_ip, node_addr, &on_link, gw_addr))) {
+					DEBUG_TRACE("failed to obtain node address for " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(local_ip));
+					return NULL;
+				}
+
+			} else {
+				if (unlikely(!ecm_interface_mac_addr_get(remote_ip, node_addr, &on_link, gw_addr))) {
+					DEBUG_TRACE("failed to obtain node address for host " ECM_IP_ADDR_DOT_FMT "\n", ECM_IP_ADDR_TO_DOT(remote_ip));
+					return NULL;
+				}
+			}
+
+			done = true;
+			break;
+#else
+			DEBUG_TRACE("PPTP interface unsupported\n");
+			return NULL;
+#endif
 		case ECM_DB_IFACE_TYPE_VLAN:
 #ifdef ECM_INTERFACE_VLAN_ENABLE
 			/*
@@ -848,7 +875,6 @@
 	}
 	DEBUG_INFO("%p: reclassify success\n", ci);
 
-
 ecm_ipv4_regen_done:
 
 	/*
@@ -1318,6 +1344,11 @@
 
 	DEBUG_TRACE("%p: Routing: %s\n", out, out->name);
 
+	if (ecm_front_end_acceleration_rejected(skb)) {
+		DEBUG_TRACE("Acceleration rejected\n");
+		return NF_ACCEPT;
+	}
+
 	/*
 	 * If operations have stopped then do not process packets
 	 */
@@ -1345,18 +1376,27 @@
 #endif
 
 #ifdef ECM_INTERFACE_PPP_ENABLE
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#ifndef ECM_INTERFACE_PPTP_ENABLE
 	/*
-	 * skip l2tpv3/pptp because we don't accelerate them
+	 * skip pptp because we don't accelerate them
 	 */
-	if (ecm_interface_skip_l2tpv3_pptp(skb, out)) {
+	if (ecm_interface_skip_pptp(skb, out)) {
+		return NF_ACCEPT;
+	}
+#endif
+#ifndef ECM_INTERFACE_L2TPV2_ENABLE
+	/*
+	 * skip l2tp v2 and v3, because we don't accelerate them
+	 */
+	if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 2) ||
+		ecm_interface_l2tp_version_check(skb, out, 3)) {
 		return NF_ACCEPT;
 	}
 #else
 	/*
-	 * skip l2tp/pptp because we don't accelerate them
+	 * skip l2tpv3 because we don't accelerate them
 	 */
-	if (ecm_interface_skip_l2tp_pptp(skb, out)) {
+	if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 3)) {
 		return NF_ACCEPT;
 	}
 #endif
diff --git a/frontends/nss/ecm_nss_ipv6.c b/frontends/nss/ecm_nss_ipv6.c
index f544dd3..745609a 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -1031,6 +1031,11 @@
 
 	DEBUG_TRACE("%p: Routing: %s\n", out, out->name);
 
+	if (ecm_front_end_acceleration_rejected(skb)) {
+		DEBUG_TRACE("Acceleration rejected.\n");
+		return NF_ACCEPT;
+	}
+
 	/*
 	 * If operations have stopped then do not process packets
 	 */
@@ -1060,9 +1065,17 @@
 #ifdef ECM_INTERFACE_PPP_ENABLE
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 	/*
-	 * skip l2tpv3/pptp because we don't accelerate them
+	 * skip l2tpv3 because we don't accelerate them
 	 */
-	if (ecm_interface_skip_l2tpv3_pptp(skb, out)) {
+	if (ecm_interface_skip_l2tp_packet_by_version(skb, out, 3)) {
+		return NF_ACCEPT;
+	}
+
+	/*
+	 * Skip PPTP beacuse we don't support acceleration for
+	 * IPv6 inner header over PPTP
+	 */
+	if (ecm_interface_skip_pptp(skb, out)) {
 		return NF_ACCEPT;
 	}
 #else
diff --git a/frontends/nss/ecm_nss_multicast_ipv4.c b/frontends/nss/ecm_nss_multicast_ipv4.c
index 1b87bb1..20ab413 100644
--- a/frontends/nss/ecm_nss_multicast_ipv4.c
+++ b/frontends/nss/ecm_nss_multicast_ipv4.c
@@ -2166,6 +2166,7 @@
 	int dest_port;
 	int src_port_nat = 0;
 	struct net_device *in_dev_nat = NULL;
+	struct net_device *out_dev_master = NULL;
 	struct ecm_db_multicast_tuple_instance *tuple_instance;
 	struct ecm_db_connection_instance *ci;
 	ip_addr_t match_addr;
@@ -2268,14 +2269,18 @@
 			is_routed = true;
 			br_dev_found_in_mfc = ecm_interface_multicast_check_for_br_dev(dst_dev, if_cnt);
 		} else {
+			out_dev_master =  ecm_interface_get_and_hold_dev_master(out_dev);
+			DEBUG_ASSERT(out_dev_master, "Expected a master\n");
+
+
 			/*
 			 * Packet flow is pure bridge. Try to query the snooper for the destination
 			 * interface list
 			 */
-			if_cnt = mc_bridge_ipv4_get_if(out_dev->master, ip_src, ip_grp, ECM_DB_MULTICAST_IF_MAX, dst_dev);
+			if_cnt = mc_bridge_ipv4_get_if(out_dev_master, ip_src, ip_grp, ECM_DB_MULTICAST_IF_MAX, dst_dev);
 			if (if_cnt <= 0) {
 				DEBUG_WARN("Not found a valid MCS if count %d\n", if_cnt);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			/*
@@ -2287,7 +2292,7 @@
 			if_cnt = ecm_interface_multicast_check_for_src_ifindex(dst_dev, if_cnt, in_dev->ifindex);
 			if (if_cnt <= 0) {
 				DEBUG_WARN("Not found a valid MCS if count %d\n", if_cnt);
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 	}
@@ -2298,7 +2303,7 @@
 	if (!is_routed) {
 		if (iph->ttl < 2) {
 			DEBUG_TRACE("%p: Ignoring, Multicast IPv4 Header has TTL one\n", skb);
-			return NF_ACCEPT;
+			goto done;
 		}
 	}
 
@@ -2315,7 +2320,7 @@
 		 */
 		in_dev_nat = ecm_interface_dev_find_by_addr(ip_src_addr_nat, &from_local_addr);
 		if (!in_dev_nat) {
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2335,7 +2340,7 @@
 		 * list for a NAT flow, which should not happen.
 		 */
 		if (!nat_if_found) {
-			return NF_ACCEPT;
+			goto done;
 		}
 	}
 
@@ -2385,7 +2390,7 @@
 			/*
 			 * As we are terminating we just allow the packet to pass - it's no longer our concern
 			 */
-			return NF_ACCEPT;
+			goto done;
 		}
 		spin_unlock_bh(&ecm_nss_ipv4_lock);
 
@@ -2395,7 +2400,7 @@
 		nci = ecm_db_connection_alloc();
 		if (!nci) {
 			DEBUG_WARN("Failed to allocate connection\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2405,7 +2410,7 @@
 		if (!feci) {
 			ecm_db_connection_deref(nci);
 			DEBUG_WARN("Failed to allocate front end\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2415,7 +2420,7 @@
 		if (!tuple_instance) {
 			ecm_db_connection_deref(nci);
 			DEBUG_WARN("Failed to allocate tuple instance\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2434,7 +2439,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			DEBUG_WARN("Failed to obtain 'from' heirarchy list\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		ecm_db_connection_from_interfaces_reset(nci, from_list, from_list_first);
 
@@ -2446,7 +2451,7 @@
 			feci->deref(feci);
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2457,7 +2462,7 @@
 			feci->deref(feci);
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
@@ -2468,7 +2473,7 @@
 			feci->deref(feci);
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
@@ -2481,7 +2486,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			kfree(to_list);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2494,7 +2499,7 @@
 		}
 
 		interface_idx_cnt = ecm_nss_multicast_connection_to_interface_heirarchy_construct(feci, to_list, ip_src_addr, ip_dest_addr, in_dev,
-												  out_dev->master, if_cnt, dst_dev, to_list_first,
+												  out_dev_master, if_cnt, dst_dev, to_list_first,
 												  src_node_addr, is_routed, layer4hdr, skb);
 		if (interface_idx_cnt == 0) {
 			ecm_db_node_deref(src_ni);
@@ -2505,7 +2510,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("%p: Failed to obtain mutlicast 'to' heirarchy list\n", nci);
-			return NF_ACCEPT;
+			goto done;
 		}
 		ret = ecm_db_multicast_connection_to_interfaces_reset(nci, to_list, to_list_first);
 		if (ret < 0) {
@@ -2524,7 +2529,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("%p: Failed to obtain mutlicast 'to' heirarchy list\n", nci);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create destination node\n", nci);
@@ -2550,7 +2555,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to establish destination node\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2572,7 +2577,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to establish dst mapping\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create the 'from NAT' interface heirarchy list\n", nci);
@@ -2595,7 +2600,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to obtain 'from NAT' heirarchy list\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		ecm_db_connection_from_nat_interfaces_reset(nci, from_nat_list, from_nat_list_first);
 
@@ -2619,7 +2624,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to obtain 'from NAT' node\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create from NAT mapping\n", nci);
@@ -2644,7 +2649,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to establish from nat mapping\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2671,7 +2676,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to allocate default classifier\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		ecm_db_connection_classifier_assign(nci, (struct ecm_classifier_instance *)dci);
 
@@ -2704,7 +2709,7 @@
 				kfree(to_list);
 				kfree(to_list_first);
 				DEBUG_WARN("Failed to allocate classifiers assignments\n");
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 
@@ -2799,14 +2804,14 @@
 			to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
 			if (!to_list) {
 				ecm_db_connection_deref(ci);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
 			if (!to_list_first) {
 				ecm_db_connection_deref(ci);
 				kfree(to_list);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			/*
@@ -2819,7 +2824,7 @@
 
 			feci = ecm_db_connection_front_end_get_and_ref(ci);
 			interface_idx_cnt = ecm_nss_multicast_connection_to_interface_heirarchy_construct(feci, to_list, ip_src_addr, ip_dest_addr, in_dev,
-													  out_dev->master, if_cnt, dst_dev, to_list_first,
+													  out_dev_master, if_cnt, dst_dev, to_list_first,
 													  src_node_addr, is_routed, (__be16 *)&udp_hdr, skb);
 			feci->deref(feci);
 			if (interface_idx_cnt == 0) {
@@ -2827,7 +2832,7 @@
 				ecm_db_connection_deref(ci);
 				kfree(to_list);
 				kfree(to_list_first);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			ret = ecm_db_multicast_connection_to_interfaces_reset(ci, to_list, to_list_first);
@@ -2850,7 +2855,7 @@
 			 */
 			if (ret < 0) {
 				ecm_db_connection_deref(ci);
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 	}
@@ -2860,7 +2865,7 @@
 	 */
 	if (!ecm_db_connection_defunct_timer_touch(ci)) {
 		ecm_db_connection_deref(ci);
-		return NF_ACCEPT;
+		goto done;
 	}
 
 	/*
@@ -3013,7 +3018,7 @@
 		DEBUG_TRACE("%p: drop: %p\n", ci, skb);
 		ecm_db_connection_data_totals_update_dropped(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
 		ecm_db_connection_deref(ci);
-		return NF_ACCEPT;
+		goto done;
 	}
 	ecm_db_multicast_connection_data_totals_update(ci, false, skb->len, 1);
 
@@ -3025,11 +3030,13 @@
 		feci = ecm_db_connection_front_end_get_and_ref(ci);
 		ecm_nss_multicast_ipv4_connection_accelerate(feci, &prevalent_pr);
 		feci->deref(feci);
-	} else {
-		goto done;
 	}
-done:
 	ecm_db_connection_deref(ci);
+
+done:
+	if (out_dev_master) {
+		dev_put(out_dev_master);
+	}
 	return NF_ACCEPT;
 }
 
diff --git a/frontends/nss/ecm_nss_multicast_ipv6.c b/frontends/nss/ecm_nss_multicast_ipv6.c
index a40d0a1..42ddefd 100644
--- a/frontends/nss/ecm_nss_multicast_ipv6.c
+++ b/frontends/nss/ecm_nss_multicast_ipv6.c
@@ -2125,6 +2125,7 @@
 	bool br_dev_found_in_mfc = false;
 	int protocol = (int)orig_tuple->dst.protonum;
 	__be16 *layer4hdr = NULL;
+	struct net_device *out_dev_master = NULL;
 
 	if (protocol != IPPROTO_UDP) {
 		DEBUG_WARN("Invalid Protocol %d in skb %p\n", protocol, skb);
@@ -2207,15 +2208,17 @@
 			is_routed = true;
 			br_dev_found_in_mfc = ecm_interface_multicast_check_for_br_dev(mc_dest_if, mc_if_cnt);
 		} else {
+			out_dev_master =  ecm_interface_get_and_hold_dev_master(out_dev);
+			DEBUG_ASSERT(out_dev_master, "Expected a master\n");
 
 			/*
 			 * Packet flow is pure bridge. Try to query the snooper for the destination
 			 * interface list
 			 */
-			mc_if_cnt = mc_bridge_ipv6_get_if(out_dev->master, &origin6, &group6, ECM_DB_MULTICAST_IF_MAX, mc_dest_if);
+			mc_if_cnt = mc_bridge_ipv6_get_if(out_dev_master, &origin6, &group6, ECM_DB_MULTICAST_IF_MAX, mc_dest_if);
 			if (mc_if_cnt <= 0) {
 				DEBUG_WARN("Not found a valid MCS if count %d\n", mc_if_cnt);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			/*
@@ -2227,7 +2230,7 @@
 			mc_if_cnt = ecm_interface_multicast_check_for_src_ifindex(mc_dest_if, mc_if_cnt, in_dev->ifindex);
 			if (mc_if_cnt <= 0) {
 				DEBUG_WARN("Not found a valid MCS if count %d\n", mc_if_cnt);
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 	}
@@ -2238,7 +2241,7 @@
 	if (!is_routed) {
 		if (iph->ttl < 2) {
 			DEBUG_TRACE("%p: Ignoring, Multicast IPv6 Header has Hop Limit one\n", skb);
-			return NF_ACCEPT;
+			goto done;
 		}
 	}
 
@@ -2288,7 +2291,7 @@
 			/*
 			 * As we are terminating we just allow the packet to pass - it's no longer our concern
 			 */
-			return NF_ACCEPT;
+			goto done;
 		}
 		spin_unlock_bh(&ecm_nss_ipv6_lock);
 
@@ -2298,7 +2301,7 @@
 		nci = ecm_db_connection_alloc();
 		if (!nci) {
 			DEBUG_WARN("Failed to allocate connection\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2308,7 +2311,7 @@
 		if (!feci) {
 			ecm_db_connection_deref(nci);
 			DEBUG_WARN("Failed to allocate front end\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2318,7 +2321,7 @@
 		if (!tuple_instance) {
 			ecm_db_connection_deref(nci);
 			DEBUG_WARN("Failed to allocate tuple instance\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		/*
 		 * Create Destination MAC address using IP multicast destination address
@@ -2338,7 +2341,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			DEBUG_WARN("Failed to obtain 'from' heirarchy list\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		ecm_db_connection_from_interfaces_reset(nci, from_list, from_list_first);
 
@@ -2350,7 +2353,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			DEBUG_WARN("Failed to establish source node\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create source mapping\n", nci);
@@ -2361,7 +2364,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			DEBUG_WARN("Failed to establish src mapping\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create the 'to' interface heirarchy list\n", nci);
@@ -2373,7 +2376,7 @@
 			feci->deref(feci);
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
@@ -2385,7 +2388,7 @@
 			ecm_db_connection_deref(nci);
 			ecm_db_multicast_tuple_instance_deref(tuple_instance);
 			kfree(to_list);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2397,7 +2400,7 @@
 			*to_first = ECM_DB_IFACE_HEIRARCHY_MAX;
 		}
 
-		interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev->master, ip_src_addr,
+		interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev_master, ip_src_addr,
 										      ip_dest_addr, mc_if_cnt, mc_dest_if, to_list_first, src_node_addr,  is_routed, skb);
 		if (interface_idx_cnt == 0) {
 			DEBUG_WARN("Failed to obtain 'to' heirarchy list\n");
@@ -2407,7 +2410,7 @@
 			ecm_db_connection_deref(nci);
 			kfree(to_list);
 			kfree(to_list_first);
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		ret = ecm_db_multicast_connection_to_interfaces_reset(nci, to_list, to_list_first);
@@ -2427,7 +2430,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to obtain 'to' heirarchy list\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2458,7 +2461,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to establish dest node\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		DEBUG_TRACE("%p: Create dest mapping\n", nci);
@@ -2479,7 +2482,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to establish dest mapping\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 
 		/*
@@ -2503,7 +2506,7 @@
 			kfree(to_list);
 			kfree(to_list_first);
 			DEBUG_WARN("Failed to allocate default classifier\n");
-			return NF_ACCEPT;
+			goto done;
 		}
 		ecm_db_connection_classifier_assign(nci, (struct ecm_classifier_instance *)dci);
 
@@ -2533,7 +2536,7 @@
 				kfree(to_list);
 				kfree(to_list_first);
 				DEBUG_WARN("Failed to allocate classifiers assignments\n");
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 
@@ -2634,14 +2637,14 @@
 			to_list = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
 			if (!to_list) {
 				ecm_db_connection_deref(ci);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			to_list_first = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
 			if (!to_list_first) {
 				ecm_db_connection_deref(ci);
 				kfree(to_list);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; i++) {
@@ -2650,7 +2653,7 @@
 			}
 
 			feci = ecm_db_connection_front_end_get_and_ref(ci);
-			interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev->master,\
+			interface_idx_cnt = ecm_nss_multicast_ipv6_interface_heirarchy_construct(feci, to_list, in_dev, out_dev_master,\
 												   ip_src_addr, ip_dest_addr, mc_if_cnt,\
 												   mc_dest_if, to_list_first, src_node_addr,
 												   is_routed, skb);
@@ -2660,7 +2663,7 @@
 				ecm_db_connection_deref(ci);
 				kfree(to_list);
 				kfree(to_list_first);
-				return NF_ACCEPT;
+				goto done;
 			}
 
 			ret = ecm_db_multicast_connection_to_interfaces_reset(ci, to_list, to_list_first);
@@ -2684,7 +2687,7 @@
 			 */
 			if (ret < 0) {
 				ecm_db_connection_deref(ci);
-				return NF_ACCEPT;
+				goto done;
 			}
 		}
 	}
@@ -2694,7 +2697,7 @@
 	 */
 	if (!ecm_db_connection_defunct_timer_touch(ci)) {
 		ecm_db_connection_deref(ci);
-		return NF_ACCEPT;
+		goto done;
 	}
 
 	/*
@@ -2847,7 +2850,7 @@
 		DEBUG_TRACE("%p: drop: %p\n", ci, skb);
 		ecm_db_connection_data_totals_update_dropped(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
 		ecm_db_connection_deref(ci);
-		return NF_ACCEPT;
+		goto done;
 	}
 	ecm_db_connection_data_totals_update(ci, (sender == ECM_TRACKER_SENDER_TYPE_SRC)? true : false, skb->len, 1);
 
@@ -2867,11 +2870,13 @@
 		feci = ecm_db_connection_front_end_get_and_ref(ci);
 		ecm_nss_multicast_ipv6_connection_accelerate(feci, &prevalent_pr);
 		feci->deref(feci);
-	} else {
-		goto done;
 	}
-done:
 	ecm_db_connection_deref(ci);
+
+done:
+	if (out_dev_master) {
+		dev_put(out_dev_master);
+	}
 	return NF_ACCEPT;
 }
 
diff --git a/frontends/nss/ecm_nss_non_ported_ipv4.c b/frontends/nss/ecm_nss_non_ported_ipv4.c
index cdeb75d..59ce422 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_non_ported_ipv4.c
@@ -387,7 +387,10 @@
 	uint8_t from_nss_iface_address[ETH_ALEN];
 	uint8_t to_nss_iface_address[ETH_ALEN];
 	ip_addr_t addr;
-	struct nss_ipv4_msg nim;
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) ||  defined(ECM_INTERFACE_PPTP_ENABLE)
+	struct net_device *dev __attribute__((unused));
+#endif
+	struct nss_ipv4_msg *nim;
 	struct nss_ipv4_rule_create_msg *nircm;
 	struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
 	int aci_index;
@@ -413,7 +416,7 @@
 	 * For non-ported protocols we only support IPv6 in 4 or ESP
 	 */
 	protocol = ecm_db_connection_protocol_get(feci->ci);
-	if ((protocol != IPPROTO_IPV6) && (protocol != IPPROTO_ESP)) {
+	if ((protocol != IPPROTO_IPV6) && (protocol != IPPROTO_ESP) && (protocol != IPPROTO_GRE)) {
 		spin_lock_bh(&feci->lock);
 		feci->accel_mode = ECM_FRONT_END_ACCELERATION_MODE_FAIL_RULE;
 		spin_unlock_bh(&feci->lock);
@@ -429,19 +432,24 @@
 		return;
 	}
 
+	nim = (struct nss_ipv4_msg *)kzalloc(sizeof(struct nss_ipv4_msg), GFP_ATOMIC | __GFP_NOWARN);
+	if (!nim) {
+		DEBUG_WARN("%p: no memory for nss ipv4 message structure instance: %p\n", feci, feci->ci);
+		return;
+	}
+
 	/*
 	 * Okay construct an accel command.
 	 * Initialise creation structure.
 	 * NOTE: We leverage the app_data void pointer to be our 32 bit connection serial number.
 	 * When we get it back we re-cast it to a uint32 and do a faster connection lookup.
 	 */
-	memset(&nim, 0, sizeof(struct nss_ipv4_msg));
-	nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
+	nss_ipv4_msg_init(nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
 			sizeof(struct nss_ipv4_rule_create_msg),
 			ecm_nss_non_ported_ipv4_connection_callback,
 			(void *)ecm_db_connection_serial_get(feci->ci));
 
-	nircm = &nim.msg.rule_create;
+	nircm = &nim->msg.rule_create;
 	nircm->valid_flags = 0;
 	nircm->rule_flags = 0;
 
@@ -654,6 +662,31 @@
 			DEBUG_TRACE("%p: IPSEC - unsupported\n", nnpci);
 #endif
 			break;
+		case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+			/*
+			 * pptp packets from lan to wan gets routed twice.
+			 *	1. eth1-->br-lan to pptp
+			 *	2. pptp ---> eth0.
+			 * we need to push nss rule for both. Requirement
+			 * mandidates multiple session per tunnel and all tunnel
+			 * packets has same 5 tuple info. So need to create a
+			 * special static pptp interface with nss to identify
+			 * packets from wan side. So pptp--->eth0 rule to be
+			 * pushed with this static interface.
+			 */
+			ecm_db_connection_from_address_get(feci->ci, addr);
+			dev = ecm_interface_dev_find_by_local_addr(addr);
+			if (likely(dev)) {
+				dev_put(dev);
+				from_nss_iface_id =  NSS_PPTP_INTERFACE;
+				nircm->conn_rule.flow_interface_num = from_nss_iface_id;
+			}
+#else
+			rule_invalid = true;
+			DEBUG_TRACE("%p: PPTP - unsupported\n", nnpci);
+#endif
+			break;
 		default:
 			DEBUG_TRACE("%p: Ignoring: %d (%s)\n", nnpci, ii_type, ii_name);
 		}
@@ -875,6 +908,20 @@
 	 * The flow_ip is where the connection established from
 	 */
 	ecm_db_connection_from_address_get(feci->ci, addr);
+
+	/*
+	 * Get MTU information
+	 */
+	nircm->conn_rule.flow_mtu = (uint32_t)ecm_db_connection_from_iface_mtu_get(feci->ci);
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+	if (unlikely(from_nss_iface_id ==  NSS_PPTP_INTERFACE)) {
+		dev = ecm_interface_dev_find_by_local_addr(addr);
+		if (likely(dev)) {
+			nircm->conn_rule.flow_mtu = dev->mtu;
+			dev_put(dev);
+		}
+	}
+#endif
 	ECM_IP_ADDR_TO_HIN4_ADDR(nircm->tuple.flow_ip, addr);
 
 	/*
@@ -951,7 +998,6 @@
 	/*
 	 * Get MTU information
 	 */
-	nircm->conn_rule.flow_mtu = (uint32_t)ecm_db_connection_from_iface_mtu_get(feci->ci);
 	nircm->conn_rule.return_mtu = (uint32_t)ecm_db_connection_to_iface_mtu_get(feci->ci);
 
 	/*
@@ -1048,6 +1094,7 @@
 	if (regen_occurrances != ecm_db_connection_regeneration_occurrances_get(feci->ci)) {
 		DEBUG_INFO("%p: connection:%p regen occurred - aborting accel rule.\n", feci, feci->ci);
 		ecm_nss_ipv4_accel_pending_clear(feci, ECM_FRONT_END_ACCELERATION_MODE_DECEL);
+		kfree(nim);
 		return;
 	}
 
@@ -1069,7 +1116,7 @@
 	/*
 	 * Call the rule create function
 	 */
-	nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, &nim);
+	nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, nim);
 	if (nss_tx_status == NSS_TX_SUCCESS) {
 		/*
 		 * Reset the driver_fail count - transmission was okay here.
@@ -1077,9 +1124,12 @@
 		spin_lock_bh(&feci->lock);
 		feci->stats.driver_fail = 0;
 		spin_unlock_bh(&feci->lock);
+		kfree(nim);
 		return;
 	}
 
+	kfree(nim);
+
 	/*
 	 * Release that ref!
 	 */
@@ -1109,6 +1159,7 @@
 non_ported_accel_bad_rule:
 	;
 
+	kfree(nim);
 	/*
 	 * Jump to here when rule data is bad and an offload command cannot be constructed
 	 */
@@ -1739,7 +1790,7 @@
 	 * Look up a connection.
 	 */
 	protocol = (int)orig_tuple->dst.protonum;
-	if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
+	if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP || (protocol == IPPROTO_GRE))) {
 		src_port = 0;
 		src_port_nat = 0;
 		dest_port = 0;
diff --git a/frontends/nss/ecm_nss_ported_ipv4.c b/frontends/nss/ecm_nss_ported_ipv4.c
index db9833a..f2fb9a2 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_ported_ipv4.c
@@ -330,10 +330,10 @@
 	uint8_t from_nss_iface_address[ETH_ALEN];
 	uint8_t to_nss_iface_address[ETH_ALEN];
 	ip_addr_t addr;
-#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+#if defined(ECM_INTERFACE_L2TPV2_ENABLE) || defined(ECM_INTERFACE_PPTP_ENABLE)
 	struct net_device *dev;
 #endif
-	struct nss_ipv4_msg nim;
+	struct nss_ipv4_msg *nim;
 	struct nss_ipv4_rule_create_msg *nircm;
 	struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
 	int aci_index;
@@ -363,19 +363,24 @@
 		return;
 	}
 
+	nim = (struct nss_ipv4_msg *)kzalloc(sizeof(struct nss_ipv4_msg), GFP_ATOMIC | __GFP_NOWARN);
+	if (!nim) {
+		DEBUG_WARN("%p: no memory for nss ipv4 message structure instance: %p\n", feci, feci->ci);
+		return;
+	}
+
 	/*
 	 * Okay construct an accel command.
 	 * Initialise creation structure.
 	 * NOTE: We leverage the app_data void pointer to be our 32 bit connection serial number.
 	 * When we get it back we re-cast it to a uint32 and do a faster connection lookup.
 	 */
-	memset(&nim, 0, sizeof(struct nss_ipv4_msg));
-	nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
+	nss_ipv4_msg_init(nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CREATE_RULE_MSG,
 			sizeof(struct nss_ipv4_rule_create_msg),
 			ecm_nss_ported_ipv4_connection_callback,
 			(void *)ecm_db_connection_serial_get(feci->ci));
 
-	nircm = &nim.msg.rule_create;
+	nircm = &nim->msg.rule_create;
 	nircm->valid_flags = 0;
 	nircm->rule_flags = 0;
 
@@ -793,6 +798,31 @@
 			DEBUG_TRACE("%p: IPSEC - unsupported\n", npci);
 #endif
 			break;
+		case ECM_DB_IFACE_TYPE_PPTP:
+#ifdef ECM_INTERFACE_PPTP_ENABLE
+			/*
+			 * pptp packets from lan to wan gets routed twice.
+			 *	1. eth1-->br-lan to pptp
+			 *	2. pptp ---> eth0.
+			 * we need to push nss rule for both. Requirement
+			 * mandidates multiple session per tunnel and all tunnel
+			 * packets has same 5 tuple info. So need to create a
+			 * special static pptp interface with nss to identify
+			 * packets from wan side. So pptp--->eth0 rule to be
+			 * pushed with this static interface.
+			 */
+			ecm_db_connection_to_address_get(feci->ci, addr);
+			dev = ecm_interface_dev_find_by_local_addr(addr);
+			if (likely(dev)) {
+				dev_put(dev);
+				from_nss_iface_id =  NSS_PPTP_INTERFACE;
+				nircm->conn_rule.flow_interface_num = from_nss_iface_id;
+			}
+#else
+			rule_invalid = true;
+			DEBUG_TRACE("%p: PPTP - unsupported\n", npci);
+#endif
+			break;
 		default:
 			DEBUG_TRACE("%p: Ignoring: %d (%s)\n", npci, ii_type, ii_name);
 		}
@@ -1110,6 +1140,7 @@
 	if (regen_occurrances != ecm_db_connection_regeneration_occurrances_get(feci->ci)) {
 		DEBUG_INFO("%p: connection:%p regen occurred - aborting accel rule.\n", feci, feci->ci);
 		ecm_nss_ipv4_accel_pending_clear(feci, ECM_FRONT_END_ACCELERATION_MODE_DECEL);
+		kfree(nim);
 		return;
 	}
 
@@ -1131,7 +1162,7 @@
 	/*
 	 * Call the rule create function
 	 */
-	nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, &nim);
+	nss_tx_status = nss_ipv4_tx(ecm_nss_ipv4_nss_ipv4_mgr, nim);
 	if (nss_tx_status == NSS_TX_SUCCESS) {
 		/*
 		 * Reset the driver_fail count - transmission was okay here.
@@ -1139,9 +1170,12 @@
 		spin_lock_bh(&feci->lock);
 		feci->stats.driver_fail = 0;
 		spin_unlock_bh(&feci->lock);
+		kfree(nim);
 		return;
 	}
 
+	kfree(nim);
+
 	/*
 	 * Release that ref!
 	 */
@@ -1171,6 +1205,8 @@
 ported_accel_bad_rule:
 	;
 
+	kfree(nim);
+
 	/*
 	 * Jump to here when rule data is bad and an offload command cannot be constructed
 	 */
@@ -1305,7 +1341,6 @@
 	nss_tx_status_t nss_tx_status;
 
 	DEBUG_CHECK_MAGIC(npci, ECM_NSS_PORTED_IPV4_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", npci);
-
 	/*
 	 * If decelerate is in error or already pending then ignore
 	 */
@@ -2318,6 +2353,36 @@
 	}
 
 	/*
+	 * In DMZ scenarios SNAT rule is getting applied on the packet after packet
+	 * passed through bridge post routing hook
+	 *
+	 * Example
+	 * Consider following scenario where both WLAN PC and eth1 are part of same bridge
+	 * 192.168.1.3(WLAN PC)<-->192.168.1.1(DUT br-lan)---> 192.168.1.4(Eth1 PC)
+	 * When a DNAT is applied it is observed that following NAT rules are appended in iptables
+	 *
+	 * -A nat_reflection_out -s 192.168.1.0/24 -d 192.168.1.4/32 -p tcp -m tcp --dport 3389 -m comment --comment "wan" -j SNAT
+	 * 		 --to-source 192.168.1.1
+	 * -A nat_reflection_out -s 192.168.1.0/24 -d 192.168.1.4/32 -p udp -m udp --dport 3389 -m comment --comment "wan" -j SNAT
+	 * 		 --to-source 192.168.1.1
+	 *
+	 * This Shows that SNAT is getting applied on bridged packet also. However it is observed that
+	 * the SNAT is updated in ct after the packet has crossed this function through bridge hook.
+	 *
+	 * Hence Flushing the connection that was already created earlier if the ip_src_addr_nat value changes for same tuple in
+	 * subsequent packets
+	 */
+	ecm_db_connection_from_address_nat_get(ci, match_addr);
+	if (!ECM_IP_ADDR_MATCH(ip_src_addr_nat, match_addr) && ct) {
+		/*
+		 * Force destruction of the connection my making it defunct
+		 */
+		ecm_db_connection_make_defunct(ci);
+		ecm_db_connection_deref(ci);
+		return NF_ACCEPT;
+	}
+
+	/*
 	 * Keep connection alive as we have seen activity
 	 */
 	if (!ecm_db_connection_defunct_timer_touch(ci)) {
@@ -2337,6 +2402,7 @@
 		sender = ECM_TRACKER_SENDER_TYPE_DEST;
 	}
 
+
 	/*
 	 * Do we need to action generation change?
 	 */