[qca-nss-sfe] PPPoE offload fixes

1. Fix protocol and endianess
2. Fix copyright year style
3. Pass non-NULL l2_info and check parse flags before using l2_info

Change-Id: I7801834b224a39a04450fdacbbb9cb9620b4221c
Signed-off-by: Guduri Prathyusha <quic_gprathyu@quicinc.com>
diff --git a/exports/sfe_api.h b/exports/sfe_api.h
index a69dfe9..75077b0 100644
--- a/exports/sfe_api.h
+++ b/exports/sfe_api.h
@@ -3,7 +3,7 @@
  *	 SFE exported function headers for SFE engine
  *
  * Copyright (c) 2015,2016, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe.c b/sfe.c
index 22ed43d..8968e94 100644
--- a/sfe.c
+++ b/sfe.c
@@ -3,7 +3,7 @@
  *     API for shortcut forwarding engine.
  *
  * Copyright (c) 2015,2016, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -473,7 +473,7 @@
 	 * Parse only PPPoE session packets
 	 * skb->data is pointing to PPPoE hdr
 	 */
-	if (!sfe_pppoe_validate_hdr(skb, l2_info)) {
+	if (!sfe_pppoe_parse_hdr(skb, l2_info)) {
 
 		/*
 		 * For exception from PPPoE return from here without modifying the skb->data
@@ -482,10 +482,6 @@
 		return false;
 	}
 
-	sfe_l2_parse_flag_set(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS);
-	sfe_l2_pppoe_hdr_offset_set(l2_info, (skb->data - skb->head));
-	sfe_l2_hdr_size_set(l2_info, SFE_PPPOE_HEADER_SIZE);
-
 	/*
 	 * Pull by L2 header size considering all L2.5 headers
 	 */
@@ -1143,6 +1139,11 @@
 
 	dev = skb->dev;
 
+	/*
+	 * Setting parse flags to 0 since l2_info is passed for non L2.5 header case as well
+	 */
+	l2_info.parse_flags = 0;
+
 #ifdef CONFIG_NET_CLS_ACT
 	/*
 	 * If ingress Qdisc configured, and packet not processed by ingress Qdisc yet
@@ -1166,7 +1167,7 @@
 	switch (ntohs(skb->protocol)) {
 	case ETH_P_IP:
 		if (likely(sfe_is_l2_feature_enabled()) || sfe_dev_is_layer_3_interface(dev, true)) {
-			return sfe_ipv4_recv(dev, skb, NULL, false);
+			return sfe_ipv4_recv(dev, skb, &l2_info, false);
 		}
 
 		DEBUG_TRACE("No IPv4 address for device: %s\n", dev->name);
@@ -1174,7 +1175,7 @@
 
 	case ETH_P_IPV6:
 		if (likely(sfe_is_l2_feature_enabled()) || sfe_dev_is_layer_3_interface(dev, false)) {
-			return sfe_ipv6_recv(dev, skb, NULL, false);
+			return sfe_ipv6_recv(dev, skb, &l2_info, false);
 		}
 
 		DEBUG_TRACE("No IPv6 address for device: %s\n", dev->name);
@@ -1196,13 +1197,13 @@
 	 * Parse the L2 headers to find the L3 protocol and the L2 header offset
 	 */
 	if (unlikely(!sfe_recv_parse_l2(dev, skb, &l2_info))) {
-		DEBUG_TRACE("%px: Invalid L2.5 header format\n", skb);
+		DEBUG_TRACE("%px: Invalid L2.5 header format with protocol : %d\n", skb, ntohs(skb->protocol));
 		return 0;
 	}
 
 	/*
-	 * Protocol in l2_info is expected to be in network byte order.
-	 * PPPoE is doing it in the sfe_pppoe_validate_hdr()
+	 * Protocol in l2_info is expected to be in host byte order.
+	 * PPPoE is doing it in the sfe_pppoe_parse_hdr()
 	 */
 	if (likely(l2_info.protocol == ETH_P_IP)) {
 		ret = sfe_ipv4_recv(dev, skb, &l2_info, false);
diff --git a/sfe.h b/sfe.h
index 01636f2..c6f8421 100644
--- a/sfe.h
+++ b/sfe.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine.
  *
  * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -230,7 +230,7 @@
  * sfe_l2_parse_flag_set()
  *	Set L2 parse flag
  */
-static inline void sfe_l2_parse_flag_set(struct sfe_l2_info *l2_info, u32 flag)
+static inline void sfe_l2_parse_flag_set(struct sfe_l2_info *l2_info, u16 flag)
 {
 	l2_info->parse_flags |= flag;
 }
@@ -239,7 +239,7 @@
  * sfe_l2_parse_flag_get()
  *	Get L2 parse flag
  */
-static inline u32 sfe_l2_parse_flag_get(struct sfe_l2_info *l2_info)
+static inline u16 sfe_l2_parse_flag_get(struct sfe_l2_info *l2_info)
 {
 	return l2_info->parse_flags;
 }
@@ -248,9 +248,9 @@
  * sfe_l2_parse_flag_check()
  *	Check L2 parse flag
  */
-static inline bool sfe_l2_parse_flag_check(struct sfe_l2_info *l2_info, u32 flag)
+static inline bool sfe_l2_parse_flag_check(struct sfe_l2_info *l2_info, u16 flag)
 {
-	return l2_info->parse_flags & flag;
+	return !!(l2_info->parse_flags & flag);
 }
 
 /*
diff --git a/sfe_ipv4.c b/sfe_ipv4.c
index 34fbe1e..154700f 100644
--- a/sfe_ipv4.c
+++ b/sfe_ipv4.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv4 edition.
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -2253,10 +2253,13 @@
  */
 static unsigned int sfe_ipv4_local_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *nhs)
 {
+	struct sfe_l2_info l2_info;
+	l2_info.parse_flags = 0;
+
 	DEBUG_TRACE("%px: sfe: sfe_ipv4_local_out hook called.\n", skb);
 
 	if (likely(skb->skb_iif)) {
-		return sfe_ipv4_recv(skb->dev, skb, NULL, true) ? NF_STOLEN : NF_ACCEPT;
+		return sfe_ipv4_recv(skb->dev, skb, &l2_info, true) ? NF_STOLEN : NF_ACCEPT;
 	}
 
 	return NF_ACCEPT;
diff --git a/sfe_ipv4.h b/sfe_ipv4.h
index e614cbc..9f2e1f4 100644
--- a/sfe_ipv4.h
+++ b/sfe_ipv4.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine header file for IPv4.
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -237,7 +237,7 @@
 	SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE,
 	SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE,
 	SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL,
-	SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED,
+	SFE_IPV4_EXCEPTION_EVENT_NO_HEADROOM,
 	SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION,
 	SFE_IPV4_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING,
 	SFE_IPV4_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME,
diff --git a/sfe_ipv4_tcp.c b/sfe_ipv4_tcp.c
index 8c229ba..1f8e3d0 100644
--- a/sfe_ipv4_tcp.c
+++ b/sfe_ipv4_tcp.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv4 TCP implementation
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -467,45 +467,6 @@
 	}
 
 	/*
-	 * For PPPoE packets, match server MAC and session id
-	 */
-	if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
-		struct pppoe_hdr *ph;
-		struct ethhdr *eth;
-
-		if (unlikely(!l2_info) || unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
-			return 0;
-		}
-
-		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
-		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
-		if (unlikely(cm->pppoe_session_id != htons(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE sessions did not match \n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
-			return 0;
-		}
-		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
-	} else if (unlikely(l2_info) && unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-
-		/*
-		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
-		 */
-		rcu_read_unlock();
-		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
-		sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
-		return 0;
-	}
-
-	/*
-	 * From this point on we're good to modify the packet.
-	 */
-
-	/*
 	 * Check if skb was cloned. If it was, unshare it. Because
 	 * the data area is going to be written in this path and we don't want to
 	 * change the cloned skb's data section.
@@ -527,13 +488,54 @@
 	}
 
 	/*
+	 * For PPPoE packets, match server MAC and session id
+	 */
+	if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
+		struct pppoe_hdr *ph;
+		struct ethhdr *eth;
+
+		if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+			rcu_read_unlock();
+			DEBUG_TRACE("%px: PPPoE header not present in packet for PPPoE rule\n", skb);
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
+			return 0;
+		}
+
+		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
+		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
+		if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
+			DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
+							skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+			rcu_read_unlock();
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+			return 0;
+		}
+		skb->protocol = htons(l2_info->protocol);
+		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
+
+	} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+
+		/*
+		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+		 */
+		rcu_read_unlock();
+		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
+		sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
+		return 0;
+	}
+
+	/*
+	 * From this point on we're good to modify the packet.
+	 */
+
+	/*
 	 * For PPPoE flows, add PPPoE header before L2 header is added.
 	 */
 	if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
 		if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IP))) {
 			rcu_read_unlock();
 			DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NO_HEADROOM);
 			return 0;
 		}
 		this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
@@ -636,7 +638,7 @@
 	 */
 	if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
 		if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
-			dev_hard_header(skb, xmit_dev, ETH_P_IP,
+			dev_hard_header(skb, xmit_dev, ntohs(skb->protocol),
 					cm->xmit_dest_mac, cm->xmit_src_mac, len);
 		} else {
 			/*
@@ -644,7 +646,7 @@
 			 */
 			struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
 
-			eth->h_proto = htons(ETH_P_IP);
+			eth->h_proto = skb->protocol;
 
 			ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
 			ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
diff --git a/sfe_ipv4_tcp.h b/sfe_ipv4_tcp.h
index 81b7baf..a52ab4f 100644
--- a/sfe_ipv4_tcp.h
+++ b/sfe_ipv4_tcp.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv4 TCP header file
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe_ipv4_udp.c b/sfe_ipv4_udp.c
index 30aba15..c4847e2 100644
--- a/sfe_ipv4_udp.c
+++ b/sfe_ipv4_udp.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv4 UDP implementation
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -259,45 +259,6 @@
 	}
 
 	/*
-	 * For PPPoE packets, match server MAC and session id
-	 */
-	if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
-		struct pppoe_hdr *ph;
-		struct ethhdr *eth;
-
-		if (unlikely(!l2_info) || unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
-			return 0;
-		}
-
-		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
-		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
-		if (unlikely(cm->pppoe_session_id != htons(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE sessions did not match \n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
-			return 0;
-		}
-		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
-	} else if (unlikely(l2_info) && unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-
-		/*
-		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
-		 */
-		rcu_read_unlock();
-		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
-		sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
-		return 0;
-	}
-
-	/*
-	 * From this point on we're good to modify the packet.
-	 */
-
-	/*
 	 * Check if skb was cloned. If it was, unshare it. Because
 	 * the data area is going to be written in this path and we don't want to
 	 * change the cloned skb's data section.
@@ -319,13 +280,54 @@
 	}
 
 	/*
+	 * For PPPoE packets, match server MAC and session id
+	 */
+	if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
+		struct pppoe_hdr *ph;
+		struct ethhdr *eth;
+
+		if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+			rcu_read_unlock();
+			DEBUG_TRACE("%px: PPPoE header not present in packet for PPPoE rule\n", skb);
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
+			return 0;
+		}
+
+		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
+		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
+		if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
+			DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
+							skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+			rcu_read_unlock();
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+			return 0;
+		}
+		skb->protocol = htons(l2_info->protocol);
+		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
+
+	} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+
+		/*
+		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+		 */
+		rcu_read_unlock();
+		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
+		sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
+		return 0;
+	}
+
+	/*
+	 * From this point on we're good to modify the packet.
+	 */
+
+	/*
 	 * For PPPoE flows, add PPPoE header before L2 header is added.
 	 */
 	if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
 		if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IP))) {
 			rcu_read_unlock();
 			DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
-			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+			sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_NO_HEADROOM);
 			return 0;
 		}
 		this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
@@ -479,14 +481,14 @@
 	 */
 	if (likely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
 		if (unlikely(!(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
-			dev_hard_header(skb, xmit_dev, ETH_P_IP,
+			dev_hard_header(skb, xmit_dev, ntohs(skb->protocol),
 					cm->xmit_dest_mac, cm->xmit_src_mac, len);
 		} else {
 			/*
 			 * For the simple case we write this really fast.
 			 */
 			struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
-			eth->h_proto = htons(ETH_P_IP);
+			eth->h_proto = skb->protocol;
 			ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
 			ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
 		}
diff --git a/sfe_ipv4_udp.h b/sfe_ipv4_udp.h
index 4cb8d47..8c64fcf 100644
--- a/sfe_ipv4_udp.h
+++ b/sfe_ipv4_udp.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv4 UDP header file
  *
  * Copyright (c) 2013-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe_ipv6.c b/sfe_ipv6.c
index 7d75de7..813ce01 100644
--- a/sfe_ipv6.c
+++ b/sfe_ipv6.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine - IPv6 support.
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe_ipv6.h b/sfe_ipv6.h
index f737f79..4cbcd50 100644
--- a/sfe_ipv6.h
+++ b/sfe_ipv6.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine header file for IPv6.
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -243,7 +243,7 @@
 	SFE_IPV6_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE,
 	SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL,
 	SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL,
-	SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED,
+	SFE_IPV6_EXCEPTION_EVENT_NO_HEADROOM,
 	SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION,
 	SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING,
 	SFE_IPV6_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME,
diff --git a/sfe_ipv6_tcp.c b/sfe_ipv6_tcp.c
index f70fea5..11c81ba 100644
--- a/sfe_ipv6_tcp.c
+++ b/sfe_ipv6_tcp.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine file for IPv6 TCP
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -474,46 +474,6 @@
 	}
 
 	/*
-	 * For PPPoE packets, match server MAC and session id
-	 */
-	if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
-		struct pppoe_hdr *ph;
-		struct ethhdr *eth;
-
-		if (unlikely(!l2_info) || unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
-			return 0;
-		}
-
-		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
-		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
-
-		if (unlikely(cm->pppoe_session_id != htons(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE sessions did not match \n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
-			return 0;
-		}
-		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
-	} else if (unlikely(l2_info) && unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-
-		/*
-		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
-		 */
-		rcu_read_unlock();
-		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
-		sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
-		return 0;
-	}
-
-	/*
-	 * From this point on we're good to modify the packet.
-	 */
-
-	/*
 	 * Check if skb was cloned. If it was, unshare it. Because
 	 * the data area is going to be written in this path and we don't want to
 	 * change the cloned skb's data section.
@@ -535,14 +495,55 @@
 	}
 
 	/*
+	 * For PPPoE packets, match server MAC and session id
+	 */
+	if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
+		struct pppoe_hdr *ph;
+		struct ethhdr *eth;
+
+		if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+			rcu_read_unlock();
+			DEBUG_TRACE("%px: PPPoE header not present in packet for PPPoE rule\n", skb);
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+			return 0;
+		}
+
+		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
+		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
+
+		if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
+			DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match \n",
+							skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+			rcu_read_unlock();
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+			return 0;
+		}
+		skb->protocol = htons(l2_info->protocol);
+		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
+
+	} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+
+		/*
+		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+		 */
+		rcu_read_unlock();
+		DEBUG_TRACE("%px: CME doesn't contain PPPOE flag but packet has PPPoE header\n", skb);
+		sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_NOT_SET_IN_CME);
+		return 0;
+	}
+
+	/*
+	 * From this point on we're good to modify the packet.
+	 */
+
+	/*
 	 * For PPPoE flows, add PPPoE header before L2 header is added.
 	 */
 	if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
 		if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IPV6))) {
 			rcu_read_unlock();
 			DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
-			return 0;
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_NO_HEADROOM);
 		}
 		this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
 	}
@@ -639,7 +640,7 @@
 	 */
 	if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
 		if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
-			dev_hard_header(skb, xmit_dev, ETH_P_IPV6,
+			dev_hard_header(skb, xmit_dev, ntohs(skb->protocol),
 					cm->xmit_dest_mac, cm->xmit_src_mac, len);
 		} else {
 			/*
@@ -647,7 +648,7 @@
 			 */
 			struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
 
-			eth->h_proto = htons(ETH_P_IPV6);
+			eth->h_proto = skb->protocol;
 			ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
 			ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
 		}
diff --git a/sfe_ipv6_tcp.h b/sfe_ipv6_tcp.h
index 069dc41..5aecc3f 100644
--- a/sfe_ipv6_tcp.h
+++ b/sfe_ipv6_tcp.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine header file for IPv6 TCP
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe_ipv6_udp.c b/sfe_ipv6_udp.c
index 5ddaef6..c5e522d 100644
--- a/sfe_ipv6_udp.c
+++ b/sfe_ipv6_udp.c
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine file for IPv6 UDP
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -266,45 +266,6 @@
 	}
 
 	/*
-	 * For PPPoE packets, match server MAC and session id
-	 */
-	if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
-		struct pppoe_hdr *ph;
-		struct ethhdr *eth;
-
-		if (unlikely(!l2_info) || unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
-			return 0;
-		}
-
-		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
-		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
-		if (unlikely(cm->pppoe_session_id != htons(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
-			rcu_read_unlock();
-			DEBUG_TRACE("%px: PPPoE sessions did not match \n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
-			return 0;
-		}
-		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
-
-	} else if (unlikely(l2_info) && unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
-
-		/*
-		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
-		 */
-		rcu_read_unlock();
-		DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
-		sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
-		return 0;
-	}
-
-	/*
-	 * From this point on we're good to modify the packet.
-	 */
-
-	/*
 	 * Check if skb was cloned. If it was, unshare it. Because
 	 * the data area is going to be written in this path and we don't want to
 	 * change the cloned skb's data section.
@@ -326,14 +287,54 @@
 	}
 
 	/*
+	 * For PPPoE packets, match server MAC and session id
+	 */
+	if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP)) {
+		struct pppoe_hdr *ph;
+		struct ethhdr *eth;
+
+		if (unlikely(!sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+			rcu_read_unlock();
+			DEBUG_TRACE("%px: PPPoE header not present in packet for PPPoE rule\n", skb);
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
+			return 0;
+		}
+
+		ph = (struct pppoe_hdr *)(skb->head + sfe_l2_pppoe_hdr_offset_get(l2_info));
+		eth = (struct ethhdr *)(skb->head + sfe_l2_hdr_offset_get(l2_info));
+		if (unlikely(cm->pppoe_session_id != ntohs(ph->sid)) || unlikely(!(ether_addr_equal((u8*)cm->pppoe_remote_mac, (u8 *)eth->h_source)))) {
+			DEBUG_TRACE("%px: PPPoE sessions with session IDs %d and %d or server MACs %pM and %pM did not match\n",
+							skb, cm->pppoe_session_id, htons(ph->sid), cm->pppoe_remote_mac, eth->h_source);
+			rcu_read_unlock();
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INVALID_PPPOE_SESSION);
+			return 0;
+		}
+		skb->protocol = htons(l2_info->protocol);
+		this_cpu_inc(si->stats_pcpu->pppoe_decap_packets_forwarded64);
+
+	} else if (unlikely(sfe_l2_parse_flag_check(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS))) {
+
+		/*
+		 * If packet contains PPPOE header but CME doesn't contain PPPoE flag yet we are exceptioning the packet to linux
+		 */
+		rcu_read_unlock();
+		DEBUG_TRACE("%px: PPPoE is not parsed\n", skb);
+		sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_INCORRECT_PPPOE_PARSING);
+		return 0;
+	}
+
+	/*
+	 * From this point on we're good to modify the packet.
+	 */
+
+	/*
 	 * For PPPoE flows, add PPPoE header before L2 header is added.
 	 */
 	if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
 		if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IPV6))) {
 			rcu_read_unlock();
 			DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
-			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
-			return 0;
+			sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_NO_HEADROOM);
 		}
 		this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
 	}
@@ -473,14 +474,14 @@
 	 */
 	if (likely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_L2_HDR)) {
 		if (unlikely(!(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_WRITE_FAST_ETH_HDR))) {
-			dev_hard_header(skb, xmit_dev, ETH_P_IPV6,
+			dev_hard_header(skb, xmit_dev, ntohs(skb->protocol),
 					cm->xmit_dest_mac, cm->xmit_src_mac, len);
 		} else {
 			/*
 			 * For the simple case we write this really fast.
 			 */
 			struct ethhdr *eth = (struct ethhdr *)__skb_push(skb, ETH_HLEN);
-			eth->h_proto = htons(ETH_P_IPV6);
+			eth->h_proto = skb->protocol;
 			ether_addr_copy((u8 *)eth->h_dest, (u8 *)cm->xmit_dest_mac);
 			ether_addr_copy((u8 *)eth->h_source, (u8 *)cm->xmit_src_mac);
 		}
diff --git a/sfe_ipv6_udp.h b/sfe_ipv6_udp.h
index 2899be6..edab1f6 100644
--- a/sfe_ipv6_udp.h
+++ b/sfe_ipv6_udp.h
@@ -3,7 +3,7 @@
  *	Shortcut forwarding engine header file for IPv6 UDP
  *
  * Copyright (c) 2015-2016, 2019-2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
diff --git a/sfe_pppoe.c b/sfe_pppoe.c
index 89e4a90..4f9341e 100644
--- a/sfe_pppoe.c
+++ b/sfe_pppoe.c
@@ -2,7 +2,7 @@
  * sfe_pppoe.c
  *     API for shortcut forwarding engine PPPoE flows
  *
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -36,66 +36,71 @@
 {
 	u16 *l2_header;
 	struct pppoe_hdr *ph;
+	struct sfe_ppp_hdr *ppp;
 	u16 *l3_header = (u16 *)skb->data;
 
 	/*
-	 * Check that we have space for PPPoE header and PPP header (2 bytes)
+	 * Check that we have space for PPPoE header, PPP header (2 bytes) and Ethernet header
+	 * TODO: Calculate the l2_hdr_len during rule push so that this is avoided in datapath
 	 */
-	if (unlikely(!pskb_may_pull(skb, SFE_PPPOE_HEADER_SIZE))) {
-		DEBUG_TRACE("%px: Not enough headroom for PPPoE header \n", skb);
+	if (unlikely(skb_headroom(skb) < ((sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)) + ETH_HLEN))) {
+		DEBUG_TRACE("%px: Not enough headroom for PPPoE header\n", skb);
 		return false;
 	}
 
 	/*
-	 * PPPoE header (8 bytes) + PPP header (2 bytes)
+	 * PPPoE header (6 bytes) + PPP header (2 bytes)
 	 *
-	 * Hence move by 10 bytes to accomodate PPPoE header
+	 * Hence move by 8 bytes to accomodate PPPoE header
 	 */
-	l2_header = l3_header - (SFE_PPPOE_HEADER_SIZE / 2);
+	l2_header = l3_header - ((sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)) / 2);
 
 	/*
 	 * Headers in skb will look like in below sequence
-	 *	| PPPoE hdr(10 bytes) | L3 hdr |
+	 *	| PPPoE hdr(6 bytes) | PPP hdr (2 bytes) | L3 hdr |
+	 *
+	 *	The length field in the PPPoE header indicates the length of the PPPoE payload which
+	 *	consists of a 2-byte PPP header plus a skb->len.
 	 */
 	ph = (struct pppoe_hdr *)l2_header;
 	ph->ver = 1;
 	ph->type = 1;
 	ph->code = 0;
-	ph->sid = pppoe_session_id;
-	ph->length = skb->len;
-	skb->protocol = cpu_to_be16(ETH_P_PPP_SES);
+	ph->sid = htons(pppoe_session_id);
+	ph->length = htons(skb->len + sizeof(struct sfe_ppp_hdr));
+	skb->protocol = htons(ETH_P_PPP_SES);
 
 	/*
 	 * Insert the PPP header protocol
 	 */
-	*(l2_header + 4) = ppp_protocol;
+	ppp = (struct sfe_ppp_hdr *)(l2_header + (sizeof(struct pppoe_hdr) / 2));
+	ppp->protocol = htons(ppp_protocol);
 
 	/*
 	 * L2 header offset will point to PPPoE header,
-	 * since sfe_ipv4_recv_tcp/udp() does skb_push by ETH_HLEN before adding L2 header.
 	 */
-	__skb_push(skb, SFE_PPPOE_HEADER_SIZE);
+	__skb_push(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
 
 	return true;
 }
 
 /*
- * sfe_pppoe_validate_hdr()
- *	Validate PPPoE header
+ * sfe_pppoe_parse_hdr()
+ *	Parse PPPoE header
  *
  * Returns true if the packet is good for further processing.
  */
-bool sfe_pppoe_validate_hdr(struct sk_buff *skb, struct sfe_l2_info *l2_info)
+bool sfe_pppoe_parse_hdr(struct sk_buff *skb, struct sfe_l2_info *l2_info)
 {
-	u16 ppp_protocol;
 	unsigned int len;
 	int pppoe_len;
+	struct sfe_ppp_hdr *ppp;
 	struct pppoe_hdr *ph = (struct pppoe_hdr *)skb->data;
 
 	/*
 	 * Check that we have space for PPPoE header here.
 	 */
-	if (unlikely(!pskb_may_pull(skb, SFE_PPPOE_HEADER_SIZE))) {
+	if (unlikely(!pskb_may_pull(skb, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr))))) {
 		DEBUG_TRACE("%px: packet too short for PPPoE header\n", skb);
 		return false;
 	}
@@ -107,28 +112,32 @@
 		return false;
 	}
 
-	ppp_protocol = htons((*(uint16_t *)((u8 *)ph + sizeof(*ph))));
+	ppp = (struct sfe_ppp_hdr *)((u8*)ph + sizeof(*ph));
 
 	/*
 	 * Converting PPP protocol values to ether type protocol values
 	 */
-	switch(ppp_protocol) {
+	switch(ntohs(ppp->protocol)) {
 	case PPP_IP:
 		sfe_l2_protocol_set(l2_info, ETH_P_IP);
-		return true;
+		break;
 
 	case PPP_IPV6:
 		sfe_l2_protocol_set(l2_info, ETH_P_IPV6);
-		return true;
+		break;
 
 	case PPP_LCP:
 		DEBUG_TRACE("%px: LCP packets are not supported in SFE\n", skb);
 		return false;
 
 	default:
-		DEBUG_TRACE("%px: Unsupported protocol : %d in PPP header \n", skb, ppp_protocol);
-		break;
+		DEBUG_TRACE("%px: Unsupported protocol : %d in PPP header\n", skb, ntohs(ppp->protocol));
+		return false;
 	}
 
-	return false;
+	sfe_l2_parse_flag_set(l2_info, SFE_L2_PARSE_FLAGS_PPPOE_INGRESS);
+	sfe_l2_pppoe_hdr_offset_set(l2_info, (skb->data - skb->head));
+	sfe_l2_hdr_size_set(l2_info, (sizeof(struct pppoe_hdr) + sizeof(struct sfe_ppp_hdr)));
+
+	return true;
 }
diff --git a/sfe_pppoe.h b/sfe_pppoe.h
index c5f97b2..4190b4e 100644
--- a/sfe_pppoe.h
+++ b/sfe_pppoe.h
@@ -2,7 +2,7 @@
  * sfe_pppoe.h
  *	Shortcut flow acceleration for PPPoE flow
  *
- * Copyright (c) 2021,2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -16,10 +16,13 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+
 #include <linux/ppp_defs.h>
 #include <linux/if_pppox.h>
 
-#define SFE_PPPOE_HEADER_SIZE (sizeof(struct pppoe_hdr) + 2)
+struct sfe_ppp_hdr {
+	u16 protocol;
+};
 
 bool sfe_pppoe_add_header(struct sk_buff *skb, u16 pppoe_session_id, u16 ppp_protocol);
-bool sfe_pppoe_validate_hdr(struct sk_buff *skb, struct sfe_l2_info *l2_info);
+bool sfe_pppoe_parse_hdr(struct sk_buff *skb, struct sfe_l2_info *l2_info);