diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index 9ea95c3..93a92a0 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -290,10 +290,6 @@ static inline int packet_parse_not_complete(odp_packet_hdr_t *pkt_hdr)
 }
 
 /* Forward declarations */
-int _odp_packet_copy_to_packet(odp_packet_t srcpkt, uint32_t srcoffset,
-			       odp_packet_t dstpkt, uint32_t dstoffset,
-			       uint32_t len);
-
 void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
 
 odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse);
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 7448575..f603bcd 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -731,11 +731,11 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
 	if (params->pkt != params->out_pkt) {
 		if (odp_unlikely(ODP_PACKET_INVALID == params->out_pkt))
 			ODP_ABORT();
-		(void)_odp_packet_copy_to_packet(params->pkt,
-						 0,
-						 params->out_pkt,
-						 0,
-						 odp_packet_len(params->pkt));
+		(void)odp_packet_copy_from_pkt(params->out_pkt,
+					       0,
+					       params->pkt,
+					       0,
+					       odp_packet_len(params->pkt));
 		_odp_packet_copy_md_to_packet(params->pkt, params->out_pkt);
 		odp_packet_free(params->pkt);
 		params->pkt = ODP_PACKET_INVALID;
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 7ec2c83..a314942 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -628,11 +628,9 @@ int odp_packet_add_data(odp_packet_t *pkt_ptr, uint32_t offset, uint32_t len)
 	if (newpkt == ODP_PACKET_INVALID)
 		return -1;
 
-	if (_odp_packet_copy_to_packet(pkt, 0,
-				       newpkt, 0, offset) != 0 ||
-	    _odp_packet_copy_to_packet(pkt, offset, newpkt,
-				       offset + len,
-				       pktlen - offset) != 0) {
+	if (odp_packet_copy_from_pkt(newpkt, 0, pkt, 0, offset) != 0 ||
+	    odp_packet_copy_from_pkt(newpkt, offset + len, pkt, offset,
+				     pktlen - offset) != 0) {
 		odp_packet_free(newpkt);
 		return -1;
 	}
@@ -659,11 +657,9 @@ int odp_packet_rem_data(odp_packet_t *pkt_ptr, uint32_t offset, uint32_t len)
 	if (newpkt == ODP_PACKET_INVALID)
 		return -1;
 
-	if (_odp_packet_copy_to_packet(pkt, 0,
-				       newpkt, 0, offset) != 0 ||
-	    _odp_packet_copy_to_packet(pkt, offset + len,
-				       newpkt, offset,
-				       pktlen - offset - len) != 0) {
+	if (odp_packet_copy_from_pkt(newpkt, 0, pkt, 0, offset) != 0 ||
+	    odp_packet_copy_from_pkt(newpkt, offset, pkt, offset + len,
+				     pktlen - offset - len) != 0) {
 		odp_packet_free(newpkt);
 		return -1;
 	}
@@ -700,8 +696,8 @@ odp_packet_t odp_packet_copy(odp_packet_t pkt, odp_pool_t pool)
 		memcpy(newstart, srcstart,
 		       sizeof(odp_packet_hdr_t) - meta_offset);
 
-		if (_odp_packet_copy_to_packet(pkt, 0,
-					       newpkt, 0, pktlen) != 0) {
+		if (odp_packet_copy_from_pkt(newpkt, 0, pkt, 0,
+					     pktlen) != 0) {
 			odp_packet_free(newpkt);
 			newpkt = ODP_PACKET_INVALID;
 		}
@@ -758,6 +754,59 @@ int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset,
 	return 0;
 }
 
+int odp_packet_copy_from_pkt(odp_packet_t dst, uint32_t dst_offset,
+			     odp_packet_t src, uint32_t src_offset,
+			     uint32_t len)
+{
+	odp_packet_hdr_t *dst_hdr = odp_packet_hdr(dst);
+	odp_packet_hdr_t *src_hdr = odp_packet_hdr(src);
+	void *dst_map;
+	void *src_map;
+	uint32_t cpylen, minseg;
+	uint32_t dst_seglen = 0; /* GCC */
+	uint32_t src_seglen = 0; /* GCC */
+	int overlap;
+
+	if (dst_offset + len > dst_hdr->frame_len ||
+	    src_offset + len > src_hdr->frame_len)
+		return -1;
+
+	overlap = (dst_hdr == src_hdr &&
+		   ((dst_offset <= src_offset &&
+		     dst_offset + len >= src_offset) ||
+		    (src_offset <= dst_offset &&
+		     src_offset + len >= dst_offset)));
+
+	if (overlap && src_offset < dst_offset) {
+		odp_packet_t temp =
+			odp_packet_copy_part(src, src_offset, len,
+					     odp_packet_pool(src));
+		if (temp == ODP_PACKET_INVALID)
+			return -1;
+		odp_packet_copy_from_pkt(dst, dst_offset, temp, 0, len);
+		odp_packet_free(temp);
+		return 0;
+	}
+
+	while (len > 0) {
+		dst_map = packet_map(dst_hdr, dst_offset, &dst_seglen);
+		src_map = packet_map(src_hdr, src_offset, &src_seglen);
+
+		minseg = dst_seglen > src_seglen ? src_seglen : dst_seglen;
+		cpylen = len > minseg ? minseg : len;
+
+		if (overlap)
+			memmove(dst_map, src_map, cpylen);
+		else
+			memcpy(dst_map, src_map, cpylen);
+
+		dst_offset += cpylen;
+		src_offset += cpylen;
+		len        -= cpylen;
+	}
+
+	return 0;
+}
 /*
  *
  * Debugging
@@ -833,38 +882,6 @@ void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt)
 	copy_packet_parser_metadata(srchdr, dsthdr);
 }
 
-int _odp_packet_copy_to_packet(odp_packet_t srcpkt, uint32_t srcoffset,
-			       odp_packet_t dstpkt, uint32_t dstoffset,
-			       uint32_t len)
-{
-	odp_packet_hdr_t *srchdr = odp_packet_hdr(srcpkt);
-	odp_packet_hdr_t *dsthdr = odp_packet_hdr(dstpkt);
-	void *srcmap;
-	void *dstmap;
-	uint32_t cpylen, minseg;
-	uint32_t srcseglen = 0; /* GCC */
-	uint32_t dstseglen = 0; /* GCC */
-
-	if (srcoffset + len > srchdr->frame_len ||
-	    dstoffset + len > dsthdr->frame_len)
-		return -1;
-
-	while (len > 0) {
-		srcmap = packet_map(srchdr, srcoffset, &srcseglen);
-		dstmap = packet_map(dsthdr, dstoffset, &dstseglen);
-
-		minseg = dstseglen > srcseglen ? srcseglen : dstseglen;
-		cpylen = len > minseg ? minseg : len;
-		memcpy(dstmap, srcmap, cpylen);
-
-		srcoffset += cpylen;
-		dstoffset += cpylen;
-		len       -= cpylen;
-	}
-
-	return 0;
-}
-
 /**
  * Parser helper function for IPv4
  */
