crypto/cnxk: support lookaside IPsec AES-CBC-HMAC-SHA256
[dpdk.git] / drivers / common / cnxk / cnxk_security.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <rte_udp.h>
6
7 #include "cnxk_security.h"
8
9 #include "roc_api.h"
10
11 static void
12 ipsec_hmac_opad_ipad_gen(struct rte_crypto_sym_xform *auth_xform,
13                          uint8_t *hmac_opad_ipad)
14 {
15         const uint8_t *key = auth_xform->auth.key.data;
16         uint32_t length = auth_xform->auth.key.length;
17         uint8_t opad[128] = {[0 ... 127] = 0x5c};
18         uint8_t ipad[128] = {[0 ... 127] = 0x36};
19         uint32_t i;
20
21         /* HMAC OPAD and IPAD */
22         for (i = 0; i < 127 && i < length; i++) {
23                 opad[i] = opad[i] ^ key[i];
24                 ipad[i] = ipad[i] ^ key[i];
25         }
26
27         /* Precompute hash of HMAC OPAD and IPAD to avoid
28          * per packet computation
29          */
30         switch (auth_xform->auth.algo) {
31         case RTE_CRYPTO_AUTH_SHA1_HMAC:
32                 roc_hash_sha1_gen(opad, (uint32_t *)&hmac_opad_ipad[0]);
33                 roc_hash_sha1_gen(ipad, (uint32_t *)&hmac_opad_ipad[24]);
34                 break;
35         case RTE_CRYPTO_AUTH_SHA256_HMAC:
36                 roc_hash_sha256_gen(opad, (uint32_t *)&hmac_opad_ipad[0]);
37                 roc_hash_sha256_gen(ipad, (uint32_t *)&hmac_opad_ipad[64]);
38                 break;
39         default:
40                 break;
41         }
42 }
43
44 static int
45 ot_ipsec_sa_common_param_fill(union roc_ot_ipsec_sa_word2 *w2,
46                               uint8_t *cipher_key, uint8_t *salt_key,
47                               uint8_t *hmac_opad_ipad,
48                               struct rte_security_ipsec_xform *ipsec_xfrm,
49                               struct rte_crypto_sym_xform *crypto_xfrm)
50 {
51         struct rte_crypto_sym_xform *auth_xfrm, *cipher_xfrm;
52         const uint8_t *key;
53         uint32_t *tmp_salt;
54         uint64_t *tmp_key;
55         int length, i;
56
57         /* Set direction */
58         switch (ipsec_xfrm->direction) {
59         case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
60                 w2->s.dir = ROC_IE_SA_DIR_INBOUND;
61                 auth_xfrm = crypto_xfrm;
62                 cipher_xfrm = crypto_xfrm->next;
63                 break;
64         case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
65                 w2->s.dir = ROC_IE_SA_DIR_OUTBOUND;
66                 cipher_xfrm = crypto_xfrm;
67                 auth_xfrm = crypto_xfrm->next;
68                 break;
69         default:
70                 return -EINVAL;
71         }
72
73         /* Set protocol - ESP vs AH */
74         switch (ipsec_xfrm->proto) {
75         case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
76                 w2->s.protocol = ROC_IE_SA_PROTOCOL_ESP;
77                 break;
78         case RTE_SECURITY_IPSEC_SA_PROTO_AH:
79                 w2->s.protocol = ROC_IE_SA_PROTOCOL_AH;
80                 break;
81         default:
82                 return -EINVAL;
83         }
84
85         /* Set mode - transport vs tunnel */
86         switch (ipsec_xfrm->mode) {
87         case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
88                 w2->s.mode = ROC_IE_SA_MODE_TRANSPORT;
89                 break;
90         case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
91                 w2->s.mode = ROC_IE_SA_MODE_TUNNEL;
92                 break;
93         default:
94                 return -EINVAL;
95         }
96
97         /* Set encryption algorithm */
98         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
99                 key = crypto_xfrm->aead.key.data;
100                 length = crypto_xfrm->aead.key.length;
101
102                 switch (crypto_xfrm->aead.algo) {
103                 case RTE_CRYPTO_AEAD_AES_GCM:
104                         w2->s.enc_type = ROC_IE_OT_SA_ENC_AES_GCM;
105                         w2->s.auth_type = ROC_IE_OT_SA_AUTH_NULL;
106                         memcpy(salt_key, &ipsec_xfrm->salt, 4);
107                         tmp_salt = (uint32_t *)salt_key;
108                         *tmp_salt = rte_be_to_cpu_32(*tmp_salt);
109                         break;
110                 default:
111                         return -ENOTSUP;
112                 }
113         } else {
114                 switch (cipher_xfrm->cipher.algo) {
115                 case RTE_CRYPTO_CIPHER_AES_CBC:
116                         w2->s.enc_type = ROC_IE_OT_SA_ENC_AES_CBC;
117                         break;
118                 default:
119                         return -ENOTSUP;
120                 }
121
122                 switch (auth_xfrm->auth.algo) {
123                 case RTE_CRYPTO_AUTH_NULL:
124                         w2->s.auth_type = ROC_IE_OT_SA_AUTH_NULL;
125                         break;
126                 case RTE_CRYPTO_AUTH_SHA1_HMAC:
127                         w2->s.auth_type = ROC_IE_OT_SA_AUTH_SHA1;
128                         ipsec_hmac_opad_ipad_gen(auth_xfrm, hmac_opad_ipad);
129
130                         tmp_key = (uint64_t *)hmac_opad_ipad;
131                         for (i = 0; i < (int)(ROC_CTX_MAX_OPAD_IPAD_LEN /
132                                               sizeof(uint64_t));
133                              i++)
134                                 tmp_key[i] = rte_be_to_cpu_64(tmp_key[i]);
135                         break;
136                 case RTE_CRYPTO_AUTH_SHA256_HMAC:
137                         w2->s.auth_type = ROC_IE_OT_SA_AUTH_SHA2_256;
138                         ipsec_hmac_opad_ipad_gen(auth_xfrm, hmac_opad_ipad);
139
140                         tmp_key = (uint64_t *)hmac_opad_ipad;
141                         for (i = 0; i < (int)(ROC_CTX_MAX_OPAD_IPAD_LEN /
142                                               sizeof(uint64_t));
143                              i++)
144                                 tmp_key[i] = rte_be_to_cpu_64(tmp_key[i]);
145                         break;
146                 default:
147                         return -ENOTSUP;
148                 }
149
150                 key = cipher_xfrm->cipher.key.data;
151                 length = cipher_xfrm->cipher.key.length;
152         }
153
154         /* Set encapsulation type */
155         if (ipsec_xfrm->options.udp_encap)
156                 w2->s.encap_type = ROC_IE_OT_SA_ENCAP_UDP;
157
158         w2->s.spi = ipsec_xfrm->spi;
159
160         /* Copy encryption key */
161         memcpy(cipher_key, key, length);
162         tmp_key = (uint64_t *)cipher_key;
163         for (i = 0; i < (int)(ROC_CTX_MAX_CKEY_LEN / sizeof(uint64_t)); i++)
164                 tmp_key[i] = rte_be_to_cpu_64(tmp_key[i]);
165
166         switch (length) {
167         case ROC_CPT_AES128_KEY_LEN:
168                 w2->s.aes_key_len = ROC_IE_SA_AES_KEY_LEN_128;
169                 break;
170         case ROC_CPT_AES192_KEY_LEN:
171                 w2->s.aes_key_len = ROC_IE_SA_AES_KEY_LEN_192;
172                 break;
173         case ROC_CPT_AES256_KEY_LEN:
174                 w2->s.aes_key_len = ROC_IE_SA_AES_KEY_LEN_256;
175                 break;
176         default:
177                 return -EINVAL;
178         }
179
180         if (ipsec_xfrm->life.packets_soft_limit != 0 ||
181             ipsec_xfrm->life.packets_hard_limit != 0) {
182                 if (ipsec_xfrm->life.bytes_soft_limit != 0 ||
183                     ipsec_xfrm->life.bytes_hard_limit != 0) {
184                         plt_err("Expiry tracking with both packets & bytes is not supported");
185                         return -EINVAL;
186                 }
187                 w2->s.life_unit = ROC_IE_OT_SA_LIFE_UNIT_PKTS;
188         }
189
190         if (ipsec_xfrm->life.bytes_soft_limit != 0 ||
191             ipsec_xfrm->life.bytes_hard_limit != 0) {
192                 if (ipsec_xfrm->life.packets_soft_limit != 0 ||
193                     ipsec_xfrm->life.packets_hard_limit != 0) {
194                         plt_err("Expiry tracking with both packets & bytes is not supported");
195                         return -EINVAL;
196                 }
197                 w2->s.life_unit = ROC_IE_OT_SA_LIFE_UNIT_OCTETS;
198         }
199
200         return 0;
201 }
202
203 static size_t
204 ot_ipsec_inb_ctx_size(struct roc_ot_ipsec_inb_sa *sa)
205 {
206         size_t size;
207
208         /* Variable based on Anti-replay Window */
209         size = offsetof(struct roc_ot_ipsec_inb_sa, ctx) +
210                offsetof(struct roc_ot_ipsec_inb_ctx_update_reg, ar_winbits);
211
212         if (sa->w0.s.ar_win)
213                 size += (1 << (sa->w0.s.ar_win - 1)) * sizeof(uint64_t);
214
215         return size;
216 }
217
218 static int
219 ot_ipsec_inb_tunnel_hdr_fill(struct roc_ot_ipsec_inb_sa *sa,
220                              struct rte_security_ipsec_xform *ipsec_xfrm)
221 {
222         struct rte_security_ipsec_tunnel_param *tunnel;
223
224         if (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
225                 return 0;
226
227         if (ipsec_xfrm->options.tunnel_hdr_verify == 0)
228                 return 0;
229
230         tunnel = &ipsec_xfrm->tunnel;
231
232         switch (tunnel->type) {
233         case RTE_SECURITY_IPSEC_TUNNEL_IPV4:
234                 sa->w2.s.outer_ip_ver = ROC_IE_SA_IP_VERSION_4;
235                 memcpy(&sa->outer_hdr.ipv4.src_addr, &tunnel->ipv4.src_ip,
236                        sizeof(struct in_addr));
237                 memcpy(&sa->outer_hdr.ipv4.dst_addr, &tunnel->ipv4.dst_ip,
238                        sizeof(struct in_addr));
239
240                 /* IP Source and Dest are in LE/CPU endian */
241                 sa->outer_hdr.ipv4.src_addr =
242                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.src_addr);
243                 sa->outer_hdr.ipv4.dst_addr =
244                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.dst_addr);
245
246                 break;
247         case RTE_SECURITY_IPSEC_TUNNEL_IPV6:
248                 sa->w2.s.outer_ip_ver = ROC_IE_SA_IP_VERSION_6;
249                 memcpy(&sa->outer_hdr.ipv6.src_addr, &tunnel->ipv6.src_addr,
250                        sizeof(struct in6_addr));
251                 memcpy(&sa->outer_hdr.ipv6.dst_addr, &tunnel->ipv6.dst_addr,
252                        sizeof(struct in6_addr));
253
254                 break;
255         default:
256                 return -EINVAL;
257         }
258
259         switch (ipsec_xfrm->options.tunnel_hdr_verify) {
260         case RTE_SECURITY_IPSEC_TUNNEL_VERIFY_DST_ADDR:
261                 sa->w2.s.ip_hdr_verify = ROC_IE_OT_SA_IP_HDR_VERIFY_DST_ADDR;
262                 break;
263         case RTE_SECURITY_IPSEC_TUNNEL_VERIFY_SRC_DST_ADDR:
264                 sa->w2.s.ip_hdr_verify =
265                         ROC_IE_OT_SA_IP_HDR_VERIFY_SRC_DST_ADDR;
266                 break;
267         default:
268                 return -ENOTSUP;
269         }
270
271         return 0;
272 }
273
274 int
275 cnxk_ot_ipsec_inb_sa_fill(struct roc_ot_ipsec_inb_sa *sa,
276                           struct rte_security_ipsec_xform *ipsec_xfrm,
277                           struct rte_crypto_sym_xform *crypto_xfrm)
278 {
279         union roc_ot_ipsec_sa_word2 w2;
280         uint32_t replay_win_sz;
281         size_t offset;
282         int rc;
283
284         w2.u64 = 0;
285         rc = ot_ipsec_sa_common_param_fill(&w2, sa->cipher_key, sa->w8.s.salt,
286                                            sa->hmac_opad_ipad, ipsec_xfrm,
287                                            crypto_xfrm);
288         if (rc)
289                 return rc;
290
291         /* Updata common word2 data */
292         sa->w2.u64 = w2.u64;
293
294         /* Only support power-of-two window sizes supported */
295         replay_win_sz = ipsec_xfrm->replay_win_sz;
296         if (replay_win_sz) {
297                 if (!rte_is_power_of_2(replay_win_sz) ||
298                     replay_win_sz > ROC_AR_WIN_SIZE_MAX)
299                         return -ENOTSUP;
300
301                 sa->w0.s.ar_win = rte_log2_u32(replay_win_sz) - 5;
302         }
303
304         rc = ot_ipsec_inb_tunnel_hdr_fill(sa, ipsec_xfrm);
305         if (rc)
306                 return rc;
307
308         /* Default options for pkt_out and pkt_fmt are with
309          * second pass meta and no defrag.
310          */
311         sa->w0.s.pkt_format = ROC_IE_OT_SA_PKT_FMT_META;
312         sa->w0.s.pkt_output = ROC_IE_OT_SA_PKT_OUTPUT_HW_BASED_DEFRAG;
313         sa->w0.s.pkind = ROC_OT_CPT_META_PKIND;
314
315         /* ESN */
316         sa->w2.s.esn_en = !!ipsec_xfrm->options.esn;
317         if (ipsec_xfrm->options.udp_encap) {
318                 sa->w10.s.udp_src_port = 4500;
319                 sa->w10.s.udp_dst_port = 4500;
320         }
321
322         if (ipsec_xfrm->options.udp_ports_verify)
323                 sa->w2.s.udp_ports_verify = 1;
324
325         offset = offsetof(struct roc_ot_ipsec_inb_sa, ctx);
326         /* Word offset for HW managed SA field */
327         sa->w0.s.hw_ctx_off = offset / 8;
328         /* Context push size for inbound spans up to hw_ctx including
329          * ar_base field, in 8b units
330          */
331         sa->w0.s.ctx_push_size = sa->w0.s.hw_ctx_off + 1;
332         /* Entire context size in 128B units */
333         sa->w0.s.ctx_size =
334                 (PLT_ALIGN_CEIL(ot_ipsec_inb_ctx_size(sa), ROC_CTX_UNIT_128B) /
335                  ROC_CTX_UNIT_128B) -
336                 1;
337
338         /**
339          * CPT MC triggers expiry when counter value changes from 2 to 1. To
340          * mitigate this behaviour add 1 to the life counter values provided.
341          */
342
343         if (ipsec_xfrm->life.bytes_soft_limit) {
344                 sa->ctx.soft_life = ipsec_xfrm->life.bytes_soft_limit + 1;
345                 sa->w0.s.soft_life_dec = 1;
346         }
347
348         if (ipsec_xfrm->life.packets_soft_limit) {
349                 sa->ctx.soft_life = ipsec_xfrm->life.packets_soft_limit + 1;
350                 sa->w0.s.soft_life_dec = 1;
351         }
352
353         if (ipsec_xfrm->life.bytes_hard_limit) {
354                 sa->ctx.hard_life = ipsec_xfrm->life.bytes_hard_limit + 1;
355                 sa->w0.s.hard_life_dec = 1;
356         }
357
358         if (ipsec_xfrm->life.packets_hard_limit) {
359                 sa->ctx.hard_life = ipsec_xfrm->life.packets_hard_limit + 1;
360                 sa->w0.s.hard_life_dec = 1;
361         }
362
363         /* There are two words of CPT_CTX_HW_S for ucode to skip */
364         sa->w0.s.ctx_hdr_size = 1;
365         sa->w0.s.aop_valid = 1;
366         sa->w0.s.et_ovrwr = 1;
367
368         rte_wmb();
369
370         /* Enable SA */
371         sa->w2.s.valid = 1;
372         return 0;
373 }
374
375 int
376 cnxk_ot_ipsec_outb_sa_fill(struct roc_ot_ipsec_outb_sa *sa,
377                            struct rte_security_ipsec_xform *ipsec_xfrm,
378                            struct rte_crypto_sym_xform *crypto_xfrm)
379 {
380         struct rte_security_ipsec_tunnel_param *tunnel = &ipsec_xfrm->tunnel;
381         union roc_ot_ipsec_sa_word2 w2;
382         size_t offset;
383         int rc;
384
385         w2.u64 = 0;
386         rc = ot_ipsec_sa_common_param_fill(&w2, sa->cipher_key, sa->iv.s.salt,
387                                            sa->hmac_opad_ipad, ipsec_xfrm,
388                                            crypto_xfrm);
389         if (rc)
390                 return rc;
391
392         /* Update common word2 data */
393         sa->w2.u64 = w2.u64;
394
395         if (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
396                 goto skip_tunnel_info;
397
398         /* Tunnel header info */
399         switch (tunnel->type) {
400         case RTE_SECURITY_IPSEC_TUNNEL_IPV4:
401                 sa->w2.s.outer_ip_ver = ROC_IE_SA_IP_VERSION_4;
402                 memcpy(&sa->outer_hdr.ipv4.src_addr, &tunnel->ipv4.src_ip,
403                        sizeof(struct in_addr));
404                 memcpy(&sa->outer_hdr.ipv4.dst_addr, &tunnel->ipv4.dst_ip,
405                        sizeof(struct in_addr));
406
407                 /* IP Source and Dest seems to be in LE/CPU endian */
408                 sa->outer_hdr.ipv4.src_addr =
409                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.src_addr);
410                 sa->outer_hdr.ipv4.dst_addr =
411                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.dst_addr);
412
413                 /* Outer header DF bit source */
414                 if (!ipsec_xfrm->options.copy_df) {
415                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
416                                 ROC_IE_OT_SA_COPY_FROM_SA;
417                         sa->w10.s.ipv4_df_or_ipv6_flw_lbl = tunnel->ipv4.df;
418                 } else {
419                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
420                                 ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
421                 }
422
423                 /* Outer header DSCP source */
424                 if (!ipsec_xfrm->options.copy_dscp) {
425                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_SA;
426                         sa->w10.s.dscp = tunnel->ipv4.dscp;
427                 } else {
428                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
429                 }
430                 break;
431         case RTE_SECURITY_IPSEC_TUNNEL_IPV6:
432                 sa->w2.s.outer_ip_ver = ROC_IE_SA_IP_VERSION_6;
433                 memcpy(&sa->outer_hdr.ipv6.src_addr, &tunnel->ipv6.src_addr,
434                        sizeof(struct in6_addr));
435                 memcpy(&sa->outer_hdr.ipv6.dst_addr, &tunnel->ipv6.dst_addr,
436                        sizeof(struct in6_addr));
437
438                 /* Outer header flow label source */
439                 if (!ipsec_xfrm->options.copy_flabel) {
440                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
441                                 ROC_IE_OT_SA_COPY_FROM_SA;
442
443                         sa->w10.s.ipv4_df_or_ipv6_flw_lbl = tunnel->ipv6.flabel;
444                 } else {
445                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
446                                 ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
447                 }
448
449                 /* Outer header DSCP source */
450                 if (!ipsec_xfrm->options.copy_dscp) {
451                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_SA;
452                         sa->w10.s.dscp = tunnel->ipv6.dscp;
453                 } else {
454                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
455                 }
456                 break;
457         default:
458                 return -EINVAL;
459         }
460
461 skip_tunnel_info:
462         /* ESN */
463         sa->w0.s.esn_en = !!ipsec_xfrm->options.esn;
464
465         if (ipsec_xfrm->options.udp_encap) {
466                 sa->w10.s.udp_src_port = 4500;
467                 sa->w10.s.udp_dst_port = 4500;
468         }
469
470         offset = offsetof(struct roc_ot_ipsec_outb_sa, ctx);
471         /* Word offset for HW managed SA field */
472         sa->w0.s.hw_ctx_off = offset / 8;
473         /* Context push size is up to hmac_opad_ipad */
474         sa->w0.s.ctx_push_size = sa->w0.s.hw_ctx_off;
475         /* Entire context size in 128B units */
476         offset = sizeof(struct roc_ot_ipsec_outb_sa);
477         sa->w0.s.ctx_size = (PLT_ALIGN_CEIL(offset, ROC_CTX_UNIT_128B) /
478                              ROC_CTX_UNIT_128B) -
479                             1;
480
481         /* IPID gen */
482         sa->w2.s.ipid_gen = 1;
483
484         /**
485          * CPT MC triggers expiry when counter value changes from 2 to 1. To
486          * mitigate this behaviour add 1 to the life counter values provided.
487          */
488
489         if (ipsec_xfrm->life.bytes_soft_limit) {
490                 sa->ctx.soft_life = ipsec_xfrm->life.bytes_soft_limit + 1;
491                 sa->w0.s.soft_life_dec = 1;
492         }
493
494         if (ipsec_xfrm->life.packets_soft_limit) {
495                 sa->ctx.soft_life = ipsec_xfrm->life.packets_soft_limit + 1;
496                 sa->w0.s.soft_life_dec = 1;
497         }
498
499         if (ipsec_xfrm->life.bytes_hard_limit) {
500                 sa->ctx.hard_life = ipsec_xfrm->life.bytes_hard_limit + 1;
501                 sa->w0.s.hard_life_dec = 1;
502         }
503
504         if (ipsec_xfrm->life.packets_hard_limit) {
505                 sa->ctx.hard_life = ipsec_xfrm->life.packets_hard_limit + 1;
506                 sa->w0.s.hard_life_dec = 1;
507         }
508
509         /* There are two words of CPT_CTX_HW_S for ucode to skip */
510         sa->w0.s.ctx_hdr_size = 1;
511         sa->w0.s.aop_valid = 1;
512
513         rte_wmb();
514
515         /* Enable SA */
516         sa->w2.s.valid = 1;
517         return 0;
518 }
519
520 bool
521 cnxk_ot_ipsec_inb_sa_valid(struct roc_ot_ipsec_inb_sa *sa)
522 {
523         return !!sa->w2.s.valid;
524 }
525
526 bool
527 cnxk_ot_ipsec_outb_sa_valid(struct roc_ot_ipsec_outb_sa *sa)
528 {
529         return !!sa->w2.s.valid;
530 }
531
532 static inline int
533 ipsec_xfrm_verify(struct rte_security_ipsec_xform *ipsec_xfrm,
534                   struct rte_crypto_sym_xform *crypto_xfrm)
535 {
536         if (crypto_xfrm->next == NULL)
537                 return -EINVAL;
538
539         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
540                 if (crypto_xfrm->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
541                     crypto_xfrm->next->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
542                         return -EINVAL;
543         } else {
544                 if (crypto_xfrm->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
545                     crypto_xfrm->next->type != RTE_CRYPTO_SYM_XFORM_AUTH)
546                         return -EINVAL;
547         }
548
549         return 0;
550 }
551
552 static int
553 onf_ipsec_sa_common_param_fill(struct roc_ie_onf_sa_ctl *ctl, uint8_t *salt,
554                                uint8_t *cipher_key, uint8_t *hmac_opad_ipad,
555                                struct rte_security_ipsec_xform *ipsec_xfrm,
556                                struct rte_crypto_sym_xform *crypto_xfrm)
557 {
558         struct rte_crypto_sym_xform *auth_xfrm, *cipher_xfrm;
559         int rc, length, auth_key_len;
560         const uint8_t *key = NULL;
561
562         /* Set direction */
563         switch (ipsec_xfrm->direction) {
564         case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
565                 ctl->direction = ROC_IE_SA_DIR_INBOUND;
566                 auth_xfrm = crypto_xfrm;
567                 cipher_xfrm = crypto_xfrm->next;
568                 break;
569         case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
570                 ctl->direction = ROC_IE_SA_DIR_OUTBOUND;
571                 cipher_xfrm = crypto_xfrm;
572                 auth_xfrm = crypto_xfrm->next;
573                 break;
574         default:
575                 return -EINVAL;
576         }
577
578         /* Set protocol - ESP vs AH */
579         switch (ipsec_xfrm->proto) {
580         case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
581                 ctl->ipsec_proto = ROC_IE_SA_PROTOCOL_ESP;
582                 break;
583         case RTE_SECURITY_IPSEC_SA_PROTO_AH:
584                 return -ENOTSUP;
585         default:
586                 return -EINVAL;
587         }
588
589         /* Set mode - transport vs tunnel */
590         switch (ipsec_xfrm->mode) {
591         case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
592                 ctl->ipsec_mode = ROC_IE_SA_MODE_TRANSPORT;
593                 break;
594         case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
595                 ctl->ipsec_mode = ROC_IE_SA_MODE_TUNNEL;
596                 break;
597         default:
598                 return -EINVAL;
599         }
600
601         /* Set encryption algorithm */
602         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
603                 length = crypto_xfrm->aead.key.length;
604
605                 switch (crypto_xfrm->aead.algo) {
606                 case RTE_CRYPTO_AEAD_AES_GCM:
607                         ctl->enc_type = ROC_IE_ON_SA_ENC_AES_GCM;
608                         ctl->auth_type = ROC_IE_ON_SA_AUTH_NULL;
609                         memcpy(salt, &ipsec_xfrm->salt, 4);
610                         key = crypto_xfrm->aead.key.data;
611                         break;
612                 default:
613                         return -ENOTSUP;
614                 }
615
616         } else {
617                 rc = ipsec_xfrm_verify(ipsec_xfrm, crypto_xfrm);
618                 if (rc)
619                         return rc;
620
621                 switch (cipher_xfrm->cipher.algo) {
622                 case RTE_CRYPTO_CIPHER_AES_CBC:
623                         ctl->enc_type = ROC_IE_ON_SA_ENC_AES_CBC;
624                         break;
625                 default:
626                         return -ENOTSUP;
627                 }
628
629                 switch (auth_xfrm->auth.algo) {
630                 case RTE_CRYPTO_AUTH_SHA1_HMAC:
631                         ctl->auth_type = ROC_IE_ON_SA_AUTH_SHA1;
632                         break;
633                 default:
634                         return -ENOTSUP;
635                 }
636                 auth_key_len = auth_xfrm->auth.key.length;
637                 if (auth_key_len < 20 || auth_key_len > 64)
638                         return -ENOTSUP;
639
640                 key = cipher_xfrm->cipher.key.data;
641                 length = cipher_xfrm->cipher.key.length;
642
643                 ipsec_hmac_opad_ipad_gen(auth_xfrm, hmac_opad_ipad);
644         }
645
646         switch (length) {
647         case ROC_CPT_AES128_KEY_LEN:
648                 ctl->aes_key_len = ROC_IE_SA_AES_KEY_LEN_128;
649                 break;
650         case ROC_CPT_AES192_KEY_LEN:
651                 ctl->aes_key_len = ROC_IE_SA_AES_KEY_LEN_192;
652                 break;
653         case ROC_CPT_AES256_KEY_LEN:
654                 ctl->aes_key_len = ROC_IE_SA_AES_KEY_LEN_256;
655                 break;
656         default:
657                 return -EINVAL;
658         }
659
660         memcpy(cipher_key, key, length);
661
662         if (ipsec_xfrm->options.esn)
663                 ctl->esn_en = 1;
664
665         ctl->spi = rte_cpu_to_be_32(ipsec_xfrm->spi);
666         return 0;
667 }
668
669 int
670 cnxk_onf_ipsec_inb_sa_fill(struct roc_onf_ipsec_inb_sa *sa,
671                            struct rte_security_ipsec_xform *ipsec_xfrm,
672                            struct rte_crypto_sym_xform *crypto_xfrm)
673 {
674         struct roc_ie_onf_sa_ctl *ctl = &sa->ctl;
675         int rc;
676
677         rc = onf_ipsec_sa_common_param_fill(ctl, sa->nonce, sa->cipher_key,
678                                             sa->hmac_key, ipsec_xfrm,
679                                             crypto_xfrm);
680         if (rc)
681                 return rc;
682
683         rte_wmb();
684
685         /* Enable SA */
686         ctl->valid = 1;
687         return 0;
688 }
689
690 int
691 cnxk_onf_ipsec_outb_sa_fill(struct roc_onf_ipsec_outb_sa *sa,
692                             struct rte_security_ipsec_xform *ipsec_xfrm,
693                             struct rte_crypto_sym_xform *crypto_xfrm)
694 {
695         struct rte_security_ipsec_tunnel_param *tunnel = &ipsec_xfrm->tunnel;
696         struct roc_ie_onf_sa_ctl *ctl = &sa->ctl;
697         int rc;
698
699         /* Fill common params */
700         rc = onf_ipsec_sa_common_param_fill(ctl, sa->nonce, sa->cipher_key,
701                                             sa->hmac_key, ipsec_xfrm,
702                                             crypto_xfrm);
703         if (rc)
704                 return rc;
705
706         if (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
707                 goto skip_tunnel_info;
708
709         /* Tunnel header info */
710         switch (tunnel->type) {
711         case RTE_SECURITY_IPSEC_TUNNEL_IPV4:
712                 memcpy(&sa->ip_src, &tunnel->ipv4.src_ip,
713                        sizeof(struct in_addr));
714                 memcpy(&sa->ip_dst, &tunnel->ipv4.dst_ip,
715                        sizeof(struct in_addr));
716                 break;
717         case RTE_SECURITY_IPSEC_TUNNEL_IPV6:
718                 return -ENOTSUP;
719         default:
720                 return -EINVAL;
721         }
722
723 skip_tunnel_info:
724         rte_wmb();
725
726         /* Enable SA */
727         ctl->valid = 1;
728         return 0;
729 }
730
731 bool
732 cnxk_onf_ipsec_inb_sa_valid(struct roc_onf_ipsec_inb_sa *sa)
733 {
734         return !!sa->ctl.valid;
735 }
736
737 bool
738 cnxk_onf_ipsec_outb_sa_valid(struct roc_onf_ipsec_outb_sa *sa)
739 {
740         return !!sa->ctl.valid;
741 }
742
743 uint8_t
744 cnxk_ipsec_ivlen_get(enum rte_crypto_cipher_algorithm c_algo,
745                      enum rte_crypto_auth_algorithm a_algo,
746                      enum rte_crypto_aead_algorithm aead_algo)
747 {
748         uint8_t ivlen = 0;
749
750         if (aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
751                 ivlen = 8;
752
753         switch (c_algo) {
754         case RTE_CRYPTO_CIPHER_AES_CTR:
755                 ivlen = 8;
756                 break;
757         case RTE_CRYPTO_CIPHER_3DES_CBC:
758                 ivlen = ROC_CPT_DES_BLOCK_LENGTH;
759                 break;
760         case RTE_CRYPTO_CIPHER_AES_CBC:
761                 ivlen = ROC_CPT_AES_BLOCK_LENGTH;
762                 break;
763         default:
764                 break;
765         }
766
767         switch (a_algo) {
768         case RTE_CRYPTO_AUTH_AES_GMAC:
769                 ivlen = 8;
770                 break;
771         default:
772                 break;
773         }
774
775         return ivlen;
776 }
777
778 uint8_t
779 cnxk_ipsec_icvlen_get(enum rte_crypto_cipher_algorithm c_algo,
780                       enum rte_crypto_auth_algorithm a_algo,
781                       enum rte_crypto_aead_algorithm aead_algo)
782 {
783         uint8_t icv = 0;
784
785         (void)c_algo;
786
787         switch (a_algo) {
788         case RTE_CRYPTO_AUTH_NULL:
789                 icv = 0;
790                 break;
791         case RTE_CRYPTO_AUTH_SHA1_HMAC:
792                 icv = 12;
793                 break;
794         case RTE_CRYPTO_AUTH_SHA256_HMAC:
795         case RTE_CRYPTO_AUTH_AES_GMAC:
796                 icv = 16;
797                 break;
798         case RTE_CRYPTO_AUTH_SHA384_HMAC:
799                 icv = 24;
800                 break;
801         case RTE_CRYPTO_AUTH_SHA512_HMAC:
802                 icv = 32;
803                 break;
804         default:
805                 break;
806         }
807
808         switch (aead_algo) {
809         case RTE_CRYPTO_AEAD_AES_GCM:
810                 icv = 16;
811                 break;
812         default:
813                 break;
814         }
815
816         return icv;
817 }
818
819 uint8_t
820 cnxk_ipsec_outb_roundup_byte(enum rte_crypto_cipher_algorithm c_algo,
821                              enum rte_crypto_aead_algorithm aead_algo)
822 {
823         uint8_t roundup_byte = 4;
824
825         if (aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
826                 return roundup_byte;
827
828         switch (c_algo) {
829         case RTE_CRYPTO_CIPHER_AES_CTR:
830                 roundup_byte = 4;
831                 break;
832         case RTE_CRYPTO_CIPHER_AES_CBC:
833                 roundup_byte = 16;
834                 break;
835         case RTE_CRYPTO_CIPHER_3DES_CBC:
836                 roundup_byte = 8;
837                 break;
838         case RTE_CRYPTO_CIPHER_NULL:
839                 roundup_byte = 4;
840                 break;
841         default:
842                 break;
843         }
844
845         return roundup_byte;
846 }
847
848 int
849 cnxk_ipsec_outb_rlens_get(struct cnxk_ipsec_outb_rlens *rlens,
850                           struct rte_security_ipsec_xform *ipsec_xfrm,
851                           struct rte_crypto_sym_xform *crypto_xfrm)
852 {
853         struct rte_security_ipsec_tunnel_param *tunnel = &ipsec_xfrm->tunnel;
854         enum rte_crypto_cipher_algorithm c_algo = RTE_CRYPTO_CIPHER_NULL;
855         enum rte_crypto_auth_algorithm a_algo = RTE_CRYPTO_AUTH_NULL;
856         enum rte_crypto_aead_algorithm aead_algo = 0;
857         uint16_t partial_len = 0;
858         uint8_t roundup_byte = 0;
859         int8_t roundup_len = 0;
860
861         memset(rlens, 0, sizeof(struct cnxk_ipsec_outb_rlens));
862
863         /* Get Cipher and Auth algo */
864         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
865                 aead_algo = crypto_xfrm->aead.algo;
866         } else {
867                 if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
868                         c_algo = crypto_xfrm->cipher.algo;
869                 else
870                         a_algo = crypto_xfrm->auth.algo;
871
872                 if (crypto_xfrm->next) {
873                         if (crypto_xfrm->next->type ==
874                             RTE_CRYPTO_SYM_XFORM_CIPHER)
875                                 c_algo = crypto_xfrm->next->cipher.algo;
876                         else
877                                 a_algo = crypto_xfrm->next->auth.algo;
878                 }
879         }
880
881         if (ipsec_xfrm->proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP) {
882                 partial_len = ROC_CPT_ESP_HDR_LEN;
883                 roundup_len = ROC_CPT_ESP_TRL_LEN;
884         } else {
885                 partial_len = ROC_CPT_AH_HDR_LEN;
886         }
887
888         if (ipsec_xfrm->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
889                 if (tunnel->type == RTE_SECURITY_IPSEC_TUNNEL_IPV4)
890                         partial_len += ROC_CPT_TUNNEL_IPV4_HDR_LEN;
891                 else
892                         partial_len += ROC_CPT_TUNNEL_IPV6_HDR_LEN;
893         }
894
895         partial_len += cnxk_ipsec_ivlen_get(c_algo, a_algo, aead_algo);
896         partial_len += cnxk_ipsec_icvlen_get(c_algo, a_algo, aead_algo);
897         roundup_byte = cnxk_ipsec_outb_roundup_byte(c_algo, aead_algo);
898
899         if (ipsec_xfrm->options.udp_encap)
900                 partial_len += sizeof(struct rte_udp_hdr);
901
902         rlens->partial_len = partial_len;
903         rlens->roundup_len = roundup_len;
904         rlens->roundup_byte = roundup_byte;
905         rlens->max_extended_len = partial_len + roundup_len + roundup_byte;
906         return 0;
907 }