199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2018-2020 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <rte_ipsec.h>
699a2dd95SBruce Richardson #include <rte_esp.h>
799a2dd95SBruce Richardson #include <rte_errno.h>
899a2dd95SBruce Richardson #include <rte_cryptodev.h>
999a2dd95SBruce Richardson
1099a2dd95SBruce Richardson #include "sa.h"
1199a2dd95SBruce Richardson #include "ipsec_sqn.h"
1299a2dd95SBruce Richardson #include "crypto.h"
1399a2dd95SBruce Richardson #include "iph.h"
1499a2dd95SBruce Richardson #include "misc.h"
1599a2dd95SBruce Richardson #include "pad.h"
1699a2dd95SBruce Richardson
1768977baaSRadu Nicolau typedef uint16_t (*esp_inb_process_t)(struct rte_ipsec_sa *sa,
1899a2dd95SBruce Richardson struct rte_mbuf *mb[], uint32_t sqn[], uint32_t dr[], uint16_t num,
1999a2dd95SBruce Richardson uint8_t sqh_len);
2099a2dd95SBruce Richardson
2199a2dd95SBruce Richardson /*
2299a2dd95SBruce Richardson * helper function to fill crypto_sym op for cipher+auth algorithms.
2399a2dd95SBruce Richardson * used by inb_cop_prepare(), see below.
2499a2dd95SBruce Richardson */
2599a2dd95SBruce Richardson static inline void
sop_ciph_auth_prepare(struct rte_crypto_sym_op * sop,const struct rte_ipsec_sa * sa,const union sym_op_data * icv,uint32_t pofs,uint32_t plen)2699a2dd95SBruce Richardson sop_ciph_auth_prepare(struct rte_crypto_sym_op *sop,
2799a2dd95SBruce Richardson const struct rte_ipsec_sa *sa, const union sym_op_data *icv,
2899a2dd95SBruce Richardson uint32_t pofs, uint32_t plen)
2999a2dd95SBruce Richardson {
3099a2dd95SBruce Richardson sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
3199a2dd95SBruce Richardson sop->cipher.data.length = plen - sa->ctp.cipher.length;
3299a2dd95SBruce Richardson sop->auth.data.offset = pofs + sa->ctp.auth.offset;
3399a2dd95SBruce Richardson sop->auth.data.length = plen - sa->ctp.auth.length;
3499a2dd95SBruce Richardson sop->auth.digest.data = icv->va;
3599a2dd95SBruce Richardson sop->auth.digest.phys_addr = icv->pa;
3699a2dd95SBruce Richardson }
3799a2dd95SBruce Richardson
3899a2dd95SBruce Richardson /*
3999a2dd95SBruce Richardson * helper function to fill crypto_sym op for aead algorithms
4099a2dd95SBruce Richardson * used by inb_cop_prepare(), see below.
4199a2dd95SBruce Richardson */
4299a2dd95SBruce Richardson static inline void
sop_aead_prepare(struct rte_crypto_sym_op * sop,const struct rte_ipsec_sa * sa,const union sym_op_data * icv,uint32_t pofs,uint32_t plen)4399a2dd95SBruce Richardson sop_aead_prepare(struct rte_crypto_sym_op *sop,
4499a2dd95SBruce Richardson const struct rte_ipsec_sa *sa, const union sym_op_data *icv,
4599a2dd95SBruce Richardson uint32_t pofs, uint32_t plen)
4699a2dd95SBruce Richardson {
4799a2dd95SBruce Richardson sop->aead.data.offset = pofs + sa->ctp.cipher.offset;
4899a2dd95SBruce Richardson sop->aead.data.length = plen - sa->ctp.cipher.length;
4999a2dd95SBruce Richardson sop->aead.digest.data = icv->va;
5099a2dd95SBruce Richardson sop->aead.digest.phys_addr = icv->pa;
5199a2dd95SBruce Richardson sop->aead.aad.data = icv->va + sa->icv_len;
5299a2dd95SBruce Richardson sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
5399a2dd95SBruce Richardson }
5499a2dd95SBruce Richardson
5599a2dd95SBruce Richardson /*
5699a2dd95SBruce Richardson * setup crypto op and crypto sym op for ESP inbound packet.
5799a2dd95SBruce Richardson */
5899a2dd95SBruce Richardson static inline void
inb_cop_prepare(struct rte_crypto_op * cop,const struct rte_ipsec_sa * sa,struct rte_mbuf * mb,const union sym_op_data * icv,uint32_t pofs,uint32_t plen)5999a2dd95SBruce Richardson inb_cop_prepare(struct rte_crypto_op *cop,
6099a2dd95SBruce Richardson const struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
6199a2dd95SBruce Richardson const union sym_op_data *icv, uint32_t pofs, uint32_t plen)
6299a2dd95SBruce Richardson {
6399a2dd95SBruce Richardson struct rte_crypto_sym_op *sop;
6499a2dd95SBruce Richardson struct aead_gcm_iv *gcm;
65c99d2619SRadu Nicolau struct aead_ccm_iv *ccm;
66c99d2619SRadu Nicolau struct aead_chacha20_poly1305_iv *chacha20_poly1305;
6799a2dd95SBruce Richardson struct aesctr_cnt_blk *ctr;
6899a2dd95SBruce Richardson uint64_t *ivc, *ivp;
6999a2dd95SBruce Richardson uint32_t algo;
7099a2dd95SBruce Richardson
7199a2dd95SBruce Richardson algo = sa->algo_type;
7299a2dd95SBruce Richardson ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
7399a2dd95SBruce Richardson pofs + sizeof(struct rte_esp_hdr));
7499a2dd95SBruce Richardson
7599a2dd95SBruce Richardson /* fill sym op fields */
7699a2dd95SBruce Richardson sop = cop->sym;
7799a2dd95SBruce Richardson
7899a2dd95SBruce Richardson switch (algo) {
7999a2dd95SBruce Richardson case ALGO_TYPE_AES_GCM:
8099a2dd95SBruce Richardson sop_aead_prepare(sop, sa, icv, pofs, plen);
8199a2dd95SBruce Richardson
8299a2dd95SBruce Richardson /* fill AAD IV (located inside crypto op) */
8399a2dd95SBruce Richardson gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
8499a2dd95SBruce Richardson sa->iv_ofs);
8599a2dd95SBruce Richardson aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
8699a2dd95SBruce Richardson break;
87c99d2619SRadu Nicolau case ALGO_TYPE_AES_CCM:
88c99d2619SRadu Nicolau sop_aead_prepare(sop, sa, icv, pofs, plen);
89c99d2619SRadu Nicolau
90c99d2619SRadu Nicolau /* fill AAD IV (located inside crypto op) */
91c99d2619SRadu Nicolau ccm = rte_crypto_op_ctod_offset(cop, struct aead_ccm_iv *,
92c99d2619SRadu Nicolau sa->iv_ofs);
93c99d2619SRadu Nicolau aead_ccm_iv_fill(ccm, ivp[0], sa->salt);
94c99d2619SRadu Nicolau break;
95c99d2619SRadu Nicolau case ALGO_TYPE_CHACHA20_POLY1305:
96c99d2619SRadu Nicolau sop_aead_prepare(sop, sa, icv, pofs, plen);
97c99d2619SRadu Nicolau
98c99d2619SRadu Nicolau /* fill AAD IV (located inside crypto op) */
99c99d2619SRadu Nicolau chacha20_poly1305 = rte_crypto_op_ctod_offset(cop,
100c99d2619SRadu Nicolau struct aead_chacha20_poly1305_iv *,
101c99d2619SRadu Nicolau sa->iv_ofs);
102c99d2619SRadu Nicolau aead_chacha20_poly1305_iv_fill(chacha20_poly1305,
103c99d2619SRadu Nicolau ivp[0], sa->salt);
104c99d2619SRadu Nicolau break;
10599a2dd95SBruce Richardson case ALGO_TYPE_AES_CBC:
10699a2dd95SBruce Richardson case ALGO_TYPE_3DES_CBC:
10799a2dd95SBruce Richardson sop_ciph_auth_prepare(sop, sa, icv, pofs, plen);
10899a2dd95SBruce Richardson
10999a2dd95SBruce Richardson /* copy iv from the input packet to the cop */
11099a2dd95SBruce Richardson ivc = rte_crypto_op_ctod_offset(cop, uint64_t *, sa->iv_ofs);
11199a2dd95SBruce Richardson copy_iv(ivc, ivp, sa->iv_len);
11299a2dd95SBruce Richardson break;
113c99d2619SRadu Nicolau case ALGO_TYPE_AES_GMAC:
114c99d2619SRadu Nicolau sop_ciph_auth_prepare(sop, sa, icv, pofs, plen);
115c99d2619SRadu Nicolau
116c99d2619SRadu Nicolau /* fill AAD IV (located inside crypto op) */
117c99d2619SRadu Nicolau gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
118c99d2619SRadu Nicolau sa->iv_ofs);
119c99d2619SRadu Nicolau aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
120c99d2619SRadu Nicolau break;
12199a2dd95SBruce Richardson case ALGO_TYPE_AES_CTR:
12299a2dd95SBruce Richardson sop_ciph_auth_prepare(sop, sa, icv, pofs, plen);
12399a2dd95SBruce Richardson
12499a2dd95SBruce Richardson /* fill CTR block (located inside crypto op) */
12599a2dd95SBruce Richardson ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
12699a2dd95SBruce Richardson sa->iv_ofs);
12799a2dd95SBruce Richardson aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
12899a2dd95SBruce Richardson break;
12999a2dd95SBruce Richardson case ALGO_TYPE_NULL:
13099a2dd95SBruce Richardson sop_ciph_auth_prepare(sop, sa, icv, pofs, plen);
13199a2dd95SBruce Richardson break;
13299a2dd95SBruce Richardson }
13399a2dd95SBruce Richardson }
13499a2dd95SBruce Richardson
13599a2dd95SBruce Richardson static inline uint32_t
inb_cpu_crypto_prepare(const struct rte_ipsec_sa * sa,struct rte_mbuf * mb,uint32_t * pofs,uint32_t plen,void * iv)13699a2dd95SBruce Richardson inb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
13799a2dd95SBruce Richardson uint32_t *pofs, uint32_t plen, void *iv)
13899a2dd95SBruce Richardson {
13999a2dd95SBruce Richardson struct aead_gcm_iv *gcm;
140c99d2619SRadu Nicolau struct aead_ccm_iv *ccm;
141c99d2619SRadu Nicolau struct aead_chacha20_poly1305_iv *chacha20_poly1305;
14299a2dd95SBruce Richardson struct aesctr_cnt_blk *ctr;
14399a2dd95SBruce Richardson uint64_t *ivp;
14499a2dd95SBruce Richardson uint32_t clen;
14599a2dd95SBruce Richardson
14699a2dd95SBruce Richardson ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
14799a2dd95SBruce Richardson *pofs + sizeof(struct rte_esp_hdr));
14899a2dd95SBruce Richardson clen = 0;
14999a2dd95SBruce Richardson
15099a2dd95SBruce Richardson switch (sa->algo_type) {
15199a2dd95SBruce Richardson case ALGO_TYPE_AES_GCM:
152c99d2619SRadu Nicolau case ALGO_TYPE_AES_GMAC:
15399a2dd95SBruce Richardson gcm = (struct aead_gcm_iv *)iv;
15499a2dd95SBruce Richardson aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
15599a2dd95SBruce Richardson break;
156c99d2619SRadu Nicolau case ALGO_TYPE_AES_CCM:
157c99d2619SRadu Nicolau ccm = (struct aead_ccm_iv *)iv;
158c99d2619SRadu Nicolau aead_ccm_iv_fill(ccm, ivp[0], sa->salt);
159c99d2619SRadu Nicolau break;
160c99d2619SRadu Nicolau case ALGO_TYPE_CHACHA20_POLY1305:
161c99d2619SRadu Nicolau chacha20_poly1305 = (struct aead_chacha20_poly1305_iv *)iv;
162c99d2619SRadu Nicolau aead_chacha20_poly1305_iv_fill(chacha20_poly1305,
163c99d2619SRadu Nicolau ivp[0], sa->salt);
164c99d2619SRadu Nicolau break;
16599a2dd95SBruce Richardson case ALGO_TYPE_AES_CBC:
16699a2dd95SBruce Richardson case ALGO_TYPE_3DES_CBC:
16799a2dd95SBruce Richardson copy_iv(iv, ivp, sa->iv_len);
16899a2dd95SBruce Richardson break;
16999a2dd95SBruce Richardson case ALGO_TYPE_AES_CTR:
17099a2dd95SBruce Richardson ctr = (struct aesctr_cnt_blk *)iv;
17199a2dd95SBruce Richardson aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
17299a2dd95SBruce Richardson break;
17399a2dd95SBruce Richardson }
17499a2dd95SBruce Richardson
17599a2dd95SBruce Richardson *pofs += sa->ctp.auth.offset;
17699a2dd95SBruce Richardson clen = plen - sa->ctp.auth.length;
17799a2dd95SBruce Richardson return clen;
17899a2dd95SBruce Richardson }
17999a2dd95SBruce Richardson
18099a2dd95SBruce Richardson /*
18199a2dd95SBruce Richardson * Helper function for prepare() to deal with situation when
18299a2dd95SBruce Richardson * ICV is spread by two segments. Tries to move ICV completely into the
18399a2dd95SBruce Richardson * last segment.
18499a2dd95SBruce Richardson */
18599a2dd95SBruce Richardson static struct rte_mbuf *
move_icv(struct rte_mbuf * ml,uint32_t ofs)18699a2dd95SBruce Richardson move_icv(struct rte_mbuf *ml, uint32_t ofs)
18799a2dd95SBruce Richardson {
18899a2dd95SBruce Richardson uint32_t n;
18999a2dd95SBruce Richardson struct rte_mbuf *ms;
19099a2dd95SBruce Richardson const void *prev;
19199a2dd95SBruce Richardson void *new;
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson ms = ml->next;
19499a2dd95SBruce Richardson n = ml->data_len - ofs;
19599a2dd95SBruce Richardson
19699a2dd95SBruce Richardson prev = rte_pktmbuf_mtod_offset(ml, const void *, ofs);
19799a2dd95SBruce Richardson new = rte_pktmbuf_prepend(ms, n);
19899a2dd95SBruce Richardson if (new == NULL)
19999a2dd95SBruce Richardson return NULL;
20099a2dd95SBruce Richardson
20199a2dd95SBruce Richardson /* move n ICV bytes from ml into ms */
20299a2dd95SBruce Richardson rte_memcpy(new, prev, n);
20399a2dd95SBruce Richardson ml->data_len -= n;
20499a2dd95SBruce Richardson
20599a2dd95SBruce Richardson return ms;
20699a2dd95SBruce Richardson }
20799a2dd95SBruce Richardson
20899a2dd95SBruce Richardson /*
20999a2dd95SBruce Richardson * for pure cryptodev (lookaside none) depending on SA settings,
21099a2dd95SBruce Richardson * we might have to write some extra data to the packet.
21199a2dd95SBruce Richardson */
21299a2dd95SBruce Richardson static inline void
inb_pkt_xprepare(const struct rte_ipsec_sa * sa,rte_be64_t sqc,const union sym_op_data * icv)21399a2dd95SBruce Richardson inb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
21499a2dd95SBruce Richardson const union sym_op_data *icv)
21599a2dd95SBruce Richardson {
21699a2dd95SBruce Richardson struct aead_gcm_aad *aad;
217c99d2619SRadu Nicolau struct aead_ccm_aad *caad;
218c99d2619SRadu Nicolau struct aead_chacha20_poly1305_aad *chacha_aad;
21999a2dd95SBruce Richardson
22099a2dd95SBruce Richardson /* insert SQN.hi between ESP trailer and ICV */
22199a2dd95SBruce Richardson if (sa->sqh_len != 0)
22299a2dd95SBruce Richardson insert_sqh(sqn_hi32(sqc), icv->va, sa->icv_len);
22399a2dd95SBruce Richardson
22499a2dd95SBruce Richardson /*
22599a2dd95SBruce Richardson * fill AAD fields, if any (aad fields are placed after icv),
22699a2dd95SBruce Richardson * right now we support only one AEAD algorithm: AES-GCM.
22799a2dd95SBruce Richardson */
228c99d2619SRadu Nicolau switch (sa->algo_type) {
229c99d2619SRadu Nicolau case ALGO_TYPE_AES_GCM:
23099a2dd95SBruce Richardson if (sa->aad_len != 0) {
23199a2dd95SBruce Richardson aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
23299a2dd95SBruce Richardson aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
23399a2dd95SBruce Richardson }
234c99d2619SRadu Nicolau break;
235c99d2619SRadu Nicolau case ALGO_TYPE_AES_CCM:
236c99d2619SRadu Nicolau if (sa->aad_len != 0) {
237c99d2619SRadu Nicolau caad = (struct aead_ccm_aad *)(icv->va + sa->icv_len);
238c99d2619SRadu Nicolau aead_ccm_aad_fill(caad, sa->spi, sqc, IS_ESN(sa));
239c99d2619SRadu Nicolau }
240c99d2619SRadu Nicolau break;
241c99d2619SRadu Nicolau case ALGO_TYPE_CHACHA20_POLY1305:
242c99d2619SRadu Nicolau if (sa->aad_len != 0) {
243c99d2619SRadu Nicolau chacha_aad = (struct aead_chacha20_poly1305_aad *)
244c99d2619SRadu Nicolau (icv->va + sa->icv_len);
245c99d2619SRadu Nicolau aead_chacha20_poly1305_aad_fill(chacha_aad,
246c99d2619SRadu Nicolau sa->spi, sqc, IS_ESN(sa));
247c99d2619SRadu Nicolau }
248c99d2619SRadu Nicolau break;
249c99d2619SRadu Nicolau }
25099a2dd95SBruce Richardson }
25199a2dd95SBruce Richardson
25299a2dd95SBruce Richardson static inline int
inb_get_sqn(const struct rte_ipsec_sa * sa,const struct replay_sqn * rsn,struct rte_mbuf * mb,uint32_t hlen,rte_be64_t * sqc)25399a2dd95SBruce Richardson inb_get_sqn(const struct rte_ipsec_sa *sa, const struct replay_sqn *rsn,
25499a2dd95SBruce Richardson struct rte_mbuf *mb, uint32_t hlen, rte_be64_t *sqc)
25599a2dd95SBruce Richardson {
25699a2dd95SBruce Richardson int32_t rc;
25799a2dd95SBruce Richardson uint64_t sqn;
25899a2dd95SBruce Richardson struct rte_esp_hdr *esph;
25999a2dd95SBruce Richardson
26099a2dd95SBruce Richardson esph = rte_pktmbuf_mtod_offset(mb, struct rte_esp_hdr *, hlen);
26199a2dd95SBruce Richardson
26299a2dd95SBruce Richardson /*
26399a2dd95SBruce Richardson * retrieve and reconstruct SQN, then check it, then
26499a2dd95SBruce Richardson * convert it back into network byte order.
26599a2dd95SBruce Richardson */
26699a2dd95SBruce Richardson sqn = rte_be_to_cpu_32(esph->seq);
26799a2dd95SBruce Richardson if (IS_ESN(sa))
26899a2dd95SBruce Richardson sqn = reconstruct_esn(rsn->sqn, sqn, sa->replay.win_sz);
26999a2dd95SBruce Richardson *sqc = rte_cpu_to_be_64(sqn);
27099a2dd95SBruce Richardson
27199a2dd95SBruce Richardson /* check IPsec window */
27299a2dd95SBruce Richardson rc = esn_inb_check_sqn(rsn, sa, sqn);
27399a2dd95SBruce Richardson
27499a2dd95SBruce Richardson return rc;
27599a2dd95SBruce Richardson }
27699a2dd95SBruce Richardson
27799a2dd95SBruce Richardson /* prepare packet for upcoming processing */
27899a2dd95SBruce Richardson static inline int32_t
inb_prepare(const struct rte_ipsec_sa * sa,struct rte_mbuf * mb,uint32_t hlen,union sym_op_data * icv)27999a2dd95SBruce Richardson inb_prepare(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
28099a2dd95SBruce Richardson uint32_t hlen, union sym_op_data *icv)
28199a2dd95SBruce Richardson {
28299a2dd95SBruce Richardson uint32_t clen, icv_len, icv_ofs, plen;
28399a2dd95SBruce Richardson struct rte_mbuf *ml;
28499a2dd95SBruce Richardson
28599a2dd95SBruce Richardson /* start packet manipulation */
28699a2dd95SBruce Richardson plen = mb->pkt_len;
28799a2dd95SBruce Richardson plen = plen - hlen;
28899a2dd95SBruce Richardson
28999a2dd95SBruce Richardson /* check that packet has a valid length */
29099a2dd95SBruce Richardson clen = plen - sa->ctp.cipher.length;
29199a2dd95SBruce Richardson if ((int32_t)clen < 0 || (clen & (sa->pad_align - 1)) != 0)
29299a2dd95SBruce Richardson return -EBADMSG;
29399a2dd95SBruce Richardson
29499a2dd95SBruce Richardson /* find ICV location */
29599a2dd95SBruce Richardson icv_len = sa->icv_len;
29699a2dd95SBruce Richardson icv_ofs = mb->pkt_len - icv_len;
29799a2dd95SBruce Richardson
29899a2dd95SBruce Richardson ml = mbuf_get_seg_ofs(mb, &icv_ofs);
29999a2dd95SBruce Richardson
30099a2dd95SBruce Richardson /*
30199a2dd95SBruce Richardson * if ICV is spread by two segments, then try to
30299a2dd95SBruce Richardson * move ICV completely into the last segment.
30399a2dd95SBruce Richardson */
30499a2dd95SBruce Richardson if (ml->data_len < icv_ofs + icv_len) {
30599a2dd95SBruce Richardson
30699a2dd95SBruce Richardson ml = move_icv(ml, icv_ofs);
30799a2dd95SBruce Richardson if (ml == NULL)
30899a2dd95SBruce Richardson return -ENOSPC;
30999a2dd95SBruce Richardson
31099a2dd95SBruce Richardson /* new ICV location */
31199a2dd95SBruce Richardson icv_ofs = 0;
31299a2dd95SBruce Richardson }
31399a2dd95SBruce Richardson
31499a2dd95SBruce Richardson icv_ofs += sa->sqh_len;
31599a2dd95SBruce Richardson
31699a2dd95SBruce Richardson /*
31799a2dd95SBruce Richardson * we have to allocate space for AAD somewhere,
31899a2dd95SBruce Richardson * right now - just use free trailing space at the last segment.
31999a2dd95SBruce Richardson * Would probably be more convenient to reserve space for AAD
32099a2dd95SBruce Richardson * inside rte_crypto_op itself
32199a2dd95SBruce Richardson * (again for IV space is already reserved inside cop).
32299a2dd95SBruce Richardson */
32399a2dd95SBruce Richardson if (sa->aad_len + sa->sqh_len > rte_pktmbuf_tailroom(ml))
32499a2dd95SBruce Richardson return -ENOSPC;
32599a2dd95SBruce Richardson
32699a2dd95SBruce Richardson icv->va = rte_pktmbuf_mtod_offset(ml, void *, icv_ofs);
32799a2dd95SBruce Richardson icv->pa = rte_pktmbuf_iova_offset(ml, icv_ofs);
32899a2dd95SBruce Richardson
32999a2dd95SBruce Richardson /*
33099a2dd95SBruce Richardson * if esn is used then high-order 32 bits are also used in ICV
33199a2dd95SBruce Richardson * calculation but are not transmitted, update packet length
33299a2dd95SBruce Richardson * to be consistent with auth data length and offset, this will
33399a2dd95SBruce Richardson * be subtracted from packet length in post crypto processing
33499a2dd95SBruce Richardson */
33599a2dd95SBruce Richardson mb->pkt_len += sa->sqh_len;
33699a2dd95SBruce Richardson ml->data_len += sa->sqh_len;
33799a2dd95SBruce Richardson
33899a2dd95SBruce Richardson return plen;
33999a2dd95SBruce Richardson }
34099a2dd95SBruce Richardson
34199a2dd95SBruce Richardson static inline int32_t
inb_pkt_prepare(const struct rte_ipsec_sa * sa,const struct replay_sqn * rsn,struct rte_mbuf * mb,uint32_t hlen,union sym_op_data * icv)34299a2dd95SBruce Richardson inb_pkt_prepare(const struct rte_ipsec_sa *sa, const struct replay_sqn *rsn,
34399a2dd95SBruce Richardson struct rte_mbuf *mb, uint32_t hlen, union sym_op_data *icv)
34499a2dd95SBruce Richardson {
34599a2dd95SBruce Richardson int rc;
34699a2dd95SBruce Richardson rte_be64_t sqn;
34799a2dd95SBruce Richardson
34899a2dd95SBruce Richardson rc = inb_get_sqn(sa, rsn, mb, hlen, &sqn);
34999a2dd95SBruce Richardson if (rc != 0)
35099a2dd95SBruce Richardson return rc;
35199a2dd95SBruce Richardson
35299a2dd95SBruce Richardson rc = inb_prepare(sa, mb, hlen, icv);
35399a2dd95SBruce Richardson if (rc < 0)
35499a2dd95SBruce Richardson return rc;
35599a2dd95SBruce Richardson
35699a2dd95SBruce Richardson inb_pkt_xprepare(sa, sqn, icv);
35799a2dd95SBruce Richardson return rc;
35899a2dd95SBruce Richardson }
35999a2dd95SBruce Richardson
36099a2dd95SBruce Richardson /*
36199a2dd95SBruce Richardson * setup/update packets and crypto ops for ESP inbound case.
36299a2dd95SBruce Richardson */
36399a2dd95SBruce Richardson uint16_t
esp_inb_pkt_prepare(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],struct rte_crypto_op * cop[],uint16_t num)36499a2dd95SBruce Richardson esp_inb_pkt_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
36599a2dd95SBruce Richardson struct rte_crypto_op *cop[], uint16_t num)
36699a2dd95SBruce Richardson {
36799a2dd95SBruce Richardson int32_t rc;
36899a2dd95SBruce Richardson uint32_t i, k, hl;
36999a2dd95SBruce Richardson struct rte_ipsec_sa *sa;
37099a2dd95SBruce Richardson struct rte_cryptodev_sym_session *cs;
37199a2dd95SBruce Richardson struct replay_sqn *rsn;
37299a2dd95SBruce Richardson union sym_op_data icv;
37399a2dd95SBruce Richardson uint32_t dr[num];
37499a2dd95SBruce Richardson
37599a2dd95SBruce Richardson sa = ss->sa;
37699a2dd95SBruce Richardson cs = ss->crypto.ses;
37799a2dd95SBruce Richardson rsn = rsn_acquire(sa);
37899a2dd95SBruce Richardson
37999a2dd95SBruce Richardson k = 0;
38099a2dd95SBruce Richardson for (i = 0; i != num; i++) {
38199a2dd95SBruce Richardson
38299a2dd95SBruce Richardson hl = mb[i]->l2_len + mb[i]->l3_len;
38399a2dd95SBruce Richardson rc = inb_pkt_prepare(sa, rsn, mb[i], hl, &icv);
38499a2dd95SBruce Richardson if (rc >= 0) {
38599a2dd95SBruce Richardson lksd_none_cop_prepare(cop[k], cs, mb[i]);
38699a2dd95SBruce Richardson inb_cop_prepare(cop[k], sa, mb[i], &icv, hl, rc);
38799a2dd95SBruce Richardson k++;
38899a2dd95SBruce Richardson } else {
38999a2dd95SBruce Richardson dr[i - k] = i;
39099a2dd95SBruce Richardson rte_errno = -rc;
39199a2dd95SBruce Richardson }
39299a2dd95SBruce Richardson }
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson rsn_release(sa, rsn);
39599a2dd95SBruce Richardson
39699a2dd95SBruce Richardson /* copy not prepared mbufs beyond good ones */
39799a2dd95SBruce Richardson if (k != num && k != 0)
39899a2dd95SBruce Richardson move_bad_mbufs(mb, dr, num, num - k);
39999a2dd95SBruce Richardson
40099a2dd95SBruce Richardson return k;
40199a2dd95SBruce Richardson }
40299a2dd95SBruce Richardson
40399a2dd95SBruce Richardson /*
40499a2dd95SBruce Richardson * Start with processing inbound packet.
40599a2dd95SBruce Richardson * This is common part for both tunnel and transport mode.
40699a2dd95SBruce Richardson * Extract information that will be needed later from mbuf metadata and
40799a2dd95SBruce Richardson * actual packet data:
40899a2dd95SBruce Richardson * - mbuf for packet's last segment
40999a2dd95SBruce Richardson * - length of the L2/L3 headers
41099a2dd95SBruce Richardson * - esp tail structure
41199a2dd95SBruce Richardson */
41299a2dd95SBruce Richardson static inline void
process_step1(struct rte_mbuf * mb,uint32_t tlen,struct rte_mbuf ** ml,struct rte_esp_tail * espt,uint32_t * hlen,uint32_t * tofs)41399a2dd95SBruce Richardson process_step1(struct rte_mbuf *mb, uint32_t tlen, struct rte_mbuf **ml,
41499a2dd95SBruce Richardson struct rte_esp_tail *espt, uint32_t *hlen, uint32_t *tofs)
41599a2dd95SBruce Richardson {
41699a2dd95SBruce Richardson const struct rte_esp_tail *pt;
41799a2dd95SBruce Richardson uint32_t ofs;
41899a2dd95SBruce Richardson
41999a2dd95SBruce Richardson ofs = mb->pkt_len - tlen;
42099a2dd95SBruce Richardson hlen[0] = mb->l2_len + mb->l3_len;
42199a2dd95SBruce Richardson ml[0] = mbuf_get_seg_ofs(mb, &ofs);
42299a2dd95SBruce Richardson pt = rte_pktmbuf_mtod_offset(ml[0], const struct rte_esp_tail *, ofs);
42399a2dd95SBruce Richardson tofs[0] = ofs;
42499a2dd95SBruce Richardson espt[0] = pt[0];
42599a2dd95SBruce Richardson }
42699a2dd95SBruce Richardson
42799a2dd95SBruce Richardson /*
42899a2dd95SBruce Richardson * Helper function to check pad bytes values.
42999a2dd95SBruce Richardson * Note that pad bytes can be spread across multiple segments.
43099a2dd95SBruce Richardson */
43199a2dd95SBruce Richardson static inline int
check_pad_bytes(struct rte_mbuf * mb,uint32_t ofs,uint32_t len)43299a2dd95SBruce Richardson check_pad_bytes(struct rte_mbuf *mb, uint32_t ofs, uint32_t len)
43399a2dd95SBruce Richardson {
43499a2dd95SBruce Richardson const uint8_t *pd;
43599a2dd95SBruce Richardson uint32_t k, n;
43699a2dd95SBruce Richardson
43799a2dd95SBruce Richardson for (n = 0; n != len; n += k, mb = mb->next) {
43899a2dd95SBruce Richardson k = mb->data_len - ofs;
43999a2dd95SBruce Richardson k = RTE_MIN(k, len - n);
44099a2dd95SBruce Richardson pd = rte_pktmbuf_mtod_offset(mb, const uint8_t *, ofs);
44199a2dd95SBruce Richardson if (memcmp(pd, esp_pad_bytes + n, k) != 0)
44299a2dd95SBruce Richardson break;
44399a2dd95SBruce Richardson ofs = 0;
44499a2dd95SBruce Richardson }
44599a2dd95SBruce Richardson
44699a2dd95SBruce Richardson return len - n;
44799a2dd95SBruce Richardson }
44899a2dd95SBruce Richardson
44999a2dd95SBruce Richardson /*
45099a2dd95SBruce Richardson * packet checks for transport mode:
45199a2dd95SBruce Richardson * - no reported IPsec related failures in ol_flags
45299a2dd95SBruce Richardson * - tail and header lengths are valid
45399a2dd95SBruce Richardson * - padding bytes are valid
45499a2dd95SBruce Richardson * apart from checks, function also updates tail offset (and segment)
45599a2dd95SBruce Richardson * by taking into account pad length.
45699a2dd95SBruce Richardson */
45799a2dd95SBruce Richardson static inline int32_t
trs_process_check(struct rte_mbuf * mb,struct rte_mbuf ** ml,uint32_t * tofs,struct rte_esp_tail espt,uint32_t hlen,uint32_t tlen)45899a2dd95SBruce Richardson trs_process_check(struct rte_mbuf *mb, struct rte_mbuf **ml,
45999a2dd95SBruce Richardson uint32_t *tofs, struct rte_esp_tail espt, uint32_t hlen, uint32_t tlen)
46099a2dd95SBruce Richardson {
461daa02b5cSOlivier Matz if ((mb->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED) != 0 ||
46299a2dd95SBruce Richardson tlen + hlen > mb->pkt_len)
46399a2dd95SBruce Richardson return -EBADMSG;
46499a2dd95SBruce Richardson
46599a2dd95SBruce Richardson /* padding bytes are spread over multiple segments */
46699a2dd95SBruce Richardson if (tofs[0] < espt.pad_len) {
46799a2dd95SBruce Richardson tofs[0] = mb->pkt_len - tlen;
46899a2dd95SBruce Richardson ml[0] = mbuf_get_seg_ofs(mb, tofs);
46999a2dd95SBruce Richardson } else
47099a2dd95SBruce Richardson tofs[0] -= espt.pad_len;
47199a2dd95SBruce Richardson
47299a2dd95SBruce Richardson return check_pad_bytes(ml[0], tofs[0], espt.pad_len);
47399a2dd95SBruce Richardson }
47499a2dd95SBruce Richardson
47599a2dd95SBruce Richardson /*
47699a2dd95SBruce Richardson * packet checks for tunnel mode:
477*4a6672c2SStephen Hemminger * - same as for transport mode
47899a2dd95SBruce Richardson * - esp tail next proto contains expected for that SA value
47999a2dd95SBruce Richardson */
48099a2dd95SBruce Richardson static inline int32_t
tun_process_check(struct rte_mbuf * mb,struct rte_mbuf ** ml,uint32_t * tofs,struct rte_esp_tail espt,uint32_t hlen,uint32_t tlen,uint8_t proto)48199a2dd95SBruce Richardson tun_process_check(struct rte_mbuf *mb, struct rte_mbuf **ml,
48299a2dd95SBruce Richardson uint32_t *tofs, struct rte_esp_tail espt, uint32_t hlen, uint32_t tlen,
48399a2dd95SBruce Richardson uint8_t proto)
48499a2dd95SBruce Richardson {
48599a2dd95SBruce Richardson return (trs_process_check(mb, ml, tofs, espt, hlen, tlen) ||
48699a2dd95SBruce Richardson espt.next_proto != proto);
48799a2dd95SBruce Richardson }
48899a2dd95SBruce Richardson
48999a2dd95SBruce Richardson /*
49099a2dd95SBruce Richardson * step two for tunnel mode:
49199a2dd95SBruce Richardson * - read SQN value (for future use)
49299a2dd95SBruce Richardson * - cut of ICV, ESP tail and padding bytes
49399a2dd95SBruce Richardson * - cut of ESP header and IV, also if needed - L2/L3 headers
49499a2dd95SBruce Richardson * (controlled by *adj* value)
49599a2dd95SBruce Richardson */
49699a2dd95SBruce Richardson static inline void *
tun_process_step2(struct rte_mbuf * mb,struct rte_mbuf * ml,uint32_t hlen,uint32_t adj,uint32_t tofs,uint32_t tlen,uint32_t * sqn)49799a2dd95SBruce Richardson tun_process_step2(struct rte_mbuf *mb, struct rte_mbuf *ml, uint32_t hlen,
49899a2dd95SBruce Richardson uint32_t adj, uint32_t tofs, uint32_t tlen, uint32_t *sqn)
49999a2dd95SBruce Richardson {
50099a2dd95SBruce Richardson const struct rte_esp_hdr *ph;
50199a2dd95SBruce Richardson
50299a2dd95SBruce Richardson /* read SQN value */
50399a2dd95SBruce Richardson ph = rte_pktmbuf_mtod_offset(mb, const struct rte_esp_hdr *, hlen);
50499a2dd95SBruce Richardson sqn[0] = ph->seq;
50599a2dd95SBruce Richardson
50699a2dd95SBruce Richardson /* cut of ICV, ESP tail and padding bytes */
50799a2dd95SBruce Richardson mbuf_cut_seg_ofs(mb, ml, tofs, tlen);
50899a2dd95SBruce Richardson
50999a2dd95SBruce Richardson /* cut of L2/L3 headers, ESP header and IV */
51099a2dd95SBruce Richardson return rte_pktmbuf_adj(mb, adj);
51199a2dd95SBruce Richardson }
51299a2dd95SBruce Richardson
51399a2dd95SBruce Richardson /*
51499a2dd95SBruce Richardson * step two for transport mode:
51599a2dd95SBruce Richardson * - read SQN value (for future use)
51699a2dd95SBruce Richardson * - cut of ICV, ESP tail and padding bytes
51799a2dd95SBruce Richardson * - cut of ESP header and IV
51899a2dd95SBruce Richardson * - move L2/L3 header to fill the gap after ESP header removal
51999a2dd95SBruce Richardson */
52099a2dd95SBruce Richardson static inline void *
trs_process_step2(struct rte_mbuf * mb,struct rte_mbuf * ml,uint32_t hlen,uint32_t adj,uint32_t tofs,uint32_t tlen,uint32_t * sqn)52199a2dd95SBruce Richardson trs_process_step2(struct rte_mbuf *mb, struct rte_mbuf *ml, uint32_t hlen,
52299a2dd95SBruce Richardson uint32_t adj, uint32_t tofs, uint32_t tlen, uint32_t *sqn)
52399a2dd95SBruce Richardson {
52499a2dd95SBruce Richardson char *np, *op;
52599a2dd95SBruce Richardson
52699a2dd95SBruce Richardson /* get start of the packet before modifications */
52799a2dd95SBruce Richardson op = rte_pktmbuf_mtod(mb, char *);
52899a2dd95SBruce Richardson
52999a2dd95SBruce Richardson /* cut off ESP header and IV */
53099a2dd95SBruce Richardson np = tun_process_step2(mb, ml, hlen, adj, tofs, tlen, sqn);
53199a2dd95SBruce Richardson
53299a2dd95SBruce Richardson /* move header bytes to fill the gap after ESP header removal */
53399a2dd95SBruce Richardson remove_esph(np, op, hlen);
53499a2dd95SBruce Richardson return np;
53599a2dd95SBruce Richardson }
53699a2dd95SBruce Richardson
53799a2dd95SBruce Richardson /*
53899a2dd95SBruce Richardson * step three for transport mode:
53999a2dd95SBruce Richardson * update mbuf metadata:
54099a2dd95SBruce Richardson * - packet_type
54199a2dd95SBruce Richardson * - ol_flags
54299a2dd95SBruce Richardson */
54399a2dd95SBruce Richardson static inline void
trs_process_step3(struct rte_mbuf * mb)54499a2dd95SBruce Richardson trs_process_step3(struct rte_mbuf *mb)
54599a2dd95SBruce Richardson {
54699a2dd95SBruce Richardson /* reset mbuf packet type */
54799a2dd95SBruce Richardson mb->packet_type &= (RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK);
54899a2dd95SBruce Richardson
549daa02b5cSOlivier Matz /* clear the RTE_MBUF_F_RX_SEC_OFFLOAD flag if set */
550daa02b5cSOlivier Matz mb->ol_flags &= ~RTE_MBUF_F_RX_SEC_OFFLOAD;
55199a2dd95SBruce Richardson }
55299a2dd95SBruce Richardson
55399a2dd95SBruce Richardson /*
55499a2dd95SBruce Richardson * step three for tunnel mode:
55599a2dd95SBruce Richardson * update mbuf metadata:
55699a2dd95SBruce Richardson * - packet_type
55799a2dd95SBruce Richardson * - ol_flags
55899a2dd95SBruce Richardson * - tx_offload
55999a2dd95SBruce Richardson */
56099a2dd95SBruce Richardson static inline void
tun_process_step3(struct rte_mbuf * mb,uint64_t txof_msk,uint64_t txof_val)56199a2dd95SBruce Richardson tun_process_step3(struct rte_mbuf *mb, uint64_t txof_msk, uint64_t txof_val)
56299a2dd95SBruce Richardson {
563*4a6672c2SStephen Hemminger /* reset mbuf metadata: L2/L3 len, packet type */
56499a2dd95SBruce Richardson mb->packet_type = RTE_PTYPE_UNKNOWN;
56599a2dd95SBruce Richardson mb->tx_offload = (mb->tx_offload & txof_msk) | txof_val;
56699a2dd95SBruce Richardson
567daa02b5cSOlivier Matz /* clear the RTE_MBUF_F_RX_SEC_OFFLOAD flag if set */
568daa02b5cSOlivier Matz mb->ol_flags &= ~RTE_MBUF_F_RX_SEC_OFFLOAD;
56999a2dd95SBruce Richardson }
57099a2dd95SBruce Richardson
57199a2dd95SBruce Richardson /*
57299a2dd95SBruce Richardson * *process* function for tunnel packets
57399a2dd95SBruce Richardson */
57499a2dd95SBruce Richardson static inline uint16_t
tun_process(struct rte_ipsec_sa * sa,struct rte_mbuf * mb[],uint32_t sqn[],uint32_t dr[],uint16_t num,uint8_t sqh_len)57568977baaSRadu Nicolau tun_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
57699a2dd95SBruce Richardson uint32_t sqn[], uint32_t dr[], uint16_t num, uint8_t sqh_len)
57799a2dd95SBruce Richardson {
57868977baaSRadu Nicolau uint32_t adj, i, k, tl, bytes;
57999a2dd95SBruce Richardson uint32_t hl[num], to[num];
58099a2dd95SBruce Richardson struct rte_esp_tail espt[num];
58199a2dd95SBruce Richardson struct rte_mbuf *ml[num];
58299a2dd95SBruce Richardson const void *outh;
58399a2dd95SBruce Richardson void *inh;
58499a2dd95SBruce Richardson
58599a2dd95SBruce Richardson /*
58699a2dd95SBruce Richardson * remove icv, esp trailer and high-order
58799a2dd95SBruce Richardson * 32 bits of esn from packet length
58899a2dd95SBruce Richardson */
58999a2dd95SBruce Richardson const uint32_t tlen = sa->icv_len + sizeof(espt[0]) + sqh_len;
59099a2dd95SBruce Richardson const uint32_t cofs = sa->ctp.cipher.offset;
59199a2dd95SBruce Richardson
59299a2dd95SBruce Richardson /*
59399a2dd95SBruce Richardson * to minimize stalls due to load latency,
59499a2dd95SBruce Richardson * read mbufs metadata and esp tail first.
59599a2dd95SBruce Richardson */
59699a2dd95SBruce Richardson for (i = 0; i != num; i++)
59799a2dd95SBruce Richardson process_step1(mb[i], tlen, &ml[i], &espt[i], &hl[i], &to[i]);
59899a2dd95SBruce Richardson
59999a2dd95SBruce Richardson k = 0;
60068977baaSRadu Nicolau bytes = 0;
60199a2dd95SBruce Richardson for (i = 0; i != num; i++) {
60299a2dd95SBruce Richardson
60399a2dd95SBruce Richardson adj = hl[i] + cofs;
60499a2dd95SBruce Richardson tl = tlen + espt[i].pad_len;
60599a2dd95SBruce Richardson
60699a2dd95SBruce Richardson /* check that packet is valid */
60799a2dd95SBruce Richardson if (tun_process_check(mb[i], &ml[i], &to[i], espt[i], adj, tl,
60899a2dd95SBruce Richardson sa->proto) == 0) {
60999a2dd95SBruce Richardson
61099a2dd95SBruce Richardson outh = rte_pktmbuf_mtod_offset(mb[i], uint8_t *,
61199a2dd95SBruce Richardson mb[i]->l2_len);
61299a2dd95SBruce Richardson
61399a2dd95SBruce Richardson /* modify packet's layout */
61499a2dd95SBruce Richardson inh = tun_process_step2(mb[i], ml[i], hl[i], adj,
61599a2dd95SBruce Richardson to[i], tl, sqn + k);
61699a2dd95SBruce Richardson
61799a2dd95SBruce Richardson /* update inner ip header */
61899a2dd95SBruce Richardson update_tun_inb_l3hdr(sa, outh, inh);
61999a2dd95SBruce Richardson
62099a2dd95SBruce Richardson /* update mbuf's metadata */
62199a2dd95SBruce Richardson tun_process_step3(mb[i], sa->tx_offload.msk,
62299a2dd95SBruce Richardson sa->tx_offload.val);
62399a2dd95SBruce Richardson k++;
62468977baaSRadu Nicolau bytes += mb[i]->pkt_len;
62599a2dd95SBruce Richardson } else
62699a2dd95SBruce Richardson dr[i - k] = i;
62799a2dd95SBruce Richardson }
62899a2dd95SBruce Richardson
62968977baaSRadu Nicolau sa->statistics.count += k;
63068977baaSRadu Nicolau sa->statistics.bytes += bytes;
63199a2dd95SBruce Richardson return k;
63299a2dd95SBruce Richardson }
63399a2dd95SBruce Richardson
63499a2dd95SBruce Richardson /*
63599a2dd95SBruce Richardson * *process* function for tunnel packets
63699a2dd95SBruce Richardson */
63799a2dd95SBruce Richardson static inline uint16_t
trs_process(struct rte_ipsec_sa * sa,struct rte_mbuf * mb[],uint32_t sqn[],uint32_t dr[],uint16_t num,uint8_t sqh_len)63868977baaSRadu Nicolau trs_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
63999a2dd95SBruce Richardson uint32_t sqn[], uint32_t dr[], uint16_t num, uint8_t sqh_len)
64099a2dd95SBruce Richardson {
64199a2dd95SBruce Richardson char *np;
64268977baaSRadu Nicolau uint32_t i, k, l2, tl, bytes;
64399a2dd95SBruce Richardson uint32_t hl[num], to[num];
64499a2dd95SBruce Richardson struct rte_esp_tail espt[num];
64599a2dd95SBruce Richardson struct rte_mbuf *ml[num];
64699a2dd95SBruce Richardson
64799a2dd95SBruce Richardson /*
64899a2dd95SBruce Richardson * remove icv, esp trailer and high-order
64999a2dd95SBruce Richardson * 32 bits of esn from packet length
65099a2dd95SBruce Richardson */
65199a2dd95SBruce Richardson const uint32_t tlen = sa->icv_len + sizeof(espt[0]) + sqh_len;
65299a2dd95SBruce Richardson const uint32_t cofs = sa->ctp.cipher.offset;
65399a2dd95SBruce Richardson
65499a2dd95SBruce Richardson /*
65599a2dd95SBruce Richardson * to minimize stalls due to load latency,
65699a2dd95SBruce Richardson * read mbufs metadata and esp tail first.
65799a2dd95SBruce Richardson */
65899a2dd95SBruce Richardson for (i = 0; i != num; i++)
65999a2dd95SBruce Richardson process_step1(mb[i], tlen, &ml[i], &espt[i], &hl[i], &to[i]);
66099a2dd95SBruce Richardson
66199a2dd95SBruce Richardson k = 0;
66268977baaSRadu Nicolau bytes = 0;
66399a2dd95SBruce Richardson for (i = 0; i != num; i++) {
66499a2dd95SBruce Richardson
66599a2dd95SBruce Richardson tl = tlen + espt[i].pad_len;
66699a2dd95SBruce Richardson l2 = mb[i]->l2_len;
66799a2dd95SBruce Richardson
66899a2dd95SBruce Richardson /* check that packet is valid */
66999a2dd95SBruce Richardson if (trs_process_check(mb[i], &ml[i], &to[i], espt[i],
67099a2dd95SBruce Richardson hl[i] + cofs, tl) == 0) {
67199a2dd95SBruce Richardson
67299a2dd95SBruce Richardson /* modify packet's layout */
67399a2dd95SBruce Richardson np = trs_process_step2(mb[i], ml[i], hl[i], cofs,
67499a2dd95SBruce Richardson to[i], tl, sqn + k);
67599a2dd95SBruce Richardson update_trs_l3hdr(sa, np + l2, mb[i]->pkt_len,
67699a2dd95SBruce Richardson l2, hl[i] - l2, espt[i].next_proto);
67799a2dd95SBruce Richardson
67899a2dd95SBruce Richardson /* update mbuf's metadata */
67999a2dd95SBruce Richardson trs_process_step3(mb[i]);
68099a2dd95SBruce Richardson k++;
68168977baaSRadu Nicolau bytes += mb[i]->pkt_len;
68299a2dd95SBruce Richardson } else
68399a2dd95SBruce Richardson dr[i - k] = i;
68499a2dd95SBruce Richardson }
68599a2dd95SBruce Richardson
68668977baaSRadu Nicolau sa->statistics.count += k;
68768977baaSRadu Nicolau sa->statistics.bytes += bytes;
68899a2dd95SBruce Richardson return k;
68999a2dd95SBruce Richardson }
69099a2dd95SBruce Richardson
69199a2dd95SBruce Richardson /*
69299a2dd95SBruce Richardson * for group of ESP inbound packets perform SQN check and update.
69399a2dd95SBruce Richardson */
69499a2dd95SBruce Richardson static inline uint16_t
esp_inb_rsn_update(struct rte_ipsec_sa * sa,const uint32_t sqn[],uint32_t dr[],uint16_t num)69599a2dd95SBruce Richardson esp_inb_rsn_update(struct rte_ipsec_sa *sa, const uint32_t sqn[],
69699a2dd95SBruce Richardson uint32_t dr[], uint16_t num)
69799a2dd95SBruce Richardson {
69899a2dd95SBruce Richardson uint32_t i, k;
69999a2dd95SBruce Richardson struct replay_sqn *rsn;
70099a2dd95SBruce Richardson
70199a2dd95SBruce Richardson /* replay not enabled */
70299a2dd95SBruce Richardson if (sa->replay.win_sz == 0)
70399a2dd95SBruce Richardson return num;
70499a2dd95SBruce Richardson
70599a2dd95SBruce Richardson rsn = rsn_update_start(sa);
70699a2dd95SBruce Richardson
70799a2dd95SBruce Richardson k = 0;
70899a2dd95SBruce Richardson for (i = 0; i != num; i++) {
70999a2dd95SBruce Richardson if (esn_inb_update_sqn(rsn, sa, rte_be_to_cpu_32(sqn[i])) == 0)
71099a2dd95SBruce Richardson k++;
71199a2dd95SBruce Richardson else
71299a2dd95SBruce Richardson dr[i - k] = i;
71399a2dd95SBruce Richardson }
71499a2dd95SBruce Richardson
71599a2dd95SBruce Richardson rsn_update_finish(sa, rsn);
71699a2dd95SBruce Richardson return k;
71799a2dd95SBruce Richardson }
71899a2dd95SBruce Richardson
71999a2dd95SBruce Richardson /*
72099a2dd95SBruce Richardson * process group of ESP inbound packets.
72199a2dd95SBruce Richardson */
72299a2dd95SBruce Richardson static inline uint16_t
esp_inb_pkt_process(struct rte_ipsec_sa * sa,struct rte_mbuf * mb[],uint16_t num,uint8_t sqh_len,esp_inb_process_t process)72399a2dd95SBruce Richardson esp_inb_pkt_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
72499a2dd95SBruce Richardson uint16_t num, uint8_t sqh_len, esp_inb_process_t process)
72599a2dd95SBruce Richardson {
72699a2dd95SBruce Richardson uint32_t k, n;
72799a2dd95SBruce Richardson uint32_t sqn[num];
72899a2dd95SBruce Richardson uint32_t dr[num];
72999a2dd95SBruce Richardson
73099a2dd95SBruce Richardson /* process packets, extract seq numbers */
73199a2dd95SBruce Richardson k = process(sa, mb, sqn, dr, num, sqh_len);
73299a2dd95SBruce Richardson
73399a2dd95SBruce Richardson /* handle unprocessed mbufs */
73499a2dd95SBruce Richardson if (k != num && k != 0)
73599a2dd95SBruce Richardson move_bad_mbufs(mb, dr, num, num - k);
73699a2dd95SBruce Richardson
73799a2dd95SBruce Richardson /* update SQN and replay window */
73899a2dd95SBruce Richardson n = esp_inb_rsn_update(sa, sqn, dr, k);
73999a2dd95SBruce Richardson
74099a2dd95SBruce Richardson /* handle mbufs with wrong SQN */
74199a2dd95SBruce Richardson if (n != k && n != 0)
74299a2dd95SBruce Richardson move_bad_mbufs(mb, dr, k, k - n);
74399a2dd95SBruce Richardson
74499a2dd95SBruce Richardson if (n != num)
74599a2dd95SBruce Richardson rte_errno = EBADMSG;
74699a2dd95SBruce Richardson
74799a2dd95SBruce Richardson return n;
74899a2dd95SBruce Richardson }
74999a2dd95SBruce Richardson
75099a2dd95SBruce Richardson /*
75199a2dd95SBruce Richardson * Prepare (plus actual crypto/auth) routine for inbound CPU-CRYPTO
75299a2dd95SBruce Richardson * (synchronous mode).
75399a2dd95SBruce Richardson */
75499a2dd95SBruce Richardson uint16_t
cpu_inb_pkt_prepare(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],uint16_t num)75599a2dd95SBruce Richardson cpu_inb_pkt_prepare(const struct rte_ipsec_session *ss,
75699a2dd95SBruce Richardson struct rte_mbuf *mb[], uint16_t num)
75799a2dd95SBruce Richardson {
75899a2dd95SBruce Richardson int32_t rc;
75999a2dd95SBruce Richardson uint32_t i, k;
76099a2dd95SBruce Richardson struct rte_ipsec_sa *sa;
76199a2dd95SBruce Richardson struct replay_sqn *rsn;
76299a2dd95SBruce Richardson union sym_op_data icv;
76399a2dd95SBruce Richardson struct rte_crypto_va_iova_ptr iv[num];
76499a2dd95SBruce Richardson struct rte_crypto_va_iova_ptr aad[num];
76599a2dd95SBruce Richardson struct rte_crypto_va_iova_ptr dgst[num];
76699a2dd95SBruce Richardson uint32_t dr[num];
76799a2dd95SBruce Richardson uint32_t l4ofs[num];
76899a2dd95SBruce Richardson uint32_t clen[num];
76999a2dd95SBruce Richardson uint64_t ivbuf[num][IPSEC_MAX_IV_QWORD];
77099a2dd95SBruce Richardson
77199a2dd95SBruce Richardson sa = ss->sa;
77299a2dd95SBruce Richardson
77399a2dd95SBruce Richardson /* grab rsn lock */
77499a2dd95SBruce Richardson rsn = rsn_acquire(sa);
77599a2dd95SBruce Richardson
77699a2dd95SBruce Richardson /* do preparation for all packets */
77799a2dd95SBruce Richardson for (i = 0, k = 0; i != num; i++) {
77899a2dd95SBruce Richardson
77999a2dd95SBruce Richardson /* calculate ESP header offset */
78099a2dd95SBruce Richardson l4ofs[k] = mb[i]->l2_len + mb[i]->l3_len;
78199a2dd95SBruce Richardson
78299a2dd95SBruce Richardson /* prepare ESP packet for processing */
78399a2dd95SBruce Richardson rc = inb_pkt_prepare(sa, rsn, mb[i], l4ofs[k], &icv);
78499a2dd95SBruce Richardson if (rc >= 0) {
78599a2dd95SBruce Richardson /* get encrypted data offset and length */
78699a2dd95SBruce Richardson clen[k] = inb_cpu_crypto_prepare(sa, mb[i],
78799a2dd95SBruce Richardson l4ofs + k, rc, ivbuf[k]);
78899a2dd95SBruce Richardson
78999a2dd95SBruce Richardson /* fill iv, digest and aad */
79099a2dd95SBruce Richardson iv[k].va = ivbuf[k];
79199a2dd95SBruce Richardson aad[k].va = icv.va + sa->icv_len;
79299a2dd95SBruce Richardson dgst[k++].va = icv.va;
79399a2dd95SBruce Richardson } else {
79499a2dd95SBruce Richardson dr[i - k] = i;
79599a2dd95SBruce Richardson rte_errno = -rc;
79699a2dd95SBruce Richardson }
79799a2dd95SBruce Richardson }
79899a2dd95SBruce Richardson
79999a2dd95SBruce Richardson /* release rsn lock */
80099a2dd95SBruce Richardson rsn_release(sa, rsn);
80199a2dd95SBruce Richardson
80299a2dd95SBruce Richardson /* copy not prepared mbufs beyond good ones */
80399a2dd95SBruce Richardson if (k != num && k != 0)
80499a2dd95SBruce Richardson move_bad_mbufs(mb, dr, num, num - k);
80599a2dd95SBruce Richardson
80699a2dd95SBruce Richardson /* convert mbufs to iovecs and do actual crypto/auth processing */
80799a2dd95SBruce Richardson if (k != 0)
80899a2dd95SBruce Richardson cpu_crypto_bulk(ss, sa->cofs, mb, iv, aad, dgst,
80999a2dd95SBruce Richardson l4ofs, clen, k);
81099a2dd95SBruce Richardson return k;
81199a2dd95SBruce Richardson }
81299a2dd95SBruce Richardson
81399a2dd95SBruce Richardson /*
81499a2dd95SBruce Richardson * process group of ESP inbound tunnel packets.
81599a2dd95SBruce Richardson */
81699a2dd95SBruce Richardson uint16_t
esp_inb_tun_pkt_process(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],uint16_t num)81799a2dd95SBruce Richardson esp_inb_tun_pkt_process(const struct rte_ipsec_session *ss,
81899a2dd95SBruce Richardson struct rte_mbuf *mb[], uint16_t num)
81999a2dd95SBruce Richardson {
82099a2dd95SBruce Richardson struct rte_ipsec_sa *sa = ss->sa;
82199a2dd95SBruce Richardson
82299a2dd95SBruce Richardson return esp_inb_pkt_process(sa, mb, num, sa->sqh_len, tun_process);
82399a2dd95SBruce Richardson }
82499a2dd95SBruce Richardson
82599a2dd95SBruce Richardson uint16_t
inline_inb_tun_pkt_process(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],uint16_t num)82699a2dd95SBruce Richardson inline_inb_tun_pkt_process(const struct rte_ipsec_session *ss,
82799a2dd95SBruce Richardson struct rte_mbuf *mb[], uint16_t num)
82899a2dd95SBruce Richardson {
82999a2dd95SBruce Richardson return esp_inb_pkt_process(ss->sa, mb, num, 0, tun_process);
83099a2dd95SBruce Richardson }
83199a2dd95SBruce Richardson
83299a2dd95SBruce Richardson /*
83399a2dd95SBruce Richardson * process group of ESP inbound transport packets.
83499a2dd95SBruce Richardson */
83599a2dd95SBruce Richardson uint16_t
esp_inb_trs_pkt_process(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],uint16_t num)83699a2dd95SBruce Richardson esp_inb_trs_pkt_process(const struct rte_ipsec_session *ss,
83799a2dd95SBruce Richardson struct rte_mbuf *mb[], uint16_t num)
83899a2dd95SBruce Richardson {
83999a2dd95SBruce Richardson struct rte_ipsec_sa *sa = ss->sa;
84099a2dd95SBruce Richardson
84199a2dd95SBruce Richardson return esp_inb_pkt_process(sa, mb, num, sa->sqh_len, trs_process);
84299a2dd95SBruce Richardson }
84399a2dd95SBruce Richardson
84499a2dd95SBruce Richardson uint16_t
inline_inb_trs_pkt_process(const struct rte_ipsec_session * ss,struct rte_mbuf * mb[],uint16_t num)84599a2dd95SBruce Richardson inline_inb_trs_pkt_process(const struct rte_ipsec_session *ss,
84699a2dd95SBruce Richardson struct rte_mbuf *mb[], uint16_t num)
84799a2dd95SBruce Richardson {
84899a2dd95SBruce Richardson return esp_inb_pkt_process(ss->sa, mb, num, 0, trs_process);
84999a2dd95SBruce Richardson }
850