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