[qca-nss-ecm] Update the TCP window information correctly

When a connection is created with the reply direction of the
conntrack entry, the TCP window information needs to be updated
with the correct values. So, we need the flow and return direction
information respect to the conntrack direction.

Change-Id: I75551d28a67194ea84e4fc2d0be7e73d5ef5f468
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
diff --git a/frontends/include/ecm_front_end_common.h b/frontends/include/ecm_front_end_common.h
index 99faecf..a95b8af 100644
--- a/frontends/include/ecm_front_end_common.h
+++ b/frontends/include/ecm_front_end_common.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2015 The Linux Foundation.  All rights reserved.
+ * Copyright (c) 2015-2016 The Linux Foundation.  All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -180,6 +180,50 @@
 	return false;
 }
 
+/*
+ * ecm_front_end_flow_and_return_directions_get()
+ *	Gets the flow and return flows directions respect to conntrack entry.
+ */
+static inline void ecm_front_end_flow_and_return_directions_get(struct nf_conn *ct, ip_addr_t flow_ip, int ip_version, int *flow_dir, int *return_dir)
+{
+	ip_addr_t ct_src_ip;
+
+	if (ip_version == 4) {
+		uint32_t flow_ip_32;
+		uint32_t ct_src_ip_32;
+		ECM_NIN4_ADDR_TO_IP_ADDR(ct_src_ip, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip);
+
+		/*
+		 * Print the IP addresses for debug purpose.
+		 */
+		ECM_IP_ADDR_TO_HIN4_ADDR(flow_ip_32, flow_ip);
+		ECM_IP_ADDR_TO_HIN4_ADDR(ct_src_ip_32, ct_src_ip);
+		DEBUG_TRACE("flow_ip: %pI4h ct_src_ip: %pI4h\n", &flow_ip_32, &ct_src_ip_32);
+	} else if (ip_version == 6) {
+		ECM_NIN6_ADDR_TO_IP_ADDR(ct_src_ip, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.in6);
+
+		/*
+		 * Print the IP addresses for debug purpose.
+		 */
+		DEBUG_TRACE("flow_ip: " ECM_IP_ADDR_OCTAL_FMT " ct_src_ip: " ECM_IP_ADDR_OCTAL_FMT "\n",
+				ECM_IP_ADDR_TO_OCTAL(flow_ip), ECM_IP_ADDR_TO_OCTAL(ct_src_ip));
+	} else {
+		DEBUG_ASSERT(NULL, "Invalid ip version");
+	}
+
+	if (ECM_IP_ADDR_MATCH(ct_src_ip, flow_ip)) {
+		*flow_dir = IP_CT_DIR_ORIGINAL;
+		*return_dir = IP_CT_DIR_REPLY;
+		DEBUG_TRACE("flow_ip and ct_src_ip match\n");
+	} else {
+		*flow_dir = IP_CT_DIR_REPLY;
+		*return_dir = IP_CT_DIR_ORIGINAL;
+		DEBUG_TRACE("flow_ip and ct_src_ip do not match\n");
+	}
+
+	DEBUG_TRACE("flow_dir: %d return_dir: %d\n", *flow_dir, *return_dir);
+}
+
 extern void ecm_front_end_conntrack_notifier_stop(int num);
 extern int ecm_front_end_conntrack_notifier_init(struct dentry *dentry);
 extern void ecm_front_end_conntrack_notifier_exit(void);
diff --git a/frontends/nss/ecm_nss_ipv4.c b/frontends/nss/ecm_nss_ipv4.c
index 2364ed2..7afd787 100644
--- a/frontends/nss/ecm_nss_ipv4.c
+++ b/frontends/nss/ecm_nss_ipv4.c
@@ -1799,6 +1799,8 @@
 	int flow_ident;
 	int return_ident_xlate;
 	struct ecm_classifier_rule_sync class_sync;
+	int flow_dir;
+	int return_dir;
 
 	/*
 	 * Look up ecm connection with a view to synchronising the connection, classifier and data tracker.
@@ -2081,6 +2083,8 @@
 	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
 	DEBUG_TRACE("%p: NSS Sync: conntrack connection\n", ct);
 
+	ecm_front_end_flow_and_return_directions_get(ct, flow_ip, 4, &flow_dir, &return_dir);
+
 	/*
 	 * Only update if this is not a fixed timeout
 	 */
@@ -2108,34 +2112,34 @@
 #endif
 	if (acct) {
 		spin_lock_bh(&ct->lock);
-		atomic64_add(sync->flow_rx_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
-		atomic64_add(sync->flow_rx_byte_count, &acct[IP_CT_DIR_ORIGINAL].bytes);
+		atomic64_add(sync->flow_rx_packet_count, &acct[flow_dir].packets);
+		atomic64_add(sync->flow_rx_byte_count, &acct[flow_dir].bytes);
 
-		atomic64_add(sync->return_rx_packet_count, &acct[IP_CT_DIR_REPLY].packets);
-		atomic64_add(sync->return_rx_byte_count, &acct[IP_CT_DIR_REPLY].bytes);
+		atomic64_add(sync->return_rx_packet_count, &acct[return_dir].packets);
+		atomic64_add(sync->return_rx_byte_count, &acct[return_dir].bytes);
 		spin_unlock_bh(&ct->lock);
 	}
 
 	switch (sync->protocol) {
 	case IPPROTO_TCP:
 		spin_lock_bh(&ct->lock);
-		if (ct->proto.tcp.seen[0].td_maxwin < sync->flow_max_window) {
-			ct->proto.tcp.seen[0].td_maxwin = sync->flow_max_window;
+		if (ct->proto.tcp.seen[flow_dir].td_maxwin < sync->flow_max_window) {
+			ct->proto.tcp.seen[flow_dir].td_maxwin = sync->flow_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_end - sync->flow_end) < 0) {
-			ct->proto.tcp.seen[0].td_end = sync->flow_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_end - sync->flow_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_end = sync->flow_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sync->flow_max_end) < 0) {
-			ct->proto.tcp.seen[0].td_maxend = sync->flow_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_maxend - sync->flow_max_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_maxend = sync->flow_max_end;
 		}
-		if (ct->proto.tcp.seen[1].td_maxwin < sync->return_max_window) {
-			ct->proto.tcp.seen[1].td_maxwin = sync->return_max_window;
+		if (ct->proto.tcp.seen[return_dir].td_maxwin < sync->return_max_window) {
+			ct->proto.tcp.seen[return_dir].td_maxwin = sync->return_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_end - sync->return_end) < 0) {
-			ct->proto.tcp.seen[1].td_end = sync->return_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_end - sync->return_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_end = sync->return_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sync->return_max_end) < 0) {
-			ct->proto.tcp.seen[1].td_maxend = sync->return_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_maxend - sync->return_max_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_maxend = sync->return_max_end;
 		}
 		spin_unlock_bh(&ct->lock);
 		break;
diff --git a/frontends/nss/ecm_nss_ipv6.c b/frontends/nss/ecm_nss_ipv6.c
index c7cb8e4..b9f0313 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -1482,6 +1482,8 @@
 	struct in6_addr group6 __attribute__((unused));
 	struct in6_addr origin6 __attribute__((unused));
 	struct ecm_classifier_rule_sync class_sync;
+	int flow_dir;
+	int return_dir;
 
 	ECM_NSS_IPV6_ADDR_TO_IP_ADDR(flow_ip, sync->flow_ip);
 	ECM_NSS_IPV6_ADDR_TO_IP_ADDR(return_ip, sync->return_ip);
@@ -1741,6 +1743,8 @@
 	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
 	DEBUG_TRACE("%p: NSS Sync: conntrack connection\n", ct);
 
+	ecm_front_end_flow_and_return_directions_get(ct, flow_ip, 6, &flow_dir, &return_dir);
+
 	/*
 	 * Only update if this is not a fixed timeout
 	 */
@@ -1767,34 +1771,34 @@
 #endif
 	if (acct) {
 		spin_lock_bh(&ct->lock);
-		atomic64_add(sync->flow_rx_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
-		atomic64_add(sync->flow_rx_byte_count, &acct[IP_CT_DIR_ORIGINAL].bytes);
+		atomic64_add(sync->flow_rx_packet_count, &acct[flow_dir].packets);
+		atomic64_add(sync->flow_rx_byte_count, &acct[flow_dir].bytes);
 
-		atomic64_add(sync->return_rx_packet_count, &acct[IP_CT_DIR_REPLY].packets);
-		atomic64_add(sync->return_rx_byte_count, &acct[IP_CT_DIR_REPLY].bytes);
+		atomic64_add(sync->return_rx_packet_count, &acct[return_dir].packets);
+		atomic64_add(sync->return_rx_byte_count, &acct[return_dir].bytes);
 		spin_unlock_bh(&ct->lock);
 	}
 
 	switch (sync->protocol) {
 	case IPPROTO_TCP:
 		spin_lock_bh(&ct->lock);
-		if (ct->proto.tcp.seen[0].td_maxwin < sync->flow_max_window) {
-			ct->proto.tcp.seen[0].td_maxwin = sync->flow_max_window;
+		if (ct->proto.tcp.seen[flow_dir].td_maxwin < sync->flow_max_window) {
+			ct->proto.tcp.seen[flow_dir].td_maxwin = sync->flow_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_end - sync->flow_end) < 0) {
-			ct->proto.tcp.seen[0].td_end = sync->flow_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_end - sync->flow_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_end = sync->flow_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sync->flow_max_end) < 0) {
-			ct->proto.tcp.seen[0].td_maxend = sync->flow_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_maxend - sync->flow_max_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_maxend = sync->flow_max_end;
 		}
-		if (ct->proto.tcp.seen[1].td_maxwin < sync->return_max_window) {
-			ct->proto.tcp.seen[1].td_maxwin = sync->return_max_window;
+		if (ct->proto.tcp.seen[return_dir].td_maxwin < sync->return_max_window) {
+			ct->proto.tcp.seen[return_dir].td_maxwin = sync->return_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_end - sync->return_end) < 0) {
-			ct->proto.tcp.seen[1].td_end = sync->return_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_end - sync->return_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_end = sync->return_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sync->return_max_end) < 0) {
-			ct->proto.tcp.seen[1].td_maxend = sync->return_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_maxend - sync->return_max_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_maxend = sync->return_max_end;
 		}
 		spin_unlock_bh(&ct->lock);
 		break;
diff --git a/frontends/nss/ecm_nss_ported_ipv4.c b/frontends/nss/ecm_nss_ported_ipv4.c
index 449f2d7..c701d59 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_ported_ipv4.c
@@ -75,6 +75,7 @@
 #include "ecm_tracker.h"
 #include "ecm_classifier.h"
 #include "ecm_front_end_types.h"
+#include "ecm_front_end_common.h"
 #include "ecm_tracker_datagram.h"
 #include "ecm_tracker_udp.h"
 #include "ecm_tracker_tcp.h"
@@ -979,24 +980,29 @@
 			DEBUG_TRACE("%p: TCP Accel no ct from conn %p to get window data\n", npci, feci->ci);
 			nircm->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 		} else {
-			spin_lock_bh(&ct->lock);
-			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			int flow_dir;
+			int return_dir;
 
-			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[0].td_scale;
-			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[0].td_maxwin;
-			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[0].td_end;
-			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[0].td_maxend;
-			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[1].td_scale;
-			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[1].td_maxwin;
-			nircm->tcp_rule.return_end = ct->proto.tcp.seen[1].td_end;
-			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[1].td_maxend;
+			ecm_db_connection_from_address_get(feci->ci, addr);
+			ecm_front_end_flow_and_return_directions_get(ct, addr, 4, &flow_dir, &return_dir);
+
+			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			spin_lock_bh(&ct->lock);
+			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[flow_dir].td_scale;
+			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[flow_dir].td_maxwin;
+			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[flow_dir].td_end;
+			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[flow_dir].td_maxend;
+			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[return_dir].td_scale;
+			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[return_dir].td_maxwin;
+			nircm->tcp_rule.return_end = ct->proto.tcp.seen[return_dir].td_end;
+			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[return_dir].td_maxend;
 #ifdef ECM_OPENWRT_SUPPORT
 			if (nf_ct_tcp_be_liberal || nf_ct_tcp_no_window_check
 #else
 			if (nf_ct_tcp_be_liberal
 #endif
-					|| (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
-					|| (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
+					|| (ct->proto.tcp.seen[flow_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
+					|| (ct->proto.tcp.seen[return_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
 				nircm->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 			}
 			spin_unlock_bh(&ct->lock);
diff --git a/frontends/nss/ecm_nss_ported_ipv6.c b/frontends/nss/ecm_nss_ported_ipv6.c
index 2662e2b..5f7c810 100644
--- a/frontends/nss/ecm_nss_ported_ipv6.c
+++ b/frontends/nss/ecm_nss_ported_ipv6.c
@@ -76,6 +76,7 @@
 #include "ecm_tracker.h"
 #include "ecm_classifier.h"
 #include "ecm_front_end_types.h"
+#include "ecm_front_end_common.h"
 #include "ecm_tracker_datagram.h"
 #include "ecm_tracker_udp.h"
 #include "ecm_tracker_tcp.h"
@@ -880,24 +881,28 @@
 			DEBUG_TRACE("%p: TCP Accel no ct from conn %p to get window data\n", npci, feci->ci);
 			nircm->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 		} else {
-			spin_lock_bh(&ct->lock);
-			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			int flow_dir;
+			int return_dir;
 
-			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[0].td_scale;
-			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[0].td_maxwin;
-			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[0].td_end;
-			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[0].td_maxend;
-			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[1].td_scale;
-			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[1].td_maxwin;
-			nircm->tcp_rule.return_end = ct->proto.tcp.seen[1].td_end;
-			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[1].td_maxend;
+			ecm_front_end_flow_and_return_directions_get(ct, src_ip, 6, &flow_dir, &return_dir);
+
+			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			spin_lock_bh(&ct->lock);
+			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[flow_dir].td_scale;
+			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[flow_dir].td_maxwin;
+			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[flow_dir].td_end;
+			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[flow_dir].td_maxend;
+			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[return_dir].td_scale;
+			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[return_dir].td_maxwin;
+			nircm->tcp_rule.return_end = ct->proto.tcp.seen[return_dir].td_end;
+			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[return_dir].td_maxend;
 #ifdef ECM_OPENWRT_SUPPORT
 			if (nf_ct_tcp_be_liberal || nf_ct_tcp_no_window_check
 #else
 			if (nf_ct_tcp_be_liberal
 #endif
-					|| (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
-					|| (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
+					|| (ct->proto.tcp.seen[flow_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
+					|| (ct->proto.tcp.seen[return_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
 				nircm->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 			}
 			spin_unlock_bh(&ct->lock);
diff --git a/frontends/sfe/ecm_sfe_ipv4.c b/frontends/sfe/ecm_sfe_ipv4.c
index 2e65155..b3edf6e 100644
--- a/frontends/sfe/ecm_sfe_ipv4.c
+++ b/frontends/sfe/ecm_sfe_ipv4.c
@@ -1413,6 +1413,8 @@
 	int aci_index;
 	int assignment_count;
 	struct ecm_classifier_rule_sync class_sync;
+	int flow_dir;
+	int return_dir;
 
 	/*
 	 * Only respond to sync messages
@@ -1679,6 +1681,8 @@
 	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
 	DEBUG_TRACE("%p: SFE Sync: conntrack connection\n", ct);
 
+	ecm_front_end_flow_and_return_directions_get(ct, flow_ip, 4, &flow_dir, &return_dir);
+
 	/*
 	 * Only update if this is not a fixed timeout
 	 */
@@ -1706,34 +1710,34 @@
 #endif
 	if (acct) {
 		spin_lock_bh(&ct->lock);
-		atomic64_add(sync->flow_rx_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
-		atomic64_add(sync->flow_rx_byte_count, &acct[IP_CT_DIR_ORIGINAL].bytes);
+		atomic64_add(sync->flow_rx_packet_count, &acct[flow_dir].packets);
+		atomic64_add(sync->flow_rx_byte_count, &acct[flow_dir].bytes);
 
-		atomic64_add(sync->return_rx_packet_count, &acct[IP_CT_DIR_REPLY].packets);
-		atomic64_add(sync->return_rx_byte_count, &acct[IP_CT_DIR_REPLY].bytes);
+		atomic64_add(sync->return_rx_packet_count, &acct[return_dir].packets);
+		atomic64_add(sync->return_rx_byte_count, &acct[return_dir].bytes);
 		spin_unlock_bh(&ct->lock);
 	}
 
 	switch (sync->protocol) {
 	case IPPROTO_TCP:
 		spin_lock_bh(&ct->lock);
-		if (ct->proto.tcp.seen[0].td_maxwin < sync->flow_max_window) {
-			ct->proto.tcp.seen[0].td_maxwin = sync->flow_max_window;
+		if (ct->proto.tcp.seen[flow_dir].td_maxwin < sync->flow_max_window) {
+			ct->proto.tcp.seen[flow_dir].td_maxwin = sync->flow_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_end - sync->flow_end) < 0) {
-			ct->proto.tcp.seen[0].td_end = sync->flow_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_end - sync->flow_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_end = sync->flow_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sync->flow_max_end) < 0) {
-			ct->proto.tcp.seen[0].td_maxend = sync->flow_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_maxend - sync->flow_max_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_maxend = sync->flow_max_end;
 		}
-		if (ct->proto.tcp.seen[1].td_maxwin < sync->return_max_window) {
-			ct->proto.tcp.seen[1].td_maxwin = sync->return_max_window;
+		if (ct->proto.tcp.seen[return_dir].td_maxwin < sync->return_max_window) {
+			ct->proto.tcp.seen[return_dir].td_maxwin = sync->return_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_end - sync->return_end) < 0) {
-			ct->proto.tcp.seen[1].td_end = sync->return_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_end - sync->return_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_end = sync->return_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sync->return_max_end) < 0) {
-			ct->proto.tcp.seen[1].td_maxend = sync->return_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_maxend - sync->return_max_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_maxend = sync->return_max_end;
 		}
 		spin_unlock_bh(&ct->lock);
 		break;
diff --git a/frontends/sfe/ecm_sfe_ipv6.c b/frontends/sfe/ecm_sfe_ipv6.c
index e8512e8..a61bd18 100644
--- a/frontends/sfe/ecm_sfe_ipv6.c
+++ b/frontends/sfe/ecm_sfe_ipv6.c
@@ -1141,6 +1141,8 @@
 	struct in6_addr group6 __attribute__((unused));
 	struct in6_addr origin6 __attribute__((unused));
 	struct ecm_classifier_rule_sync class_sync;
+	int flow_dir;
+	int return_dir;
 
 	/*
 	 * Only respond to sync messages
@@ -1393,6 +1395,8 @@
 	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
 	DEBUG_TRACE("%p: SFE Sync: conntrack connection\n", ct);
 
+	ecm_front_end_flow_and_return_directions_get(ct, flow_ip, 6, &flow_dir, &return_dir);
+
 	/*
 	 * Only update if this is not a fixed timeout
 	 */
@@ -1419,34 +1423,34 @@
 #endif
 	if (acct) {
 		spin_lock_bh(&ct->lock);
-		atomic64_add(sync->flow_rx_packet_count, &acct[IP_CT_DIR_ORIGINAL].packets);
-		atomic64_add(sync->flow_rx_byte_count, &acct[IP_CT_DIR_ORIGINAL].bytes);
+		atomic64_add(sync->flow_rx_packet_count, &acct[flow_dir].packets);
+		atomic64_add(sync->flow_rx_byte_count, &acct[flow_dir].bytes);
 
-		atomic64_add(sync->return_rx_packet_count, &acct[IP_CT_DIR_REPLY].packets);
-		atomic64_add(sync->return_rx_byte_count, &acct[IP_CT_DIR_REPLY].bytes);
+		atomic64_add(sync->return_rx_packet_count, &acct[return_dir].packets);
+		atomic64_add(sync->return_rx_byte_count, &acct[return_dir].bytes);
 		spin_unlock_bh(&ct->lock);
 	}
 
 	switch (sync->protocol) {
 	case IPPROTO_TCP:
 		spin_lock_bh(&ct->lock);
-		if (ct->proto.tcp.seen[0].td_maxwin < sync->flow_max_window) {
-			ct->proto.tcp.seen[0].td_maxwin = sync->flow_max_window;
+		if (ct->proto.tcp.seen[flow_dir].td_maxwin < sync->flow_max_window) {
+			ct->proto.tcp.seen[flow_dir].td_maxwin = sync->flow_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_end - sync->flow_end) < 0) {
-			ct->proto.tcp.seen[0].td_end = sync->flow_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_end - sync->flow_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_end = sync->flow_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sync->flow_max_end) < 0) {
-			ct->proto.tcp.seen[0].td_maxend = sync->flow_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[flow_dir].td_maxend - sync->flow_max_end) < 0) {
+			ct->proto.tcp.seen[flow_dir].td_maxend = sync->flow_max_end;
 		}
-		if (ct->proto.tcp.seen[1].td_maxwin < sync->return_max_window) {
-			ct->proto.tcp.seen[1].td_maxwin = sync->return_max_window;
+		if (ct->proto.tcp.seen[return_dir].td_maxwin < sync->return_max_window) {
+			ct->proto.tcp.seen[return_dir].td_maxwin = sync->return_max_window;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_end - sync->return_end) < 0) {
-			ct->proto.tcp.seen[1].td_end = sync->return_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_end - sync->return_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_end = sync->return_end;
 		}
-		if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sync->return_max_end) < 0) {
-			ct->proto.tcp.seen[1].td_maxend = sync->return_max_end;
+		if ((int32_t)(ct->proto.tcp.seen[return_dir].td_maxend - sync->return_max_end) < 0) {
+			ct->proto.tcp.seen[return_dir].td_maxend = sync->return_max_end;
 		}
 		spin_unlock_bh(&ct->lock);
 		break;
diff --git a/frontends/sfe/ecm_sfe_ported_ipv4.c b/frontends/sfe/ecm_sfe_ported_ipv4.c
index 2dade9d..e789737 100644
--- a/frontends/sfe/ecm_sfe_ported_ipv4.c
+++ b/frontends/sfe/ecm_sfe_ported_ipv4.c
@@ -75,6 +75,7 @@
 #include "ecm_tracker.h"
 #include "ecm_classifier.h"
 #include "ecm_front_end_types.h"
+#include "ecm_front_end_common.h"
 #include "ecm_tracker_datagram.h"
 #include "ecm_tracker_udp.h"
 #include "ecm_tracker_tcp.h"
@@ -919,24 +920,29 @@
 			DEBUG_TRACE("%p: TCP Accel no ct from conn %p to get window data\n", npci, feci->ci);
 			nircm->rule_flags |= SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 		} else {
-			spin_lock_bh(&ct->lock);
-			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			int flow_dir;
+			int return_dir;
 
-			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[0].td_scale;
-			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[0].td_maxwin;
-			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[0].td_end;
-			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[0].td_maxend;
-			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[1].td_scale;
-			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[1].td_maxwin;
-			nircm->tcp_rule.return_end = ct->proto.tcp.seen[1].td_end;
-			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[1].td_maxend;
+			ecm_db_connection_from_address_get(feci->ci, addr);
+			ecm_front_end_flow_and_return_directions_get(ct, addr, 4, &flow_dir, &return_dir);
+
+			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			spin_lock_bh(&ct->lock);
+			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[flow_dir].td_scale;
+			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[flow_dir].td_maxwin;
+			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[flow_dir].td_end;
+			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[flow_dir].td_maxend;
+			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[return_dir].td_scale;
+			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[return_dir].td_maxwin;
+			nircm->tcp_rule.return_end = ct->proto.tcp.seen[return_dir].td_end;
+			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[return_dir].td_maxend;
 #ifdef ECM_OPENWRT_SUPPORT
 			if (nf_ct_tcp_be_liberal || nf_ct_tcp_no_window_check
 #else
 			if (nf_ct_tcp_be_liberal
 #endif
-					|| (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
-					|| (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
+					|| (ct->proto.tcp.seen[flow_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
+					|| (ct->proto.tcp.seen[return_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
 				nircm->rule_flags |= SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 			} else {
 #ifdef CONFIG_XFRM
diff --git a/frontends/sfe/ecm_sfe_ported_ipv6.c b/frontends/sfe/ecm_sfe_ported_ipv6.c
index 9c8792f..8b87191 100644
--- a/frontends/sfe/ecm_sfe_ported_ipv6.c
+++ b/frontends/sfe/ecm_sfe_ported_ipv6.c
@@ -76,6 +76,7 @@
 #include "ecm_tracker.h"
 #include "ecm_classifier.h"
 #include "ecm_front_end_types.h"
+#include "ecm_front_end_common.h"
 #include "ecm_tracker_datagram.h"
 #include "ecm_tracker_udp.h"
 #include "ecm_tracker_tcp.h"
@@ -879,24 +880,28 @@
 			DEBUG_TRACE("%p: TCP Accel no ct from conn %p to get window data\n", npci, feci->ci);
 			nircm->rule_flags |= SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 		} else {
-			spin_lock_bh(&ct->lock);
-			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			int flow_dir;
+			int return_dir;
 
-			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[0].td_scale;
-			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[0].td_maxwin;
-			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[0].td_end;
-			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[0].td_maxend;
-			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[1].td_scale;
-			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[1].td_maxwin;
-			nircm->tcp_rule.return_end = ct->proto.tcp.seen[1].td_end;
-			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[1].td_maxend;
+			ecm_front_end_flow_and_return_directions_get(ct, src_ip, 6, &flow_dir, &return_dir);
+
+			DEBUG_TRACE("%p: TCP Accel Get window data from ct %p for conn %p\n", npci, ct, feci->ci);
+			spin_lock_bh(&ct->lock);
+			nircm->tcp_rule.flow_window_scale = ct->proto.tcp.seen[flow_dir].td_scale;
+			nircm->tcp_rule.flow_max_window = ct->proto.tcp.seen[flow_dir].td_maxwin;
+			nircm->tcp_rule.flow_end = ct->proto.tcp.seen[flow_dir].td_end;
+			nircm->tcp_rule.flow_max_end = ct->proto.tcp.seen[flow_dir].td_maxend;
+			nircm->tcp_rule.return_window_scale = ct->proto.tcp.seen[return_dir].td_scale;
+			nircm->tcp_rule.return_max_window = ct->proto.tcp.seen[return_dir].td_maxwin;
+			nircm->tcp_rule.return_end = ct->proto.tcp.seen[return_dir].td_end;
+			nircm->tcp_rule.return_max_end = ct->proto.tcp.seen[return_dir].td_maxend;
 #ifdef ECM_OPENWRT_SUPPORT
 			if (nf_ct_tcp_be_liberal || nf_ct_tcp_no_window_check
 #else
 			if (nf_ct_tcp_be_liberal
 #endif
-					|| (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
-					|| (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
+					|| (ct->proto.tcp.seen[flow_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)
+					|| (ct->proto.tcp.seen[return_dir].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) {
 				nircm->rule_flags |= SFE_RULE_CREATE_FLAG_NO_SEQ_CHECK;
 			} else {
 #ifdef CONFIG_XFRM