diff --git a/include/odp_packet.h b/include/odp_packet.h
index 4de4db2..0b693d9 100644
--- a/include/odp_packet.h
+++ b/include/odp_packet.h
@@ -27,6 +27,8 @@ extern "C" {
 typedef uint32_t odp_packet_t;
 
 #define ODP_PACKET_INVALID ODP_BUFFER_INVALID
+#define ODP_PACKET_OFFSET_INVALID ((size_t)-1)
+
 
 /**
  * Initialize the packet
@@ -74,21 +76,41 @@ void odp_packet_set_len(odp_packet_t pkt, size_t len);
 size_t odp_packet_get_len(odp_packet_t pkt);
 
 /**
- * Get pointer to the start of the packet buffer
+ * Get address to the start of the packet buffer
  *
- * The start address of the packet buffer is not necessarily the same as the
- * start address of a received frame, e.g. an eth frame may be offset by 2 or 6
+ * The address of the packet buffer is not necessarily the same as the start
+ * address of the received frame, e.g. an eth frame may be offset by 2 or 6
  * bytes to ensure 32 or 64-bit alignment of the IP header.
- * Use odp_packet_l2(pkt) to get the start address of a received frame.
+ * Use odp_packet_l2(pkt) to get the start address of a received valid frame
+ * or odp_packet_start(pkt) to get the start address even if no valid L2 header
+ * could be found.
  *
  * @param pkt  Packet handle
  *
  * @return  Pointer to the start of the packet buffer
  *
- * @see odp_packet_l2()
+ * @see odp_packet_l2(), odp_packet_start()
  */
 uint8_t *odp_packet_buf_addr(odp_packet_t pkt);
 
+/**
+ * Get pointer to the start of the received frame
+ *
+ * The address of the packet buffer is not necessarily the same as the start
+ * address of the received frame, e.g. an eth frame may be offset by 2 or 6
+ * bytes to ensure 32 or 64-bit alignment of the IP header.
+ * Use odp_packet_l2(pkt) to get the start address of a received valid eth frame
+ *
+ * odp_packet_start() will always return a pointer to the start of the frame,
+ * even if the frame is unrecognized and no valid L2 header could be found.
+ *
+ * @param pkt  Packet handle
+ *
+ * @return  Pointer to the start of the received frame
+ *
+ * @see odp_packet_l2(), odp_packet_buf_addr()
+ */
+uint8_t *odp_packet_start(odp_packet_t pkt);
 
 /**
  * Get pointer to the start of the L2 frame
@@ -98,9 +120,9 @@ uint8_t *odp_packet_buf_addr(odp_packet_t pkt);
  *
  * @param pkt  Packet handle
  *
- * @return  Pointer to L2 header
+ * @return  Pointer to L2 header or NULL if not found
  *
- * @see odp_packet_buf_addr()
+ * @see odp_packet_buf_addr(), odp_packet_start()
  */
 uint8_t *odp_packet_l2(odp_packet_t pkt);
 
@@ -109,7 +131,7 @@ uint8_t *odp_packet_l2(odp_packet_t pkt);
  *
  * @param pkt  Packet handle
  *
- * @return  L2 byte offset
+ * @return  L2 byte offset or ODP_PACKET_OFFSET_INVALID if not found
  */
 size_t odp_packet_l2_offset(odp_packet_t pkt);
 
@@ -127,7 +149,7 @@ void odp_packet_set_l2_offset(odp_packet_t pkt, size_t offset);
  *
  * @param pkt  Packet handle
  *
- * @return  Pointer to L3 packet
+ * @return  Pointer to L3 packet or NULL if not found
  *
  */
 uint8_t *odp_packet_l3(odp_packet_t pkt);
@@ -137,7 +159,7 @@ uint8_t *odp_packet_l3(odp_packet_t pkt);
  *
  * @param pkt  Packet handle
  *
- * @return  L3 byte offset
+ * @return  L3 byte offset or ODP_PACKET_OFFSET_INVALID if not found
  */
 size_t odp_packet_l3_offset(odp_packet_t pkt);
 
@@ -155,7 +177,7 @@ void odp_packet_set_l3_offset(odp_packet_t pkt, size_t offset);
  *
  * @param pkt  Packet handle
  *
- * @return  Pointer to L4 packet
+ * @return  Pointer to L4 packet or NULL if not found
  *
  */
 uint8_t *odp_packet_l4(odp_packet_t pkt);
@@ -165,7 +187,7 @@ uint8_t *odp_packet_l4(odp_packet_t pkt);
  *
  * @param pkt  Packet handle
  *
- * @return  L4 byte offset
+ * @return  L4 byte offset or ODP_PACKET_OFFSET_INVALID if not found
  */
 size_t odp_packet_l4_offset(odp_packet_t pkt);
 
diff --git a/platform/linux-generic/source/odp_packet.c b/platform/linux-generic/source/odp_packet.c
index 6ee2c5b..060d82e 100644
--- a/platform/linux-generic/source/odp_packet.c
+++ b/platform/linux-generic/source/odp_packet.c
@@ -25,6 +25,10 @@ void odp_packet_init(odp_packet_t pkt)
 	start = (uint8_t *)pkt_hdr + start_offset;
 	len = ODP_OFFSETOF(odp_packet_hdr_t, payload) - start_offset;
 	memset(start, 0, len);
+
+	pkt_hdr->l2_offset = (uint32_t) ODP_PACKET_OFFSET_INVALID;
+	pkt_hdr->l3_offset = (uint32_t) ODP_PACKET_OFFSET_INVALID;
+	pkt_hdr->l4_offset = (uint32_t) ODP_PACKET_OFFSET_INVALID;
 }
 
 odp_packet_t odp_packet_from_buffer(odp_buffer_t buf)
@@ -52,10 +56,20 @@ uint8_t *odp_packet_buf_addr(odp_packet_t pkt)
 	return odp_buffer_addr(odp_buffer_from_packet(pkt));
 }
 
+uint8_t *odp_packet_start(odp_packet_t pkt)
+{
+	return odp_packet_buf_addr(pkt) + odp_packet_hdr(pkt)->frame_offset;
+}
+
 
 uint8_t *odp_packet_l2(odp_packet_t pkt)
 {
-	return odp_packet_buf_addr(pkt) + odp_packet_l2_offset(pkt);
+	const size_t offset = odp_packet_l2_offset(pkt);
+
+	if (odp_unlikely(offset == ODP_PACKET_OFFSET_INVALID))
+		return NULL;
+
+	return odp_packet_buf_addr(pkt) + offset;
 }
 
 size_t odp_packet_l2_offset(odp_packet_t pkt)
@@ -71,7 +85,12 @@ void odp_packet_set_l2_offset(odp_packet_t pkt, size_t offset)
 
 uint8_t *odp_packet_l3(odp_packet_t pkt)
 {
-	return odp_packet_buf_addr(pkt) + odp_packet_l3_offset(pkt);
+	const size_t offset = odp_packet_l3_offset(pkt);
+
+	if (odp_unlikely(offset == ODP_PACKET_OFFSET_INVALID))
+		return NULL;
+
+	return odp_packet_buf_addr(pkt) + offset;
 }
 
 size_t odp_packet_l3_offset(odp_packet_t pkt)
@@ -87,7 +106,12 @@ void odp_packet_set_l3_offset(odp_packet_t pkt, size_t offset)
 
 uint8_t *odp_packet_l4(odp_packet_t pkt)
 {
-	return odp_packet_buf_addr(pkt) + odp_packet_l4_offset(pkt);
+	const size_t offset = odp_packet_l4_offset(pkt);
+
+	if (odp_unlikely(offset == ODP_PACKET_OFFSET_INVALID))
+		return NULL;
+
+	return odp_packet_buf_addr(pkt) + offset;
 }
 
 size_t odp_packet_l4_offset(odp_packet_t pkt)
