[qca-nss-ecm] l2tp over pppoe support

Change-Id: Ibd9e08bd00c8a756fa21bb8f791dcf5f0878e838
Signed-off-by: ratheesh kannoth <rkannoth@codeaurora.org>
diff --git a/ecm_interface.c b/ecm_interface.c
index 672366a..f61d31d 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -1254,6 +1254,7 @@
 	ii = ecm_db_iface_find_and_ref_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id, type_info->l2tp.session.session_id);
 	if (ii) {
 		DEBUG_TRACE("%p: iface established\n", ii);
+		ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
 		return ii;
 	}
 
@@ -1274,6 +1275,7 @@
 	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;
 	}
 
@@ -1842,78 +1844,79 @@
 	 */
 	if (skb && skb->sk && (skb->sk->sk_protocol == IPPROTO_UDP)
 	    && (udp_sk(skb->sk)->encap_type == UDP_ENCAP_L2TPINUDP)) {
-		struct sock *sk = NULL;
-		struct inet_sock *inet = NULL;
-		struct l2tp_session *session = NULL;
-		struct l2tp_session *temp_session = NULL;
-		struct l2tp_tunnel *tunnel = NULL;
-		int hash;
-		struct hlist_node *walk = NULL;
+		if (skb->skb_iif == dev->ifindex) {
+			struct sock *sk = NULL;
+			struct inet_sock *inet = NULL;
+			struct l2tp_session *session = NULL;
+			struct l2tp_tunnel *tunnel = NULL;
+			int hash;
+			struct hlist_node *walk = NULL;
+			bool session_found = false;
 
-		/*
-		 * PPPoL2TPV2 channel
-		 */
-		DEBUG_TRACE("%p:  PPP channel is PPPoL2TPV2 (%s)\n", dev, dev->name);
+			/*
+			 * PPPoL2TPV2 channel
+			 */
+			DEBUG_TRACE("%p:  PPP channel is PPPoL2TPV2 (%s)\n", dev, dev->name);
 
-		/*
-		 * Get the L2TP tunnel socket this packet is associated with
-		 */
-		sk = skb->sk;
-		tunnel = l2tp_sock_to_tunnel(sk);
-		if (tunnel == NULL) {
-			return NULL;
-		}
+			/*
+			 * Get the L2TP tunnel socket this packet is associated with
+			 */
+			sk = skb->sk;
+			tunnel = l2tp_sock_to_tunnel(sk);
+			if (tunnel == NULL) {
+				return NULL;
+			}
 
-		/*
-		 * Check L2TPv2 tunnel version
-		 */
-		if (tunnel->version != 2) {
-			sock_put(sk);
-			return NULL;
-		}
+			/*
+			 * Check L2TPv2 tunnel version
+			 */
+			if (tunnel->version != 2) {
+				sock_put(sk);
+				return NULL;
+			}
 
-		/*
-		 * Find the L2TP session this packet is associated with
-		 */
-		read_lock_bh(&tunnel->hlist_lock);
-		for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
-			hlist_for_each_entry(temp_session, walk,
-					     &tunnel->session_hlist[hash], hlist) {
-				if (!strcmp(temp_session->ifname, dev_name)) {
-					session = temp_session;
-					break;
+			type_info.pppol2tpv2.l2tp.tunnel.tunnel_id = tunnel->tunnel_id;
+			type_info.pppol2tpv2.l2tp.tunnel.peer_tunnel_id = tunnel->peer_tunnel_id;
+
+			/*
+			 * Find the L2TP session this packet is associated with
+			 */
+			rcu_read_lock_bh();
+			for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
+				hlist_for_each_entry_rcu(session, walk,
+						     &tunnel->session_hlist[hash], hlist) {
+					if (!strcmp(session->ifname, dev_name)) {
+						type_info.pppol2tpv2.l2tp.session.session_id = session->session_id;
+						type_info.pppol2tpv2.l2tp.session.peer_session_id = session->peer_session_id;
+						session_found = true;
+						break;
+					}
 				}
 			}
-		}
-		read_unlock_bh(&tunnel->hlist_lock);
+			rcu_read_unlock_bh();
 
-		if (session == NULL) {
+			if (!session_found) {
+				sock_put(sk);
+				return NULL;
+			}
+
+			inet = inet_sk(sk);
+
+			type_info.pppol2tpv2.udp.sport = ntohs(inet->inet_sport);
+			type_info.pppol2tpv2.udp.dport = ntohs(inet->inet_sport);
+			type_info.pppol2tpv2.ip.saddr = ntohl(inet->inet_saddr);
+			type_info.pppol2tpv2.ip.daddr = ntohl(inet->inet_daddr);
+
 			sock_put(sk);
-			return NULL;
+
+			DEBUG_TRACE("%p: found PPPo2L2TP session\n", dev);
+
+			/*
+			 * Establish this type of interface
+			 */
+			ii = ecm_interface_pppol2tpv2_interface_establish(&type_info.pppol2tpv2, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+			return ii;
 		}
-
-		inet = inet_sk(sk);
-		l2tp_session_inc_refcount(session);
-
-		type_info.pppol2tpv2.l2tp.tunnel.tunnel_id = tunnel->tunnel_id;
-		type_info.pppol2tpv2.l2tp.tunnel.peer_tunnel_id = tunnel->peer_tunnel_id;
-		type_info.pppol2tpv2.l2tp.session.session_id = session->session_id;
-		type_info.pppol2tpv2.l2tp.session.peer_session_id = session->peer_session_id;
-		type_info.pppol2tpv2.udp.sport = ntohs(inet->inet_sport);
-		type_info.pppol2tpv2.udp.dport = ntohs(inet->inet_sport);
-		type_info.pppol2tpv2.ip.saddr = ntohl(inet->inet_saddr);
-		type_info.pppol2tpv2.ip.daddr = ntohl(inet->inet_daddr);
-
-		l2tp_session_dec_refcount(session);
-		sock_put(sk);
-
-		DEBUG_TRACE("%p: found PPPo2L2TP session\n", dev);
-
-		/*
-		 * Establish this type of interface
-		 */
-		ii = ecm_interface_pppol2tpv2_interface_establish(&type_info.pppol2tpv2, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
-		return ii;
 	}
 #endif
 
@@ -2968,6 +2971,22 @@
 		}
 	}
 
+#ifdef ECM_INTERFACE_L2TPV2_ENABLE
+	/*
+	 * if the address is a local address and indev=l2tp.
+	 */
+	if (skb && skb->sk && (skb->sk->sk_protocol == IPPROTO_UDP) && (udp_sk(skb->sk)->encap_type == UDP_ENCAP_L2TPINUDP)) {
+		if (dest_dev != given_src_dev) {
+			dev_put(src_dev);
+			src_dev = given_src_dev;
+			if (src_dev) {
+				dev_hold(src_dev);
+				DEBUG_TRACE("l2tp tunnel packet with src_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", ECM_IP_ADDR_TO_OCTAL(src_addr), src_dev, src_dev->name);
+			}
+		}
+	}
+#endif
+
 	if (!src_dev) {
 		DEBUG_WARN("src_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", ECM_IP_ADDR_TO_OCTAL(src_addr));
 		dev_put(dest_dev);
@@ -3329,8 +3348,10 @@
 
 #ifdef ECM_INTERFACE_L2TPV2_ENABLE
 			if (skb && skb->sk && (skb->sk->sk_protocol == IPPROTO_UDP) && (udp_sk(skb->sk)->encap_type == UDP_ENCAP_L2TPINUDP)) {
-				DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
-				break;
+				if (skb->skb_iif == dest_dev->ifindex) {
+					DEBUG_TRACE("Net device: %p PPP channel is PPPoL2TPV2\n", dest_dev);
+					break;
+				}
 			}
 #endif
 			/*