ipsec: support AES-CTR
[dpdk.git] / lib / librte_ipsec / sa.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <rte_ipsec.h>
6 #include <rte_esp.h>
7 #include <rte_ip.h>
8 #include <rte_errno.h>
9 #include <rte_cryptodev.h>
10
11 #include "sa.h"
12 #include "ipsec_sqn.h"
13 #include "crypto.h"
14 #include "iph.h"
15 #include "pad.h"
16
17 /* some helper structures */
18 struct crypto_xform {
19         struct rte_crypto_auth_xform *auth;
20         struct rte_crypto_cipher_xform *cipher;
21         struct rte_crypto_aead_xform *aead;
22 };
23
24 /*
25  * helper routine, fills internal crypto_xform structure.
26  */
27 static int
28 fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
29         const struct rte_ipsec_sa_prm *prm)
30 {
31         struct rte_crypto_sym_xform *xf, *xfn;
32
33         memset(xform, 0, sizeof(*xform));
34
35         xf = prm->crypto_xform;
36         if (xf == NULL)
37                 return -EINVAL;
38
39         xfn = xf->next;
40
41         /* for AEAD just one xform required */
42         if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
43                 if (xfn != NULL)
44                         return -EINVAL;
45                 xform->aead = &xf->aead;
46         /*
47          * CIPHER+AUTH xforms are expected in strict order,
48          * depending on SA direction:
49          * inbound: AUTH+CIPHER
50          * outbound: CIPHER+AUTH
51          */
52         } else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
53
54                 /* wrong order or no cipher */
55                 if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
56                                 xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
57                         return -EINVAL;
58
59                 xform->auth = &xf->auth;
60                 xform->cipher = &xfn->cipher;
61
62         } else {
63
64                 /* wrong order or no auth */
65                 if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
66                                 xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
67                         return -EINVAL;
68
69                 xform->cipher = &xf->cipher;
70                 xform->auth = &xfn->auth;
71         }
72
73         return 0;
74 }
75
76 uint64_t __rte_experimental
77 rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
78 {
79         return sa->type;
80 }
81
82 static int32_t
83 ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
84 {
85         uint32_t n, sz, wsz;
86
87         wsz = *wnd_sz;
88         n = 0;
89
90         if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
91
92                 /*
93                  * RFC 4303 recommends 64 as minimum window size.
94                  * there is no point to use ESN mode without SQN window,
95                  * so make sure we have at least 64 window when ESN is enalbed.
96                  */
97                 wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
98                         RTE_IPSEC_SATP_ESN_DISABLE) ?
99                         wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
100                 if (wsz != 0)
101                         n = replay_num_bucket(wsz);
102         }
103
104         if (n > WINDOW_BUCKET_MAX)
105                 return -EINVAL;
106
107         *wnd_sz = wsz;
108         *nb_bucket = n;
109
110         sz = rsn_size(n);
111         if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
112                 sz *= REPLAY_SQN_NUM;
113
114         sz += sizeof(struct rte_ipsec_sa);
115         return sz;
116 }
117
118 void __rte_experimental
119 rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
120 {
121         memset(sa, 0, sa->size);
122 }
123
124 /*
125  * Determine expected SA type based on input parameters.
126  */
127 static int
128 fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
129 {
130         uint64_t tp;
131
132         tp = 0;
133
134         if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
135                 tp |= RTE_IPSEC_SATP_PROTO_AH;
136         else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
137                 tp |= RTE_IPSEC_SATP_PROTO_ESP;
138         else
139                 return -EINVAL;
140
141         if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
142                 tp |= RTE_IPSEC_SATP_DIR_OB;
143         else if (prm->ipsec_xform.direction ==
144                         RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
145                 tp |= RTE_IPSEC_SATP_DIR_IB;
146         else
147                 return -EINVAL;
148
149         if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
150                 if (prm->ipsec_xform.tunnel.type ==
151                                 RTE_SECURITY_IPSEC_TUNNEL_IPV4)
152                         tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
153                 else if (prm->ipsec_xform.tunnel.type ==
154                                 RTE_SECURITY_IPSEC_TUNNEL_IPV6)
155                         tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
156                 else
157                         return -EINVAL;
158
159                 if (prm->tun.next_proto == IPPROTO_IPIP)
160                         tp |= RTE_IPSEC_SATP_IPV4;
161                 else if (prm->tun.next_proto == IPPROTO_IPV6)
162                         tp |= RTE_IPSEC_SATP_IPV6;
163                 else
164                         return -EINVAL;
165         } else if (prm->ipsec_xform.mode ==
166                         RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
167                 tp |= RTE_IPSEC_SATP_MODE_TRANS;
168                 if (prm->trs.proto == IPPROTO_IPIP)
169                         tp |= RTE_IPSEC_SATP_IPV4;
170                 else if (prm->trs.proto == IPPROTO_IPV6)
171                         tp |= RTE_IPSEC_SATP_IPV6;
172                 else
173                         return -EINVAL;
174         } else
175                 return -EINVAL;
176
177         /* check for ESN flag */
178         if (prm->ipsec_xform.options.esn == 0)
179                 tp |= RTE_IPSEC_SATP_ESN_DISABLE;
180         else
181                 tp |= RTE_IPSEC_SATP_ESN_ENABLE;
182
183         /* interpret flags */
184         if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
185                 tp |= RTE_IPSEC_SATP_SQN_ATOM;
186         else
187                 tp |= RTE_IPSEC_SATP_SQN_RAW;
188
189         *type = tp;
190         return 0;
191 }
192
193 /*
194  * Init ESP inbound specific things.
195  */
196 static void
197 esp_inb_init(struct rte_ipsec_sa *sa)
198 {
199         /* these params may differ with new algorithms support */
200         sa->ctp.auth.offset = 0;
201         sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
202         sa->ctp.cipher.offset = sizeof(struct esp_hdr) + sa->iv_len;
203         sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
204 }
205
206 /*
207  * Init ESP inbound tunnel specific things.
208  */
209 static void
210 esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
211 {
212         sa->proto = prm->tun.next_proto;
213         esp_inb_init(sa);
214 }
215
216 /*
217  * Init ESP outbound specific things.
218  */
219 static void
220 esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
221 {
222         uint8_t algo_type;
223
224         sa->sqn.outb.raw = 1;
225
226         /* these params may differ with new algorithms support */
227         sa->ctp.auth.offset = hlen;
228         sa->ctp.auth.length = sizeof(struct esp_hdr) + sa->iv_len + sa->sqh_len;
229
230         algo_type = sa->algo_type;
231
232         switch (algo_type) {
233         case ALGO_TYPE_AES_GCM:
234         case ALGO_TYPE_AES_CTR:
235         case ALGO_TYPE_NULL:
236                 sa->ctp.cipher.offset = hlen + sizeof(struct esp_hdr) +
237                         sa->iv_len;
238                 sa->ctp.cipher.length = 0;
239                 break;
240         case ALGO_TYPE_AES_CBC:
241                 sa->ctp.cipher.offset = sa->hdr_len + sizeof(struct esp_hdr);
242                 sa->ctp.cipher.length = sa->iv_len;
243                 break;
244         }
245 }
246
247 /*
248  * Init ESP outbound tunnel specific things.
249  */
250 static void
251 esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
252 {
253         sa->proto = prm->tun.next_proto;
254         sa->hdr_len = prm->tun.hdr_len;
255         sa->hdr_l3_off = prm->tun.hdr_l3_off;
256         memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
257
258         esp_outb_init(sa, sa->hdr_len);
259 }
260
261 /*
262  * helper function, init SA structure.
263  */
264 static int
265 esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
266         const struct crypto_xform *cxf)
267 {
268         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
269                                 RTE_IPSEC_SATP_MODE_MASK;
270
271         if (cxf->aead != NULL) {
272                 switch (cxf->aead->algo) {
273                 case RTE_CRYPTO_AEAD_AES_GCM:
274                         /* RFC 4106 */
275                         sa->aad_len = sizeof(struct aead_gcm_aad);
276                         sa->icv_len = cxf->aead->digest_length;
277                         sa->iv_ofs = cxf->aead->iv.offset;
278                         sa->iv_len = sizeof(uint64_t);
279                         sa->pad_align = IPSEC_PAD_AES_GCM;
280                         sa->algo_type = ALGO_TYPE_AES_GCM;
281                         break;
282                 default:
283                         return -EINVAL;
284                 }
285         } else {
286                 sa->icv_len = cxf->auth->digest_length;
287                 sa->iv_ofs = cxf->cipher->iv.offset;
288                 sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
289
290                 switch (cxf->cipher->algo) {
291                 case RTE_CRYPTO_CIPHER_NULL:
292                         sa->pad_align = IPSEC_PAD_NULL;
293                         sa->iv_len = 0;
294                         sa->algo_type = ALGO_TYPE_NULL;
295                         break;
296
297                 case RTE_CRYPTO_CIPHER_AES_CBC:
298                         sa->pad_align = IPSEC_PAD_AES_CBC;
299                         sa->iv_len = IPSEC_MAX_IV_SIZE;
300                         sa->algo_type = ALGO_TYPE_AES_CBC;
301                         break;
302
303                 case RTE_CRYPTO_CIPHER_AES_CTR:
304                         /* RFC 3686 */
305                         sa->pad_align = IPSEC_PAD_AES_CTR;
306                         sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
307                         sa->algo_type = ALGO_TYPE_AES_CTR;
308                         break;
309
310                 default:
311                         return -EINVAL;
312                 }
313         }
314
315         sa->udata = prm->userdata;
316         sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
317         sa->salt = prm->ipsec_xform.salt;
318
319         switch (sa->type & msk) {
320         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
321         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
322                 esp_inb_tun_init(sa, prm);
323                 break;
324         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
325                 esp_inb_init(sa);
326                 break;
327         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
328         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
329                 esp_outb_tun_init(sa, prm);
330                 break;
331         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
332                 esp_outb_init(sa, 0);
333                 break;
334         }
335
336         return 0;
337 }
338
339 /*
340  * helper function, init SA replay structure.
341  */
342 static void
343 fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket)
344 {
345         sa->replay.win_sz = wnd_sz;
346         sa->replay.nb_bucket = nb_bucket;
347         sa->replay.bucket_index_mask = nb_bucket - 1;
348         sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
349         if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
350                 sa->sqn.inb.rsn[1] = (struct replay_sqn *)
351                         ((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
352 }
353
354 int __rte_experimental
355 rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
356 {
357         uint64_t type;
358         uint32_t nb, wsz;
359         int32_t rc;
360
361         if (prm == NULL)
362                 return -EINVAL;
363
364         /* determine SA type */
365         rc = fill_sa_type(prm, &type);
366         if (rc != 0)
367                 return rc;
368
369         /* determine required size */
370         wsz = prm->replay_win_sz;
371         return ipsec_sa_size(type, &wsz, &nb);
372 }
373
374 int __rte_experimental
375 rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
376         uint32_t size)
377 {
378         int32_t rc, sz;
379         uint32_t nb, wsz;
380         uint64_t type;
381         struct crypto_xform cxf;
382
383         if (sa == NULL || prm == NULL)
384                 return -EINVAL;
385
386         /* determine SA type */
387         rc = fill_sa_type(prm, &type);
388         if (rc != 0)
389                 return rc;
390
391         /* determine required size */
392         wsz = prm->replay_win_sz;
393         sz = ipsec_sa_size(type, &wsz, &nb);
394         if (sz < 0)
395                 return sz;
396         else if (size < (uint32_t)sz)
397                 return -ENOSPC;
398
399         /* only esp is supported right now */
400         if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
401                 return -EINVAL;
402
403         if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
404                         prm->tun.hdr_len > sizeof(sa->hdr))
405                 return -EINVAL;
406
407         rc = fill_crypto_xform(&cxf, type, prm);
408         if (rc != 0)
409                 return rc;
410
411         /* initialize SA */
412
413         memset(sa, 0, sz);
414         sa->type = type;
415         sa->size = sz;
416
417         /* check for ESN flag */
418         sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
419                 UINT32_MAX : UINT64_MAX;
420
421         rc = esp_sa_init(sa, prm, &cxf);
422         if (rc != 0)
423                 rte_ipsec_sa_fini(sa);
424
425         /* fill replay window related fields */
426         if (nb != 0)
427                 fill_sa_replay(sa, wsz, nb);
428
429         return sz;
430 }
431
432 static inline void
433 mbuf_bulk_copy(struct rte_mbuf *dst[], struct rte_mbuf * const src[],
434         uint32_t num)
435 {
436         uint32_t i;
437
438         for (i = 0; i != num; i++)
439                 dst[i] = src[i];
440 }
441
442 /*
443  * setup crypto ops for LOOKASIDE_NONE (pure crypto) type of devices.
444  */
445 static inline void
446 lksd_none_cop_prepare(const struct rte_ipsec_session *ss,
447         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
448 {
449         uint32_t i;
450         struct rte_crypto_sym_op *sop;
451
452         for (i = 0; i != num; i++) {
453                 sop = cop[i]->sym;
454                 cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
455                 cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
456                 cop[i]->sess_type = RTE_CRYPTO_OP_WITH_SESSION;
457                 sop->m_src = mb[i];
458                 __rte_crypto_sym_op_attach_sym_session(sop, ss->crypto.ses);
459         }
460 }
461
462 /*
463  * setup crypto op and crypto sym op for ESP outbound packet.
464  */
465 static inline void
466 esp_outb_cop_prepare(struct rte_crypto_op *cop,
467         const struct rte_ipsec_sa *sa, const uint64_t ivp[IPSEC_MAX_IV_QWORD],
468         const union sym_op_data *icv, uint32_t hlen, uint32_t plen)
469 {
470         struct rte_crypto_sym_op *sop;
471         struct aead_gcm_iv *gcm;
472         struct aesctr_cnt_blk *ctr;
473         uint8_t algo_type = sa->algo_type;
474
475         /* fill sym op fields */
476         sop = cop->sym;
477
478         switch (algo_type) {
479         case ALGO_TYPE_AES_GCM:
480                 /* AEAD (AES_GCM) case */
481                 sop->aead.data.offset = sa->ctp.cipher.offset + hlen;
482                 sop->aead.data.length = sa->ctp.cipher.length + plen;
483                 sop->aead.digest.data = icv->va;
484                 sop->aead.digest.phys_addr = icv->pa;
485                 sop->aead.aad.data = icv->va + sa->icv_len;
486                 sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
487
488                 /* fill AAD IV (located inside crypto op) */
489                 gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
490                         sa->iv_ofs);
491                 aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
492                 break;
493         case ALGO_TYPE_AES_CBC:
494                 /* Cipher-Auth (AES-CBC *) case */
495                 sop->cipher.data.offset = sa->ctp.cipher.offset + hlen;
496                 sop->cipher.data.length = sa->ctp.cipher.length + plen;
497                 sop->auth.data.offset = sa->ctp.auth.offset + hlen;
498                 sop->auth.data.length = sa->ctp.auth.length + plen;
499                 sop->auth.digest.data = icv->va;
500                 sop->auth.digest.phys_addr = icv->pa;
501                 break;
502         case ALGO_TYPE_AES_CTR:
503                 /* Cipher-Auth (AES-CTR *) case */
504                 sop->cipher.data.offset = sa->ctp.cipher.offset + hlen;
505                 sop->cipher.data.length = sa->ctp.cipher.length + plen;
506                 sop->auth.data.offset = sa->ctp.auth.offset + hlen;
507                 sop->auth.data.length = sa->ctp.auth.length + plen;
508                 sop->auth.digest.data = icv->va;
509                 sop->auth.digest.phys_addr = icv->pa;
510
511                 ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
512                         sa->iv_ofs);
513                 aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
514                 break;
515         case ALGO_TYPE_NULL:
516                 /* NULL case */
517                 sop->cipher.data.offset = sa->ctp.cipher.offset + hlen;
518                 sop->cipher.data.length = sa->ctp.cipher.length + plen;
519                 sop->auth.data.offset = sa->ctp.auth.offset + hlen;
520                 sop->auth.data.length = sa->ctp.auth.length + plen;
521                 sop->auth.digest.data = icv->va;
522                 sop->auth.digest.phys_addr = icv->pa;
523                 break;
524         default:
525                 break;
526         }
527 }
528
529 /*
530  * setup/update packet data and metadata for ESP outbound tunnel case.
531  */
532 static inline int32_t
533 esp_outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
534         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
535         union sym_op_data *icv)
536 {
537         uint32_t clen, hlen, l2len, pdlen, pdofs, plen, tlen;
538         struct rte_mbuf *ml;
539         struct esp_hdr *esph;
540         struct esp_tail *espt;
541         char *ph, *pt;
542         uint64_t *iv;
543
544         /* calculate extra header space required */
545         hlen = sa->hdr_len + sa->iv_len + sizeof(*esph);
546
547         /* size of ipsec protected data */
548         l2len = mb->l2_len;
549         plen = mb->pkt_len - mb->l2_len;
550
551         /* number of bytes to encrypt */
552         clen = plen + sizeof(*espt);
553         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
554
555         /* pad length + esp tail */
556         pdlen = clen - plen;
557         tlen = pdlen + sa->icv_len;
558
559         /* do append and prepend */
560         ml = rte_pktmbuf_lastseg(mb);
561         if (tlen + sa->sqh_len + sa->aad_len > rte_pktmbuf_tailroom(ml))
562                 return -ENOSPC;
563
564         /* prepend header */
565         ph = rte_pktmbuf_prepend(mb, hlen - l2len);
566         if (ph == NULL)
567                 return -ENOSPC;
568
569         /* append tail */
570         pdofs = ml->data_len;
571         ml->data_len += tlen;
572         mb->pkt_len += tlen;
573         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
574
575         /* update pkt l2/l3 len */
576         mb->l2_len = sa->hdr_l3_off;
577         mb->l3_len = sa->hdr_len - sa->hdr_l3_off;
578
579         /* copy tunnel pkt header */
580         rte_memcpy(ph, sa->hdr, sa->hdr_len);
581
582         /* update original and new ip header fields */
583         update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len, sa->hdr_l3_off,
584                         sqn_low16(sqc));
585
586         /* update spi, seqn and iv */
587         esph = (struct esp_hdr *)(ph + sa->hdr_len);
588         iv = (uint64_t *)(esph + 1);
589         copy_iv(iv, ivp, sa->iv_len);
590
591         esph->spi = sa->spi;
592         esph->seq = sqn_low32(sqc);
593
594         /* offset for ICV */
595         pdofs += pdlen + sa->sqh_len;
596
597         /* pad length */
598         pdlen -= sizeof(*espt);
599
600         /* copy padding data */
601         rte_memcpy(pt, esp_pad_bytes, pdlen);
602
603         /* update esp trailer */
604         espt = (struct esp_tail *)(pt + pdlen);
605         espt->pad_len = pdlen;
606         espt->next_proto = sa->proto;
607
608         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
609         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
610
611         return clen;
612 }
613
614 /*
615  * for pure cryptodev (lookaside none) depending on SA settings,
616  * we might have to write some extra data to the packet.
617  */
618 static inline void
619 outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
620         const union sym_op_data *icv)
621 {
622         uint32_t *psqh;
623         struct aead_gcm_aad *aad;
624         uint8_t algo_type = sa->algo_type;
625
626         /* insert SQN.hi between ESP trailer and ICV */
627         if (sa->sqh_len != 0) {
628                 psqh = (uint32_t *)(icv->va - sa->sqh_len);
629                 psqh[0] = sqn_hi32(sqc);
630         }
631
632         /*
633          * fill IV and AAD fields, if any (aad fields are placed after icv),
634          * right now we support only one AEAD algorithm: AES-GCM .
635          */
636         if (algo_type == ALGO_TYPE_AES_GCM) {
637                 aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
638                 aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
639         }
640 }
641
642 /*
643  * setup/update packets and crypto ops for ESP outbound tunnel case.
644  */
645 static uint16_t
646 outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
647         struct rte_crypto_op *cop[], uint16_t num)
648 {
649         int32_t rc;
650         uint32_t i, k, n;
651         uint64_t sqn;
652         rte_be64_t sqc;
653         struct rte_ipsec_sa *sa;
654         union sym_op_data icv;
655         uint64_t iv[IPSEC_MAX_IV_QWORD];
656         struct rte_mbuf *dr[num];
657
658         sa = ss->sa;
659
660         n = num;
661         sqn = esn_outb_update_sqn(sa, &n);
662         if (n != num)
663                 rte_errno = EOVERFLOW;
664
665         k = 0;
666         for (i = 0; i != n; i++) {
667
668                 sqc = rte_cpu_to_be_64(sqn + i);
669                 gen_iv(iv, sqc);
670
671                 /* try to update the packet itself */
672                 rc = esp_outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv);
673
674                 /* success, setup crypto op */
675                 if (rc >= 0) {
676                         mb[k] = mb[i];
677                         outb_pkt_xprepare(sa, sqc, &icv);
678                         esp_outb_cop_prepare(cop[k], sa, iv, &icv, 0, rc);
679                         k++;
680                 /* failure, put packet into the death-row */
681                 } else {
682                         dr[i - k] = mb[i];
683                         rte_errno = -rc;
684                 }
685         }
686
687         /* update cops */
688         lksd_none_cop_prepare(ss, mb, cop, k);
689
690          /* copy not prepared mbufs beyond good ones */
691         if (k != n && k != 0)
692                 mbuf_bulk_copy(mb + k, dr, n - k);
693
694         return k;
695 }
696
697 /*
698  * setup/update packet data and metadata for ESP outbound transport case.
699  */
700 static inline int32_t
701 esp_outb_trs_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
702         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
703         uint32_t l2len, uint32_t l3len, union sym_op_data *icv)
704 {
705         uint8_t np;
706         uint32_t clen, hlen, pdlen, pdofs, plen, tlen, uhlen;
707         struct rte_mbuf *ml;
708         struct esp_hdr *esph;
709         struct esp_tail *espt;
710         char *ph, *pt;
711         uint64_t *iv;
712
713         uhlen = l2len + l3len;
714         plen = mb->pkt_len - uhlen;
715
716         /* calculate extra header space required */
717         hlen = sa->iv_len + sizeof(*esph);
718
719         /* number of bytes to encrypt */
720         clen = plen + sizeof(*espt);
721         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
722
723         /* pad length + esp tail */
724         pdlen = clen - plen;
725         tlen = pdlen + sa->icv_len;
726
727         /* do append and insert */
728         ml = rte_pktmbuf_lastseg(mb);
729         if (tlen + sa->sqh_len + sa->aad_len > rte_pktmbuf_tailroom(ml))
730                 return -ENOSPC;
731
732         /* prepend space for ESP header */
733         ph = rte_pktmbuf_prepend(mb, hlen);
734         if (ph == NULL)
735                 return -ENOSPC;
736
737         /* append tail */
738         pdofs = ml->data_len;
739         ml->data_len += tlen;
740         mb->pkt_len += tlen;
741         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
742
743         /* shift L2/L3 headers */
744         insert_esph(ph, ph + hlen, uhlen);
745
746         /* update ip  header fields */
747         np = update_trs_l3hdr(sa, ph + l2len, mb->pkt_len, l2len, l3len,
748                         IPPROTO_ESP);
749
750         /* update spi, seqn and iv */
751         esph = (struct esp_hdr *)(ph + uhlen);
752         iv = (uint64_t *)(esph + 1);
753         copy_iv(iv, ivp, sa->iv_len);
754
755         esph->spi = sa->spi;
756         esph->seq = sqn_low32(sqc);
757
758         /* offset for ICV */
759         pdofs += pdlen + sa->sqh_len;
760
761         /* pad length */
762         pdlen -= sizeof(*espt);
763
764         /* copy padding data */
765         rte_memcpy(pt, esp_pad_bytes, pdlen);
766
767         /* update esp trailer */
768         espt = (struct esp_tail *)(pt + pdlen);
769         espt->pad_len = pdlen;
770         espt->next_proto = np;
771
772         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
773         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
774
775         return clen;
776 }
777
778 /*
779  * setup/update packets and crypto ops for ESP outbound transport case.
780  */
781 static uint16_t
782 outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
783         struct rte_crypto_op *cop[], uint16_t num)
784 {
785         int32_t rc;
786         uint32_t i, k, n, l2, l3;
787         uint64_t sqn;
788         rte_be64_t sqc;
789         struct rte_ipsec_sa *sa;
790         union sym_op_data icv;
791         uint64_t iv[IPSEC_MAX_IV_QWORD];
792         struct rte_mbuf *dr[num];
793
794         sa = ss->sa;
795
796         n = num;
797         sqn = esn_outb_update_sqn(sa, &n);
798         if (n != num)
799                 rte_errno = EOVERFLOW;
800
801         k = 0;
802         for (i = 0; i != n; i++) {
803
804                 l2 = mb[i]->l2_len;
805                 l3 = mb[i]->l3_len;
806
807                 sqc = rte_cpu_to_be_64(sqn + i);
808                 gen_iv(iv, sqc);
809
810                 /* try to update the packet itself */
811                 rc = esp_outb_trs_pkt_prepare(sa, sqc, iv, mb[i],
812                                 l2, l3, &icv);
813
814                 /* success, setup crypto op */
815                 if (rc >= 0) {
816                         mb[k] = mb[i];
817                         outb_pkt_xprepare(sa, sqc, &icv);
818                         esp_outb_cop_prepare(cop[k], sa, iv, &icv, l2 + l3, rc);
819                         k++;
820                 /* failure, put packet into the death-row */
821                 } else {
822                         dr[i - k] = mb[i];
823                         rte_errno = -rc;
824                 }
825         }
826
827         /* update cops */
828         lksd_none_cop_prepare(ss, mb, cop, k);
829
830         /* copy not prepared mbufs beyond good ones */
831         if (k != n && k != 0)
832                 mbuf_bulk_copy(mb + k, dr, n - k);
833
834         return k;
835 }
836
837 /*
838  * setup crypto op and crypto sym op for ESP inbound tunnel packet.
839  */
840 static inline int32_t
841 esp_inb_tun_cop_prepare(struct rte_crypto_op *cop,
842         const struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
843         const union sym_op_data *icv, uint32_t pofs, uint32_t plen)
844 {
845         struct rte_crypto_sym_op *sop;
846         struct aead_gcm_iv *gcm;
847         struct aesctr_cnt_blk *ctr;
848         uint64_t *ivc, *ivp;
849         uint32_t clen;
850         uint8_t algo_type = sa->algo_type;
851
852         clen = plen - sa->ctp.cipher.length;
853         if ((int32_t)clen < 0 || (clen & (sa->pad_align - 1)) != 0)
854                 return -EINVAL;
855
856         /* fill sym op fields */
857         sop = cop->sym;
858
859         switch (algo_type) {
860         case ALGO_TYPE_AES_GCM:
861                 sop->aead.data.offset = pofs + sa->ctp.cipher.offset;
862                 sop->aead.data.length = clen;
863                 sop->aead.digest.data = icv->va;
864                 sop->aead.digest.phys_addr = icv->pa;
865                 sop->aead.aad.data = icv->va + sa->icv_len;
866                 sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
867
868                 /* fill AAD IV (located inside crypto op) */
869                 gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
870                         sa->iv_ofs);
871                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
872                         pofs + sizeof(struct esp_hdr));
873                 aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
874                 break;
875         case ALGO_TYPE_AES_CBC:
876                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
877                 sop->cipher.data.length = clen;
878                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
879                 sop->auth.data.length = plen - sa->ctp.auth.length;
880                 sop->auth.digest.data = icv->va;
881                 sop->auth.digest.phys_addr = icv->pa;
882
883                 /* copy iv from the input packet to the cop */
884                 ivc = rte_crypto_op_ctod_offset(cop, uint64_t *, sa->iv_ofs);
885                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
886                         pofs + sizeof(struct esp_hdr));
887                 copy_iv(ivc, ivp, sa->iv_len);
888                 break;
889         case ALGO_TYPE_AES_CTR:
890                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
891                 sop->cipher.data.length = clen;
892                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
893                 sop->auth.data.length = plen - sa->ctp.auth.length;
894                 sop->auth.digest.data = icv->va;
895                 sop->auth.digest.phys_addr = icv->pa;
896
897                 /* copy iv from the input packet to the cop */
898                 ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
899                         sa->iv_ofs);
900                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
901                         pofs + sizeof(struct esp_hdr));
902                 aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
903                 break;
904         case ALGO_TYPE_NULL:
905                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
906                 sop->cipher.data.length = clen;
907                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
908                 sop->auth.data.length = plen - sa->ctp.auth.length;
909                 sop->auth.digest.data = icv->va;
910                 sop->auth.digest.phys_addr = icv->pa;
911                 break;
912
913         default:
914                 return -EINVAL;
915         }
916
917         return 0;
918 }
919
920 /*
921  * for pure cryptodev (lookaside none) depending on SA settings,
922  * we might have to write some extra data to the packet.
923  */
924 static inline void
925 inb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
926         const union sym_op_data *icv)
927 {
928         struct aead_gcm_aad *aad;
929
930         /* insert SQN.hi between ESP trailer and ICV */
931         if (sa->sqh_len != 0)
932                 insert_sqh(sqn_hi32(sqc), icv->va, sa->icv_len);
933
934         /*
935          * fill AAD fields, if any (aad fields are placed after icv),
936          * right now we support only one AEAD algorithm: AES-GCM.
937          */
938         if (sa->aad_len != 0) {
939                 aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
940                 aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
941         }
942 }
943
944 /*
945  * setup/update packet data and metadata for ESP inbound tunnel case.
946  */
947 static inline int32_t
948 esp_inb_tun_pkt_prepare(const struct rte_ipsec_sa *sa,
949         const struct replay_sqn *rsn, struct rte_mbuf *mb,
950         uint32_t hlen, union sym_op_data *icv)
951 {
952         int32_t rc;
953         uint64_t sqn;
954         uint32_t icv_ofs, plen;
955         struct rte_mbuf *ml;
956         struct esp_hdr *esph;
957
958         esph = rte_pktmbuf_mtod_offset(mb, struct esp_hdr *, hlen);
959
960         /*
961          * retrieve and reconstruct SQN, then check it, then
962          * convert it back into network byte order.
963          */
964         sqn = rte_be_to_cpu_32(esph->seq);
965         if (IS_ESN(sa))
966                 sqn = reconstruct_esn(rsn->sqn, sqn, sa->replay.win_sz);
967
968         rc = esn_inb_check_sqn(rsn, sa, sqn);
969         if (rc != 0)
970                 return rc;
971
972         sqn = rte_cpu_to_be_64(sqn);
973
974         /* start packet manipulation */
975         plen = mb->pkt_len;
976         plen = plen - hlen;
977
978         ml = rte_pktmbuf_lastseg(mb);
979         icv_ofs = ml->data_len - sa->icv_len + sa->sqh_len;
980
981         /* we have to allocate space for AAD somewhere,
982          * right now - just use free trailing space at the last segment.
983          * Would probably be more convenient to reserve space for AAD
984          * inside rte_crypto_op itself
985          * (again for IV space is already reserved inside cop).
986          */
987         if (sa->aad_len + sa->sqh_len > rte_pktmbuf_tailroom(ml))
988                 return -ENOSPC;
989
990         icv->va = rte_pktmbuf_mtod_offset(ml, void *, icv_ofs);
991         icv->pa = rte_pktmbuf_iova_offset(ml, icv_ofs);
992
993         inb_pkt_xprepare(sa, sqn, icv);
994         return plen;
995 }
996
997 /*
998  * setup/update packets and crypto ops for ESP inbound case.
999  */
1000 static uint16_t
1001 inb_pkt_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1002         struct rte_crypto_op *cop[], uint16_t num)
1003 {
1004         int32_t rc;
1005         uint32_t i, k, hl;
1006         struct rte_ipsec_sa *sa;
1007         struct replay_sqn *rsn;
1008         union sym_op_data icv;
1009         struct rte_mbuf *dr[num];
1010
1011         sa = ss->sa;
1012         rsn = rsn_acquire(sa);
1013
1014         k = 0;
1015         for (i = 0; i != num; i++) {
1016
1017                 hl = mb[i]->l2_len + mb[i]->l3_len;
1018                 rc = esp_inb_tun_pkt_prepare(sa, rsn, mb[i], hl, &icv);
1019                 if (rc >= 0)
1020                         rc = esp_inb_tun_cop_prepare(cop[k], sa, mb[i], &icv,
1021                                 hl, rc);
1022
1023                 if (rc == 0)
1024                         mb[k++] = mb[i];
1025                 else {
1026                         dr[i - k] = mb[i];
1027                         rte_errno = -rc;
1028                 }
1029         }
1030
1031         rsn_release(sa, rsn);
1032
1033         /* update cops */
1034         lksd_none_cop_prepare(ss, mb, cop, k);
1035
1036         /* copy not prepared mbufs beyond good ones */
1037         if (k != num && k != 0)
1038                 mbuf_bulk_copy(mb + k, dr, num - k);
1039
1040         return k;
1041 }
1042
1043 /*
1044  *  setup crypto ops for LOOKASIDE_PROTO type of devices.
1045  */
1046 static inline void
1047 lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
1048         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
1049 {
1050         uint32_t i;
1051         struct rte_crypto_sym_op *sop;
1052
1053         for (i = 0; i != num; i++) {
1054                 sop = cop[i]->sym;
1055                 cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
1056                 cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
1057                 cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
1058                 sop->m_src = mb[i];
1059                 __rte_security_attach_session(sop, ss->security.ses);
1060         }
1061 }
1062
1063 /*
1064  *  setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
1065  *  Note that for LOOKASIDE_PROTO all packet modifications will be
1066  *  performed by PMD/HW.
1067  *  SW has only to prepare crypto op.
1068  */
1069 static uint16_t
1070 lksd_proto_prepare(const struct rte_ipsec_session *ss,
1071         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
1072 {
1073         lksd_proto_cop_prepare(ss, mb, cop, num);
1074         return num;
1075 }
1076
1077 /*
1078  * process ESP inbound tunnel packet.
1079  */
1080 static inline int
1081 esp_inb_tun_single_pkt_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
1082         uint32_t *sqn)
1083 {
1084         uint32_t hlen, icv_len, tlen;
1085         struct esp_hdr *esph;
1086         struct esp_tail *espt;
1087         struct rte_mbuf *ml;
1088         char *pd;
1089
1090         if (mb->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
1091                 return -EBADMSG;
1092
1093         icv_len = sa->icv_len;
1094
1095         ml = rte_pktmbuf_lastseg(mb);
1096         espt = rte_pktmbuf_mtod_offset(ml, struct esp_tail *,
1097                 ml->data_len - icv_len - sizeof(*espt));
1098
1099         /*
1100          * check padding and next proto.
1101          * return an error if something is wrong.
1102          */
1103         pd = (char *)espt - espt->pad_len;
1104         if (espt->next_proto != sa->proto ||
1105                         memcmp(pd, esp_pad_bytes, espt->pad_len))
1106                 return -EINVAL;
1107
1108         /* cut of ICV, ESP tail and padding bytes */
1109         tlen = icv_len + sizeof(*espt) + espt->pad_len;
1110         ml->data_len -= tlen;
1111         mb->pkt_len -= tlen;
1112
1113         /* cut of L2/L3 headers, ESP header and IV */
1114         hlen = mb->l2_len + mb->l3_len;
1115         esph = rte_pktmbuf_mtod_offset(mb, struct esp_hdr *, hlen);
1116         rte_pktmbuf_adj(mb, hlen + sa->ctp.cipher.offset);
1117
1118         /* retrieve SQN for later check */
1119         *sqn = rte_be_to_cpu_32(esph->seq);
1120
1121         /* reset mbuf metatdata: L2/L3 len, packet type */
1122         mb->packet_type = RTE_PTYPE_UNKNOWN;
1123         mb->l2_len = 0;
1124         mb->l3_len = 0;
1125
1126         /* clear the PKT_RX_SEC_OFFLOAD flag if set */
1127         mb->ol_flags &= ~(mb->ol_flags & PKT_RX_SEC_OFFLOAD);
1128         return 0;
1129 }
1130
1131 /*
1132  * process ESP inbound transport packet.
1133  */
1134 static inline int
1135 esp_inb_trs_single_pkt_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
1136         uint32_t *sqn)
1137 {
1138         uint32_t hlen, icv_len, l2len, l3len, tlen;
1139         struct esp_hdr *esph;
1140         struct esp_tail *espt;
1141         struct rte_mbuf *ml;
1142         char *np, *op, *pd;
1143
1144         if (mb->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
1145                 return -EBADMSG;
1146
1147         icv_len = sa->icv_len;
1148
1149         ml = rte_pktmbuf_lastseg(mb);
1150         espt = rte_pktmbuf_mtod_offset(ml, struct esp_tail *,
1151                 ml->data_len - icv_len - sizeof(*espt));
1152
1153         /* check padding, return an error if something is wrong. */
1154         pd = (char *)espt - espt->pad_len;
1155         if (memcmp(pd, esp_pad_bytes, espt->pad_len))
1156                 return -EINVAL;
1157
1158         /* cut of ICV, ESP tail and padding bytes */
1159         tlen = icv_len + sizeof(*espt) + espt->pad_len;
1160         ml->data_len -= tlen;
1161         mb->pkt_len -= tlen;
1162
1163         /* retrieve SQN for later check */
1164         l2len = mb->l2_len;
1165         l3len = mb->l3_len;
1166         hlen = l2len + l3len;
1167         op = rte_pktmbuf_mtod(mb, char *);
1168         esph = (struct esp_hdr *)(op + hlen);
1169         *sqn = rte_be_to_cpu_32(esph->seq);
1170
1171         /* cut off ESP header and IV, update L3 header */
1172         np = rte_pktmbuf_adj(mb, sa->ctp.cipher.offset);
1173         remove_esph(np, op, hlen);
1174         update_trs_l3hdr(sa, np + l2len, mb->pkt_len, l2len, l3len,
1175                         espt->next_proto);
1176
1177         /* reset mbuf packet type */
1178         mb->packet_type &= (RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK);
1179
1180         /* clear the PKT_RX_SEC_OFFLOAD flag if set */
1181         mb->ol_flags &= ~(mb->ol_flags & PKT_RX_SEC_OFFLOAD);
1182         return 0;
1183 }
1184
1185 /*
1186  * for group of ESP inbound packets perform SQN check and update.
1187  */
1188 static inline uint16_t
1189 esp_inb_rsn_update(struct rte_ipsec_sa *sa, const uint32_t sqn[],
1190         struct rte_mbuf *mb[], struct rte_mbuf *dr[], uint16_t num)
1191 {
1192         uint32_t i, k;
1193         struct replay_sqn *rsn;
1194
1195         rsn = rsn_update_start(sa);
1196
1197         k = 0;
1198         for (i = 0; i != num; i++) {
1199                 if (esn_inb_update_sqn(rsn, sa, sqn[i]) == 0)
1200                         mb[k++] = mb[i];
1201                 else
1202                         dr[i - k] = mb[i];
1203         }
1204
1205         rsn_update_finish(sa, rsn);
1206         return k;
1207 }
1208
1209 /*
1210  * process group of ESP inbound tunnel packets.
1211  */
1212 static uint16_t
1213 inb_tun_pkt_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1214         uint16_t num)
1215 {
1216         uint32_t i, k;
1217         struct rte_ipsec_sa *sa;
1218         uint32_t sqn[num];
1219         struct rte_mbuf *dr[num];
1220
1221         sa = ss->sa;
1222
1223         /* process packets, extract seq numbers */
1224
1225         k = 0;
1226         for (i = 0; i != num; i++) {
1227                 /* good packet */
1228                 if (esp_inb_tun_single_pkt_process(sa, mb[i], sqn + k) == 0)
1229                         mb[k++] = mb[i];
1230                 /* bad packet, will drop from furhter processing */
1231                 else
1232                         dr[i - k] = mb[i];
1233         }
1234
1235         /* update seq # and replay winow */
1236         k = esp_inb_rsn_update(sa, sqn, mb, dr + i - k, k);
1237
1238         /* handle unprocessed mbufs */
1239         if (k != num) {
1240                 rte_errno = EBADMSG;
1241                 if (k != 0)
1242                         mbuf_bulk_copy(mb + k, dr, num - k);
1243         }
1244
1245         return k;
1246 }
1247
1248 /*
1249  * process group of ESP inbound transport packets.
1250  */
1251 static uint16_t
1252 inb_trs_pkt_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1253         uint16_t num)
1254 {
1255         uint32_t i, k;
1256         uint32_t sqn[num];
1257         struct rte_ipsec_sa *sa;
1258         struct rte_mbuf *dr[num];
1259
1260         sa = ss->sa;
1261
1262         /* process packets, extract seq numbers */
1263
1264         k = 0;
1265         for (i = 0; i != num; i++) {
1266                 /* good packet */
1267                 if (esp_inb_trs_single_pkt_process(sa, mb[i], sqn + k) == 0)
1268                         mb[k++] = mb[i];
1269                 /* bad packet, will drop from furhter processing */
1270                 else
1271                         dr[i - k] = mb[i];
1272         }
1273
1274         /* update seq # and replay winow */
1275         k = esp_inb_rsn_update(sa, sqn, mb, dr + i - k, k);
1276
1277         /* handle unprocessed mbufs */
1278         if (k != num) {
1279                 rte_errno = EBADMSG;
1280                 if (k != 0)
1281                         mbuf_bulk_copy(mb + k, dr, num - k);
1282         }
1283
1284         return k;
1285 }
1286
1287 /*
1288  * process outbound packets for SA with ESN support,
1289  * for algorithms that require SQN.hibits to be implictly included
1290  * into digest computation.
1291  * In that case we have to move ICV bytes back to their proper place.
1292  */
1293 static uint16_t
1294 outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1295         uint16_t num)
1296 {
1297         uint32_t i, k, icv_len, *icv;
1298         struct rte_mbuf *ml;
1299         struct rte_ipsec_sa *sa;
1300         struct rte_mbuf *dr[num];
1301
1302         sa = ss->sa;
1303
1304         k = 0;
1305         icv_len = sa->icv_len;
1306
1307         for (i = 0; i != num; i++) {
1308                 if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0) {
1309                         ml = rte_pktmbuf_lastseg(mb[i]);
1310                         icv = rte_pktmbuf_mtod_offset(ml, void *,
1311                                 ml->data_len - icv_len);
1312                         remove_sqh(icv, icv_len);
1313                         mb[k++] = mb[i];
1314                 } else
1315                         dr[i - k] = mb[i];
1316         }
1317
1318         /* handle unprocessed mbufs */
1319         if (k != num) {
1320                 rte_errno = EBADMSG;
1321                 if (k != 0)
1322                         mbuf_bulk_copy(mb + k, dr, num - k);
1323         }
1324
1325         return k;
1326 }
1327
1328 /*
1329  * simplest pkt process routine:
1330  * all actual processing is already done by HW/PMD,
1331  * just check mbuf ol_flags.
1332  * used for:
1333  * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
1334  * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
1335  * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
1336  */
1337 static uint16_t
1338 pkt_flag_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1339         uint16_t num)
1340 {
1341         uint32_t i, k;
1342         struct rte_mbuf *dr[num];
1343
1344         RTE_SET_USED(ss);
1345
1346         k = 0;
1347         for (i = 0; i != num; i++) {
1348                 if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0)
1349                         mb[k++] = mb[i];
1350                 else
1351                         dr[i - k] = mb[i];
1352         }
1353
1354         /* handle unprocessed mbufs */
1355         if (k != num) {
1356                 rte_errno = EBADMSG;
1357                 if (k != 0)
1358                         mbuf_bulk_copy(mb + k, dr, num - k);
1359         }
1360
1361         return k;
1362 }
1363
1364 /*
1365  * prepare packets for inline ipsec processing:
1366  * set ol_flags and attach metadata.
1367  */
1368 static inline void
1369 inline_outb_mbuf_prepare(const struct rte_ipsec_session *ss,
1370         struct rte_mbuf *mb[], uint16_t num)
1371 {
1372         uint32_t i, ol_flags;
1373
1374         ol_flags = ss->security.ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA;
1375         for (i = 0; i != num; i++) {
1376
1377                 mb[i]->ol_flags |= PKT_TX_SEC_OFFLOAD;
1378                 if (ol_flags != 0)
1379                         rte_security_set_pkt_metadata(ss->security.ctx,
1380                                 ss->security.ses, mb[i], NULL);
1381         }
1382 }
1383
1384 /*
1385  * process group of ESP outbound tunnel packets destined for
1386  * INLINE_CRYPTO type of device.
1387  */
1388 static uint16_t
1389 inline_outb_tun_pkt_process(const struct rte_ipsec_session *ss,
1390         struct rte_mbuf *mb[], uint16_t num)
1391 {
1392         int32_t rc;
1393         uint32_t i, k, n;
1394         uint64_t sqn;
1395         rte_be64_t sqc;
1396         struct rte_ipsec_sa *sa;
1397         union sym_op_data icv;
1398         uint64_t iv[IPSEC_MAX_IV_QWORD];
1399         struct rte_mbuf *dr[num];
1400
1401         sa = ss->sa;
1402
1403         n = num;
1404         sqn = esn_outb_update_sqn(sa, &n);
1405         if (n != num)
1406                 rte_errno = EOVERFLOW;
1407
1408         k = 0;
1409         for (i = 0; i != n; i++) {
1410
1411                 sqc = rte_cpu_to_be_64(sqn + i);
1412                 gen_iv(iv, sqc);
1413
1414                 /* try to update the packet itself */
1415                 rc = esp_outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv);
1416
1417                 /* success, update mbuf fields */
1418                 if (rc >= 0)
1419                         mb[k++] = mb[i];
1420                 /* failure, put packet into the death-row */
1421                 else {
1422                         dr[i - k] = mb[i];
1423                         rte_errno = -rc;
1424                 }
1425         }
1426
1427         inline_outb_mbuf_prepare(ss, mb, k);
1428
1429         /* copy not processed mbufs beyond good ones */
1430         if (k != n && k != 0)
1431                 mbuf_bulk_copy(mb + k, dr, n - k);
1432
1433         return k;
1434 }
1435
1436 /*
1437  * process group of ESP outbound transport packets destined for
1438  * INLINE_CRYPTO type of device.
1439  */
1440 static uint16_t
1441 inline_outb_trs_pkt_process(const struct rte_ipsec_session *ss,
1442         struct rte_mbuf *mb[], uint16_t num)
1443 {
1444         int32_t rc;
1445         uint32_t i, k, n, l2, l3;
1446         uint64_t sqn;
1447         rte_be64_t sqc;
1448         struct rte_ipsec_sa *sa;
1449         union sym_op_data icv;
1450         uint64_t iv[IPSEC_MAX_IV_QWORD];
1451         struct rte_mbuf *dr[num];
1452
1453         sa = ss->sa;
1454
1455         n = num;
1456         sqn = esn_outb_update_sqn(sa, &n);
1457         if (n != num)
1458                 rte_errno = EOVERFLOW;
1459
1460         k = 0;
1461         for (i = 0; i != n; i++) {
1462
1463                 l2 = mb[i]->l2_len;
1464                 l3 = mb[i]->l3_len;
1465
1466                 sqc = rte_cpu_to_be_64(sqn + i);
1467                 gen_iv(iv, sqc);
1468
1469                 /* try to update the packet itself */
1470                 rc = esp_outb_trs_pkt_prepare(sa, sqc, iv, mb[i],
1471                                 l2, l3, &icv);
1472
1473                 /* success, update mbuf fields */
1474                 if (rc >= 0)
1475                         mb[k++] = mb[i];
1476                 /* failure, put packet into the death-row */
1477                 else {
1478                         dr[i - k] = mb[i];
1479                         rte_errno = -rc;
1480                 }
1481         }
1482
1483         inline_outb_mbuf_prepare(ss, mb, k);
1484
1485         /* copy not processed mbufs beyond good ones */
1486         if (k != n && k != 0)
1487                 mbuf_bulk_copy(mb + k, dr, n - k);
1488
1489         return k;
1490 }
1491
1492 /*
1493  * outbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1494  * actual processing is done by HW/PMD, just set flags and metadata.
1495  */
1496 static uint16_t
1497 outb_inline_proto_process(const struct rte_ipsec_session *ss,
1498                 struct rte_mbuf *mb[], uint16_t num)
1499 {
1500         inline_outb_mbuf_prepare(ss, mb, num);
1501         return num;
1502 }
1503
1504 /*
1505  * Select packet processing function for session on LOOKASIDE_NONE
1506  * type of device.
1507  */
1508 static int
1509 lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
1510                 struct rte_ipsec_sa_pkt_func *pf)
1511 {
1512         int32_t rc;
1513
1514         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
1515                         RTE_IPSEC_SATP_MODE_MASK;
1516
1517         rc = 0;
1518         switch (sa->type & msk) {
1519         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
1520         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
1521                 pf->prepare = inb_pkt_prepare;
1522                 pf->process = inb_tun_pkt_process;
1523                 break;
1524         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
1525                 pf->prepare = inb_pkt_prepare;
1526                 pf->process = inb_trs_pkt_process;
1527                 break;
1528         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
1529         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
1530                 pf->prepare = outb_tun_prepare;
1531                 pf->process = (sa->sqh_len != 0) ?
1532                         outb_sqh_process : pkt_flag_process;
1533                 break;
1534         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
1535                 pf->prepare = outb_trs_prepare;
1536                 pf->process = (sa->sqh_len != 0) ?
1537                         outb_sqh_process : pkt_flag_process;
1538                 break;
1539         default:
1540                 rc = -ENOTSUP;
1541         }
1542
1543         return rc;
1544 }
1545
1546 /*
1547  * Select packet processing function for session on INLINE_CRYPTO
1548  * type of device.
1549  */
1550 static int
1551 inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
1552                 struct rte_ipsec_sa_pkt_func *pf)
1553 {
1554         int32_t rc;
1555
1556         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
1557                         RTE_IPSEC_SATP_MODE_MASK;
1558
1559         rc = 0;
1560         switch (sa->type & msk) {
1561         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
1562         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
1563                 pf->process = inb_tun_pkt_process;
1564                 break;
1565         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
1566                 pf->process = inb_trs_pkt_process;
1567                 break;
1568         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
1569         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
1570                 pf->process = inline_outb_tun_pkt_process;
1571                 break;
1572         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
1573                 pf->process = inline_outb_trs_pkt_process;
1574                 break;
1575         default:
1576                 rc = -ENOTSUP;
1577         }
1578
1579         return rc;
1580 }
1581
1582 /*
1583  * Select packet processing function for given session based on SA parameters
1584  * and type of associated with the session device.
1585  */
1586 int
1587 ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
1588         const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
1589 {
1590         int32_t rc;
1591
1592         rc = 0;
1593         pf[0] = (struct rte_ipsec_sa_pkt_func) { 0 };
1594
1595         switch (ss->type) {
1596         case RTE_SECURITY_ACTION_TYPE_NONE:
1597                 rc = lksd_none_pkt_func_select(sa, pf);
1598                 break;
1599         case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
1600                 rc = inline_crypto_pkt_func_select(sa, pf);
1601                 break;
1602         case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1603                 if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
1604                                 RTE_IPSEC_SATP_DIR_IB)
1605                         pf->process = pkt_flag_process;
1606                 else
1607                         pf->process = outb_inline_proto_process;
1608                 break;
1609         case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
1610                 pf->prepare = lksd_proto_prepare;
1611                 pf->process = pkt_flag_process;
1612                 break;
1613         default:
1614                 rc = -ENOTSUP;
1615         }
1616
1617         return rc;
1618 }