blob: ff61b900d9c84dd74824b8a36a9987f45c60046f [file] [log] [blame]
developer75e4dad2022-11-16 15:17:14 +08001// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2022 MediaTek Inc.
3
4#include <crypto/aes.h>
5#include <crypto/hash.h>
6#include <crypto/hmac.h>
7#include <crypto/sha.h>
8#include <crypto/sha3.h>
9#include <net/xfrm.h>
10#include <linux/ip.h>
11#include <linux/psp-sev.h>
12#include <linux/netdevice.h>
13
14#include "mtk_eth_soc.h"
15#include "mtk_ipsec.h"
16
17static inline void write_state_le(__le32 *dst, const u32 *src, u32 size)
18{
19 int i;
20
21 for (i = 0; i < SIZE_IN_WORDS(size); i++)
22 dst[i] = cpu_to_le32(src[i]);
23}
24
25static inline void write_state_be(__le32 *dst, const u32 *src, u32 size)
26{
27 int i;
28
29 for (i = 0; i < SIZE_IN_WORDS(size); i++)
30 dst[i] = cpu_to_be32(src[i]);
31}
32
33static int hmac_init_iv(struct crypto_shash *tfm,
34 unsigned int blocksize, u8 *pad, void *state)
35{
36 SHASH_DESC_ON_STACK(desc, tfm);
37 int ret;
38
39 desc->tfm = tfm;
40
41 ret = crypto_shash_init(desc);
42 if (ret)
43 return ret;
44
45 ret = crypto_shash_update(desc, pad, blocksize);
46 if (ret && ret != -EINPROGRESS && ret != -EBUSY)
47 return ret;
48
49 crypto_shash_export(desc, state);
50 shash_desc_zero(desc);
51
52 return 0;
53}
54
55static int hmac_init_pad(unsigned int blocksize, const u8 *key,
56 unsigned int keylen, u8 *ipad, u8 *opad)
57{
58 int i;
59
60 if (keylen <= blocksize)
61 memcpy(ipad, key, keylen);
62
63 memset(ipad + keylen, 0, blocksize - keylen);
64 memcpy(opad, ipad, blocksize);
65
66 for (i = 0; i < blocksize; i++) {
67 ipad[i] ^= HMAC_IPAD_VALUE;
68 opad[i] ^= HMAC_OPAD_VALUE;
69 }
70
71 return 0;
72}
73
74int hmac_setkey(const char *alg, const u8 *key, unsigned int keylen,
75 void *istate, void *ostate)
76{
77 struct crypto_shash *tfm;
78 unsigned int blocksize;
79 u8 *ipad, *opad;
80 int ret;
81
82 tfm = crypto_alloc_shash(alg, 0, 0);
83 if (IS_ERR(tfm))
84 return PTR_ERR(tfm);
85
86 crypto_shash_clear_flags(tfm, ~0);
87 blocksize = crypto_tfm_alg_blocksize(crypto_shash_tfm(tfm));
88
89 ipad = kcalloc(2, blocksize, GFP_KERNEL);
90 if (!ipad) {
91 ret = -ENOMEM;
92 goto free_request;
93 }
94
95 opad = ipad + blocksize;
96
97 ret = hmac_init_pad(blocksize, key, keylen, ipad, opad);
98 if (ret)
99 goto free_ipad;
100
101 ret = hmac_init_iv(tfm, blocksize, ipad, istate);
102 if (ret)
103 goto free_ipad;
104
105 ret = hmac_init_iv(tfm, blocksize, opad, ostate);
106
107free_ipad:
108 kfree(ipad);
109free_request:
110 crypto_free_shash(tfm);
111
112 return ret;
113}
114
115static int mtk_ipsec_add_sa(struct xfrm_state *xs)
116{
117 struct net_device *dev = xs->xso.dev;
118 struct mtk_mac *mac = netdev_priv(dev);
119 struct mtk_eth *eth = mac->hw;
120 struct context_record *context;
121 struct ahash_export_state istate, ostate;
122 unsigned char *key_aalg;
123 unsigned char *key_ealg;
developerdd7ff4b2022-12-06 13:42:32 +0800124 unsigned int checksum;
developer75e4dad2022-11-16 15:17:14 +0800125 unsigned int key_len;
126 int i;
127 int cdrt_idx;
128
129 if (xs->props.family != AF_INET) {
130 netdev_info(dev, "Only IPv4 xfrm states may be offloaded\n");
131 return -EINVAL;
132 }
133
134 if (xs->id.proto != IPPROTO_ESP) {
135 netdev_info(dev, "Unsupported protocol 0x%04x\n",
136 xs->id.proto);
137 return -EINVAL;
138 }
139
140 context = kzalloc(sizeof(*context), GFP_KERNEL);
141 if (unlikely(!context))
142 return -ENOMEM;
143
144 /**
145 * Set Transform record
146 * cdrt_idx=0, outbound for encryption
147 * cdrt_idx=1, inbound for decryption
148 **/
149 if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
150 /* rx path */
151 context->control0 = CTRL_WORD0_IN;
152 context->control1 = CTRL_WORD1_IN;
153 context->data[46] = 0x01020000;
154 context->data[49] = 0x6117d6a5;
155 context->data[50] = 0x07040c10;
156 context->data[52] = 0xdd07000c;
157 context->data[53] = 0xe4561820;
158 cdrt_idx = 1;
159
160 } else {
161 /* tx path */
162 context->control0 = CTRL_WORD0_OUT;
163 context->control1 = CTRL_WORD1_OUT;
164 memcpy(context->data + 38, &xs->props.saddr.a4, 4);
165 memcpy(context->data + 42, &xs->id.daddr.a4, 4);
developer75e4dad2022-11-16 15:17:14 +0800166 context->data[46] = 0x04020000;
167 context->data[49] = 0x9e14ed69;
168 context->data[50] = 0x01020c10;
169 context->data[52] = 0xd0060000;
170 context->data[53] = 0xe1560811;
171 context->data[55] = 0x00000049;
172 cdrt_idx = 0;
173 }
174 context->data[47] = 0x00080000;
175 context->data[48] = 0x00f00008;
176 context->data[51] = 0x94119411;
177
developerdd7ff4b2022-12-06 13:42:32 +0800178 /* Calculate Checksum */
179 checksum = 0;
180 checksum += context->data[38] % 0x10000;
181 checksum += context->data[38] / 0x10000;
182 checksum += context->data[42] % 0x10000;
183 checksum += context->data[42] / 0x10000;
184 checksum += checksum / 0x10000;
185 checksum = checksum % 0x10000;
186 context->data[39] = checksum;
187
developer75e4dad2022-11-16 15:17:14 +0800188 /* EIP-96 context words[2...39]*/
189 if (strcmp(xs->aalg->alg_name, "hmac(sha1)") == 0) {
190 key_aalg = &xs->aalg->alg_key[0];
191 hmac_setkey("sha1-generic", key_aalg,
192 xs->aalg->alg_key_len / 8,
193 &istate.state, &ostate.state);
194 key_ealg = &xs->ealg->alg_key[0];
195 key_len = xs->ealg->alg_key_len / 8;
196 write_state_le(context->data, (const u32 *)key_ealg, key_len);
197 write_state_be(context->data + SIZE_IN_WORDS(key_len),
198 (const u32 *)&istate.state, SHA1_DIGEST_SIZE);
199
200 key_len += SHA1_DIGEST_SIZE;
201 write_state_be(context->data + SIZE_IN_WORDS(key_len),
202 (const u32 *)&ostate.state, SHA1_DIGEST_SIZE);
203
204 key_len += SHA1_DIGEST_SIZE;
205 memcpy(context->data + SIZE_IN_WORDS(key_len),
206 &xs->id.spi, 4);
developer141ccec2023-02-16 09:51:22 +0800207 } else if (strcmp(xs->aalg->alg_name, "hmac(sha256)") == 0) {
208 key_aalg = &xs->aalg->alg_key[0];
209 hmac_setkey("sha256-generic", key_aalg,
210 xs->aalg->alg_key_len / 8,
211 &istate.state, &ostate.state);
212 key_ealg = &xs->ealg->alg_key[0];
213 key_len = xs->ealg->alg_key_len / 8;
214 write_state_le(context->data, (const u32 *)key_ealg, key_len);
215 write_state_be(context->data + SIZE_IN_WORDS(key_len),
216 (const u32 *)&istate.state, SHA256_DIGEST_SIZE);
217
218 key_len += SHA256_DIGEST_SIZE;
219 write_state_be(context->data + SIZE_IN_WORDS(key_len),
220 (const u32 *)&ostate.state, SHA256_DIGEST_SIZE);
221
222 key_len += SHA256_DIGEST_SIZE;
223 memcpy(context->data + SIZE_IN_WORDS(key_len),
224 &xs->id.spi, 4);
225
226 if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
227 /* rx path */
228 context->control0 = CTRL_WORD0_IN_SHA256;
229 context->control1 = CTRL_WORD1_IN_SHA256;
230 context->data[50] = 0x07041010;
231 context->data[52] = 0xdd070010;
232 context->data[53] = 0xe4561820;
233 } else {
234 /* tx path */
235 context->control0 = CTRL_WORD0_OUT_SHA256;
236 context->control1 = CTRL_WORD1_OUT_SHA256;
237 context->data[50] = 0x01021010;
238 context->data[53] = 0xe1560817;
239 context->data[55] = 0x0000004d;
240 }
developer75e4dad2022-11-16 15:17:14 +0800241 }
developer75e4dad2022-11-16 15:17:14 +0800242
243 /**
244 * Set CDRT for inline IPSec
245 * Follow FE_CSR_MEM config flow.
246 **/
247
248 /* Command descriptor W0-W3 */
249 for (i = MTK_GLO_MEM_DATA0; i <= MTK_GLO_MEM_DATA9; i = i + 4)
250 mtk_w32(eth, 0, i);
251
252 mtk_w32(eth, TYPE(3), MTK_GLO_MEM_DATA0);
253 mtk_w32(eth, TOKEN_LEN(48), MTK_GLO_MEM_DATA1);
254 mtk_w32(eth, __psp_pa(context) | 2, MTK_GLO_MEM_DATA2);
255 mtk_w32(eth, CTRL_CMD(1) | CTRL_INDEX(3) | CTRL_ADDR(cdrt_idx * 3),
256 MTK_GLO_MEM_CTRL);
257
258 /* Command descriptor W4-W7 */
259 for (i = MTK_GLO_MEM_DATA0; i <= MTK_GLO_MEM_DATA9; i = i + 4)
260 mtk_w32(eth, 0, i);
261
262 mtk_w32(eth, HW_SER(2) | ALLOW_PAD | STRIP_PAD, MTK_GLO_MEM_DATA0);
263 mtk_w32(eth, CTRL_CMD(1) | CTRL_INDEX(3) | CTRL_ADDR(cdrt_idx * 3 + 1),
264 MTK_GLO_MEM_CTRL);
265
266 /* Command descriptor W8-W11 */
267 for (i = MTK_GLO_MEM_DATA0; i <= MTK_GLO_MEM_DATA9; i = i + 4)
268 mtk_w32(eth, 0, i);
269
270 mtk_w32(eth, CTRL_CMD(1) | CTRL_INDEX(3) | CTRL_ADDR(cdrt_idx * 3 + 2),
271 MTK_GLO_MEM_CTRL);
272
273 xs->xso.offload_handle = (unsigned long)context;
274
275 return 0;
276}
277
278static void mtk_ipsec_free_state(struct xfrm_state *xs)
279{
280 struct context_record *context;
281
282 if (!xs->xso.offload_handle)
283 return;
284
285 context = (struct context_record *)xs->xso.offload_handle;
286 kfree(context);
287}
288
289static bool mtk_ipsec_offload_ok(struct sk_buff *skb,
290 struct xfrm_state *xs)
291{
292 struct xfrm_offload *xo = NULL;
293
294 if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
295 /* rx path */
296 if (xfrm_offload(skb) != NULL)
297 xo = xfrm_offload(skb);
298
299 } else {
300 /* tx path */
301 if (xfrm_offload(skb) != NULL)
302 xo = xfrm_offload(skb);
303 }
304
305 if (xs->props.family == AF_INET) {
306 /* Offload with IPv4 options is not supported yet */
307 if (ip_hdr(skb)->ihl != 5)
308 return false;
309 }
310
311 return true;
312}
313
314static const struct xfrmdev_ops mtk_xfrmdev_ops = {
315 .xdo_dev_state_add = mtk_ipsec_add_sa,
316 .xdo_dev_state_free = mtk_ipsec_free_state,
317 .xdo_dev_offload_ok = mtk_ipsec_offload_ok,
318};
319
320void mtk_ipsec_offload_init(struct mtk_eth *eth)
321{
322 int i;
323
324 for (i = 0; i < MTK_MAC_COUNT; i++)
325 eth->netdev[i]->xfrmdev_ops = &mtk_xfrmdev_ops;
326}