+static struct rte_mbuf *
+nix_sec_attach_frags(const struct cpt_parse_hdr_s *hdr,
+ struct cn10k_inb_priv_data *inb_priv,
+ const uint64_t mbuf_init)
+{
+ struct rte_mbuf *head, *mbuf, *mbuf_prev;
+ uint32_t offset = hdr->w2.fi_offset;
+ union nix_rx_parse_u *frag_rx;
+ struct cpt_frag_info_s *finfo;
+ uint64_t *frag_ptr = NULL;
+ uint64_t ol_flags;
+ uint16_t frag_size;
+ uint16_t rlen;
+ uint64_t *wqe;
+ int off;
+
+ off = inb_priv->reass_dynfield_off;
+ ol_flags = BIT_ULL(inb_priv->reass_dynflag_bit);
+ ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD;
+
+ /* offset of 0 implies 256B, otherwise it implies offset*8B */
+ offset = (((offset - 1) & 0x1f) + 1) * 8;
+ finfo = RTE_PTR_ADD(hdr, offset + hdr->w2.fi_pad);
+
+ /* Frag-0: */
+ wqe = (uint64_t *)(rte_be_to_cpu_64(hdr->wqe_ptr));
+ rlen = ((*(wqe + 10)) >> 16) & 0xFFFF;
+
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+ frag_size = rlen + frag_rx->lcptr - frag_rx->laptr;
+ frag_rx->pkt_lenm1 = frag_size - 1;
+
+ mbuf = (struct rte_mbuf *)((uintptr_t)wqe - sizeof(struct rte_mbuf));
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init;
+ mbuf->data_len = frag_size;
+ mbuf->pkt_len = frag_size;
+ mbuf->ol_flags = ol_flags;
+ mbuf->next = NULL;
+ head = mbuf;
+ mbuf_prev = mbuf;
+ /* Update dynamic field with userdata */
+ *rte_security_dynfield(mbuf) = (uint64_t)inb_priv->userdata;
+
+ cnxk_ip_reassembly_dynfield(head, off)->nb_frags = hdr->w0.num_frags - 1;
+ cnxk_ip_reassembly_dynfield(head, off)->next_frag = NULL;
+
+ /* Frag-1: */
+ if (hdr->w0.num_frags > 1) {
+ wqe = (uint64_t *)(rte_be_to_cpu_64(hdr->frag1_wqe_ptr));
+ rlen = ((*(wqe + 10)) >> 16) & 0xFFFF;
+
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+ frag_size = rlen + frag_rx->lcptr - frag_rx->laptr;
+ frag_rx->pkt_lenm1 = frag_size - 1;
+
+ mbuf = (struct rte_mbuf *)((uintptr_t)wqe -
+ sizeof(struct rte_mbuf));
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init;
+ mbuf->data_len = frag_size;
+ mbuf->pkt_len = frag_size;
+ mbuf->ol_flags = ol_flags;
+ mbuf->next = NULL;
+
+ /* Update dynamic field with userdata */
+ *rte_security_dynfield(mbuf) = (uint64_t)inb_priv->userdata;
+
+ cnxk_ip_reassembly_dynfield(mbuf, off)->nb_frags =
+ hdr->w0.num_frags - 2;
+ cnxk_ip_reassembly_dynfield(mbuf, off)->next_frag = NULL;
+ cnxk_ip_reassembly_dynfield(mbuf_prev, off)->next_frag = mbuf;
+ mbuf_prev = mbuf;
+ }
+
+ /* Frag-2: */
+ if (hdr->w0.num_frags > 2) {
+ frag_ptr = (uint64_t *)(finfo + 1);
+ wqe = (uint64_t *)(rte_be_to_cpu_64(*frag_ptr));
+ rlen = ((*(wqe + 10)) >> 16) & 0xFFFF;
+
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+ frag_size = rlen + frag_rx->lcptr - frag_rx->laptr;
+ frag_rx->pkt_lenm1 = frag_size - 1;
+
+ mbuf = (struct rte_mbuf *)((uintptr_t)wqe -
+ sizeof(struct rte_mbuf));
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init;
+ mbuf->data_len = frag_size;
+ mbuf->pkt_len = frag_size;
+ mbuf->ol_flags = ol_flags;
+ mbuf->next = NULL;
+
+ /* Update dynamic field with userdata */
+ *rte_security_dynfield(mbuf) = (uint64_t)inb_priv->userdata;
+
+ cnxk_ip_reassembly_dynfield(mbuf, off)->nb_frags =
+ hdr->w0.num_frags - 3;
+ cnxk_ip_reassembly_dynfield(mbuf, off)->next_frag = NULL;
+ cnxk_ip_reassembly_dynfield(mbuf_prev, off)->next_frag = mbuf;
+ mbuf_prev = mbuf;
+ }
+
+ /* Frag-3: */
+ if (hdr->w0.num_frags > 3) {
+ wqe = (uint64_t *)(rte_be_to_cpu_64(*(frag_ptr + 1)));
+ rlen = ((*(wqe + 10)) >> 16) & 0xFFFF;
+
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+ frag_size = rlen + frag_rx->lcptr - frag_rx->laptr;
+ frag_rx->pkt_lenm1 = frag_size - 1;
+
+ mbuf = (struct rte_mbuf *)((uintptr_t)wqe -
+ sizeof(struct rte_mbuf));
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init;
+ mbuf->data_len = frag_size;
+ mbuf->pkt_len = frag_size;
+ mbuf->ol_flags = ol_flags;
+ mbuf->next = NULL;
+
+ /* Update dynamic field with userdata */
+ *rte_security_dynfield(mbuf) = (uint64_t)inb_priv->userdata;
+
+ cnxk_ip_reassembly_dynfield(mbuf, off)->nb_frags =
+ hdr->w0.num_frags - 4;
+ cnxk_ip_reassembly_dynfield(mbuf, off)->next_frag = NULL;
+ cnxk_ip_reassembly_dynfield(mbuf_prev, off)->next_frag = mbuf;
+ }
+ return head;
+}
+
+static struct rte_mbuf *
+nix_sec_reassemble_frags(const struct cpt_parse_hdr_s *hdr, uint64_t cq_w1,
+ uint64_t cq_w5, uint64_t mbuf_init)
+{
+ uint32_t fragx_sum, pkt_hdr_len, l3_hdr_size;
+ uint32_t offset = hdr->w2.fi_offset;
+ union nix_rx_parse_u *inner_rx;
+ uint16_t rlen, data_off, b_off;
+ union nix_rx_parse_u *frag_rx;
+ struct cpt_frag_info_s *finfo;
+ struct rte_mbuf *head, *mbuf;
+ uint64_t *frag_ptr = NULL;
+ rte_iova_t *inner_iova;
+ uint16_t frag_size;
+ uint64_t *wqe;
+
+ /* Base data offset */
+ b_off = mbuf_init & 0xFFFFUL;
+ mbuf_init &= ~0xFFFFUL;
+
+ /* offset of 0 implies 256B, otherwise it implies offset*8B */
+ offset = (((offset - 1) & 0x1f) + 1) * 8;
+ finfo = RTE_PTR_ADD(hdr, offset + hdr->w2.fi_pad);
+
+ /* Frag-0: */
+ wqe = (uint64_t *)rte_be_to_cpu_64(hdr->wqe_ptr);
+ inner_rx = (union nix_rx_parse_u *)(wqe + 1);
+ inner_iova = (rte_iova_t *)*(wqe + 9);
+
+ /* Update only the upper 28-bits from meta pkt parse info */
+ *((uint64_t *)inner_rx) = ((*((uint64_t *)inner_rx) & ((1ULL << 36) - 1)) |
+ (cq_w1 & ~((1ULL << 36) - 1)));
+
+ rlen = ((*(wqe + 10)) >> 16) & 0xFFFF;
+ frag_size = rlen + ((cq_w5 >> 16) & 0xFF) - (cq_w5 & 0xFF);
+ fragx_sum = rte_be_to_cpu_16(finfo->w1.frag_size0);
+ pkt_hdr_len = frag_size - fragx_sum;
+
+ mbuf = (struct rte_mbuf *)((uintptr_t)wqe - sizeof(struct rte_mbuf));
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init | b_off;
+ mbuf->data_len = frag_size;
+ head = mbuf;
+
+ if (inner_rx->lctype == NPC_LT_LC_IP) {
+ struct rte_ipv4_hdr *hdr = (struct rte_ipv4_hdr *)
+ RTE_PTR_ADD(inner_iova, inner_rx->lcptr);
+
+ l3_hdr_size = (hdr->version_ihl & 0xf) << 2;
+ } else {
+ struct rte_ipv6_hdr *hdr = (struct rte_ipv6_hdr *)
+ RTE_PTR_ADD(inner_iova, inner_rx->lcptr);
+ size_t ext_len = sizeof(struct rte_ipv6_hdr);
+ uint8_t *nxt_hdr = (uint8_t *)hdr;
+ int nh = hdr->proto;
+
+ l3_hdr_size = 0;
+ while (nh != -EINVAL) {
+ nxt_hdr += ext_len;
+ l3_hdr_size += ext_len;
+ nh = rte_ipv6_get_next_ext(nxt_hdr, nh, &ext_len);
+ }
+ }
+
+ /* Frag-1: */
+ wqe = (uint64_t *)(rte_be_to_cpu_64(hdr->frag1_wqe_ptr));
+ frag_size = rte_be_to_cpu_16(finfo->w1.frag_size1);
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+
+ mbuf->next = (struct rte_mbuf *)((uintptr_t)wqe - sizeof(struct rte_mbuf));
+ mbuf = mbuf->next;
+ data_off = b_off + frag_rx->lcptr + l3_hdr_size;
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init | data_off;
+ mbuf->data_len = frag_size;
+ fragx_sum += frag_size;
+
+ /* Frag-2: */
+ if (hdr->w0.num_frags > 2) {
+ frag_ptr = (uint64_t *)(finfo + 1);
+ wqe = (uint64_t *)(rte_be_to_cpu_64(*frag_ptr));
+ frag_size = rte_be_to_cpu_16(finfo->w1.frag_size2);
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+
+ mbuf->next = (struct rte_mbuf *)((uintptr_t)wqe - sizeof(struct rte_mbuf));
+ mbuf = mbuf->next;
+ data_off = b_off + frag_rx->lcptr + l3_hdr_size;
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init | data_off;
+ mbuf->data_len = frag_size;
+ fragx_sum += frag_size;
+ }
+
+ /* Frag-3: */
+ if (hdr->w0.num_frags > 3) {
+ wqe = (uint64_t *)(rte_be_to_cpu_64(*(frag_ptr + 1)));
+ frag_size = rte_be_to_cpu_16(finfo->w1.frag_size3);
+ frag_rx = (union nix_rx_parse_u *)(wqe + 1);
+
+ mbuf->next = (struct rte_mbuf *)((uintptr_t)wqe - sizeof(struct rte_mbuf));
+ mbuf = mbuf->next;
+ data_off = b_off + frag_rx->lcptr + l3_hdr_size;
+ *(uint64_t *)(&mbuf->rearm_data) = mbuf_init | data_off;
+ mbuf->data_len = frag_size;
+ fragx_sum += frag_size;
+ }
+
+ if (inner_rx->lctype == NPC_LT_LC_IP) {
+ struct rte_ipv4_hdr *hdr = (struct rte_ipv4_hdr *)
+ RTE_PTR_ADD(inner_iova, inner_rx->lcptr);
+
+ hdr->fragment_offset = 0;
+ hdr->total_length = rte_cpu_to_be_16(fragx_sum + l3_hdr_size);
+ hdr->hdr_checksum = 0;
+ hdr->hdr_checksum = rte_ipv4_cksum(hdr);
+
+ inner_rx->pkt_lenm1 = pkt_hdr_len + fragx_sum - 1;
+ } else {
+ /* Remove the frag header by moving header 8 bytes forward */
+ struct rte_ipv6_hdr *hdr = (struct rte_ipv6_hdr *)
+ RTE_PTR_ADD(inner_iova, inner_rx->lcptr);
+
+ hdr->payload_len = rte_cpu_to_be_16(fragx_sum + l3_hdr_size -
+ 8 - sizeof(struct rte_ipv6_hdr));
+
+ rte_memcpy(rte_pktmbuf_mtod_offset(head, void *, 8),
+ rte_pktmbuf_mtod(head, void *),
+ inner_rx->lcptr + sizeof(struct rte_ipv6_hdr));
+
+ inner_rx->pkt_lenm1 = pkt_hdr_len + fragx_sum - 8 - 1;
+ head->data_len -= 8;
+ head->data_off += 8;
+ }
+ mbuf->next = NULL;
+ head->pkt_len = inner_rx->pkt_lenm1 + 1;
+ head->nb_segs = hdr->w0.num_frags;
+
+ return head;
+}
+