1 
2 /* SPDX-License-Identifier: BSD-3-Clause
3  * Copyright(C) 2019 Marvell International Ltd.
4  */
5 
6 #ifndef __OTX2_IPSEC_PO_OPS_H__
7 #define __OTX2_IPSEC_PO_OPS_H__
8 
9 #include <rte_crypto_sym.h>
10 #include <rte_security.h>
11 
12 #include "otx2_cryptodev.h"
13 #include "otx2_security.h"
14 
15 static __rte_always_inline int32_t
otx2_ipsec_po_out_rlen_get(struct otx2_sec_session_ipsec_lp * sess,uint32_t plen)16 otx2_ipsec_po_out_rlen_get(struct otx2_sec_session_ipsec_lp *sess,
17 			   uint32_t plen)
18 {
19 	uint32_t enc_payload_len;
20 
21 	enc_payload_len = RTE_ALIGN_CEIL(plen + sess->roundup_len,
22 			sess->roundup_byte);
23 
24 	return sess->partial_len + enc_payload_len;
25 }
26 
27 static __rte_always_inline struct cpt_request_info *
alloc_request_struct(char * maddr,void * cop,int mdata_len,enum rte_security_ipsec_tunnel_type tunnel_type)28 alloc_request_struct(char *maddr, void *cop, int mdata_len,
29 		     enum rte_security_ipsec_tunnel_type tunnel_type)
30 {
31 	struct cpt_request_info *req;
32 	struct cpt_meta_info *meta;
33 	uint8_t *resp_addr;
34 	uintptr_t *op;
35 
36 	meta = (void *)RTE_PTR_ALIGN((uint8_t *)maddr, 16);
37 
38 	op = (uintptr_t *)meta->deq_op_info;
39 	req = &meta->cpt_req;
40 	resp_addr = (uint8_t *)&meta->cpt_res;
41 
42 	req->completion_addr = (uint64_t *)((uint8_t *)resp_addr);
43 	*req->completion_addr = COMPLETION_CODE_INIT;
44 	req->comp_baddr = rte_mem_virt2iova(resp_addr);
45 	req->op = op;
46 
47 	op[0] = (uintptr_t)((uint64_t)meta | 1ull);
48 	op[1] = (uintptr_t)cop;
49 	op[2] = (uintptr_t)req;
50 	op[3] = mdata_len;
51 	op[4] = tunnel_type;
52 
53 	return req;
54 }
55 
56 static __rte_always_inline int
process_outb_sa(struct rte_crypto_op * cop,struct otx2_sec_session_ipsec_lp * sess,struct cpt_qp_meta_info * m_info,void ** prep_req)57 process_outb_sa(struct rte_crypto_op *cop,
58 	       struct otx2_sec_session_ipsec_lp *sess,
59 	       struct cpt_qp_meta_info *m_info, void **prep_req)
60 {
61 	uint32_t dlen, rlen, extend_head, extend_tail;
62 	struct rte_crypto_sym_op *sym_op = cop->sym;
63 	struct rte_mbuf *m_src = sym_op->m_src;
64 	struct otx2_ipsec_po_sa_ctl *ctl_wrd;
65 	struct cpt_request_info *req = NULL;
66 	struct otx2_ipsec_po_out_hdr *hdr;
67 	struct otx2_ipsec_po_out_sa *sa;
68 	int hdr_len, mdata_len, ret = 0;
69 	vq_cmd_word0_t word0;
70 	char *mdata, *data;
71 
72 	sa = &sess->out_sa;
73 	ctl_wrd = &sa->ctl;
74 	hdr_len = sizeof(*hdr);
75 
76 	dlen = rte_pktmbuf_pkt_len(m_src) + hdr_len;
77 	rlen = otx2_ipsec_po_out_rlen_get(sess, dlen - hdr_len);
78 
79 	extend_head = hdr_len + RTE_ETHER_HDR_LEN;
80 	extend_tail = rlen - dlen;
81 	mdata_len = m_info->lb_mlen + 8;
82 
83 	mdata = rte_pktmbuf_append(m_src, extend_tail + mdata_len);
84 	if (unlikely(mdata == NULL)) {
85 		otx2_err("Not enough tail room\n");
86 		ret = -ENOMEM;
87 		goto exit;
88 	}
89 
90 	mdata += extend_tail; /* mdata follows encrypted data */
91 	req = alloc_request_struct(mdata, (void *)cop, mdata_len,
92 		sess->tunnel_type);
93 
94 	data = rte_pktmbuf_prepend(m_src, extend_head);
95 	if (unlikely(data == NULL)) {
96 		otx2_err("Not enough head room\n");
97 		ret = -ENOMEM;
98 		goto exit;
99 	}
100 
101 	/*
102 	 * Move the Ethernet header, to insert otx2_ipsec_po_out_hdr prior
103 	 * to the IP header
104 	 */
105 	memcpy(data, data + hdr_len, RTE_ETHER_HDR_LEN);
106 
107 	hdr = (struct otx2_ipsec_po_out_hdr *)rte_pktmbuf_adj(m_src,
108 							RTE_ETHER_HDR_LEN);
109 
110 	if (ctl_wrd->enc_type == OTX2_IPSEC_FP_SA_ENC_AES_GCM) {
111 		memcpy(&hdr->iv[0], &sa->iv.gcm.nonce, 4);
112 		memcpy(&hdr->iv[4], rte_crypto_op_ctod_offset(cop, uint8_t *,
113 			sess->iv_offset), sess->iv_length);
114 	} else if (ctl_wrd->auth_type == OTX2_IPSEC_FP_SA_ENC_AES_CBC) {
115 		memcpy(&hdr->iv[0], rte_crypto_op_ctod_offset(cop, uint8_t *,
116 			sess->iv_offset), sess->iv_length);
117 	}
118 
119 	/* Prepare CPT instruction */
120 	word0.u64 = sess->ucmd_w0;
121 	word0.s.dlen = dlen;
122 
123 	req->ist.ei0 = word0.u64;
124 	req->ist.ei1 = rte_pktmbuf_iova(m_src);
125 	req->ist.ei2 = req->ist.ei1;
126 
127 	hdr->seq = rte_cpu_to_be_32(sess->seq_lo);
128 	hdr->ip_id = rte_cpu_to_be_32(sess->ip_id);
129 
130 	sess->ip_id++;
131 	sess->esn++;
132 
133 exit:
134 	*prep_req = req;
135 
136 	return ret;
137 }
138 
139 static __rte_always_inline int
process_inb_sa(struct rte_crypto_op * cop,struct otx2_sec_session_ipsec_lp * sess,struct cpt_qp_meta_info * m_info,void ** prep_req)140 process_inb_sa(struct rte_crypto_op *cop,
141 	      struct otx2_sec_session_ipsec_lp *sess,
142 	      struct cpt_qp_meta_info *m_info, void **prep_req)
143 {
144 	struct rte_crypto_sym_op *sym_op = cop->sym;
145 	struct rte_mbuf *m_src = sym_op->m_src;
146 	struct cpt_request_info *req = NULL;
147 	int mdata_len, ret = 0;
148 	vq_cmd_word0_t word0;
149 	uint32_t dlen;
150 	char *mdata;
151 
152 	dlen = rte_pktmbuf_pkt_len(m_src);
153 	mdata_len = m_info->lb_mlen + 8;
154 
155 	mdata = rte_pktmbuf_append(m_src, mdata_len);
156 	if (unlikely(mdata == NULL)) {
157 		otx2_err("Not enough tail room\n");
158 		ret = -ENOMEM;
159 		goto exit;
160 	}
161 
162 	req = alloc_request_struct(mdata, (void *)cop, mdata_len,
163 		sess->tunnel_type);
164 
165 	/* Prepare CPT instruction */
166 	word0.u64 = sess->ucmd_w0;
167 	word0.s.dlen   = dlen;
168 
169 	req->ist.ei0 = word0.u64;
170 	req->ist.ei1 = rte_pktmbuf_iova(m_src);
171 	req->ist.ei2 = req->ist.ei1;
172 
173 exit:
174 	*prep_req = req;
175 	return ret;
176 }
177 #endif /* __OTX2_IPSEC_PO_OPS_H__ */
178