blob: 045002c74635d14728cb167741c4f4465c0d5d6a [file] [log] [blame]
developer94c513e2023-08-21 17:33:25 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2023 MediaTek Inc.
4 *
5 * Author: Chris.Chou <chris.chou@mediatek.com>
6 * Ren-Ting Wang <ren-ting.wang@mediatek.com>
7 */
8
9#include <linux/bitops.h>
10
11#include <mtk_eth_soc.h>
12#include <mtk_hnat/hnat.h>
13#include <mtk_hnat/nf_hnat_mtk.h>
14
15#include <pce/cdrt.h>
16#include <pce/cls.h>
17#include <pce/netsys.h>
18
19#include <crypto-eip/ddk/configs/cs_hwpal_ext.h>
20#include <crypto-eip/ddk/kit/iotoken/iotoken.h>
21#include <crypto-eip/ddk/kit/iotoken/iotoken_ext.h>
22
23#include "crypto-eip/crypto-eip.h"
24#include "crypto-eip/ddk-wrapper.h"
25#include "crypto-eip/internal.h"
26
27static LIST_HEAD(xfrm_params_head);
28
developerd0a7d722023-10-19 11:24:25 +080029static inline bool is_tops_udp_tunnel(struct sk_buff *skb)
30{
31 return skb_hnat_tops(skb) && (ntohs(skb->protocol) == ETH_P_IP) &&
32 (ip_hdr(skb)->protocol == IPPROTO_UDP);
33}
34
35static inline bool is_tcp(struct sk_buff *skb)
36{
37 return (ntohs(skb->protocol) == ETH_P_IP) && (ip_hdr(skb)->protocol == IPPROTO_TCP);
38}
39
40static inline bool is_hnat_rate_reach(struct sk_buff *skb)
41{
42 return is_magic_tag_valid(skb) && (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH);
43}
44
developer94c513e2023-08-21 17:33:25 +080045static void mtk_xfrm_offload_cdrt_tear_down(struct mtk_xfrm_params *xfrm_params)
46{
47 memset(&xfrm_params->cdrt->desc, 0, sizeof(struct cdrt_desc));
48
49 mtk_pce_cdrt_entry_write(xfrm_params->cdrt);
50}
51
52static int mtk_xfrm_offload_cdrt_setup(struct mtk_xfrm_params *xfrm_params)
53{
54 struct cdrt_desc *cdesc = &xfrm_params->cdrt->desc;
55
56 cdesc->desc1.common.type = 3;
57 cdesc->desc1.token_len = 48;
58 cdesc->desc1.p_tr[0] = __pa(xfrm_params->p_tr) | 2;
59
60 cdesc->desc2.hw_srv = 2;
61 cdesc->desc2.allow_pad = 1;
62 cdesc->desc2.strip_pad = 1;
63
64 return mtk_pce_cdrt_entry_write(xfrm_params->cdrt);
65}
66
developer8ac909d2023-08-25 11:03:33 +080067static void mtk_xfrm_offload_cls_entry_tear_down(struct mtk_xfrm_params *xfrm_params)
68{
69 memset(&xfrm_params->cdrt->cls->cdesc, 0, sizeof(struct cls_desc));
70
71 mtk_pce_cls_entry_write(xfrm_params->cdrt->cls);
72
73 mtk_pce_cls_entry_free(xfrm_params->cdrt->cls);
74}
75
developer94c513e2023-08-21 17:33:25 +080076static int mtk_xfrm_offload_cls_entry_setup(struct mtk_xfrm_params *xfrm_params)
77{
developer8ac909d2023-08-25 11:03:33 +080078 struct cls_desc *cdesc;
79
80 xfrm_params->cdrt->cls = mtk_pce_cls_entry_alloc();
81 if (IS_ERR(xfrm_params->cdrt->cls))
82 return PTR_ERR(xfrm_params->cdrt->cls);
developer94c513e2023-08-21 17:33:25 +080083
developer8ac909d2023-08-25 11:03:33 +080084 cdesc = &xfrm_params->cdrt->cls->cdesc;
developer94c513e2023-08-21 17:33:25 +080085
developer8ac909d2023-08-25 11:03:33 +080086 CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
87 CLS_DESC_DATA(cdesc, tport_idx, 0x2);
88 CLS_DESC_DATA(cdesc, cdrt_idx, xfrm_params->cdrt->idx);
89
90 CLS_DESC_MASK_DATA(cdesc, tag,
91 CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_HDR);
92 CLS_DESC_MASK_DATA(cdesc, l4_udp_hdr_nez,
93 CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK,
94 CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK);
95 CLS_DESC_MASK_DATA(cdesc, l4_type,
96 CLS_DESC_L4_TYPE_MASK, IPPROTO_ESP);
97 CLS_DESC_MASK_DATA(cdesc, l4_valid,
98 0x3,
99 CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
100 CLS_DESC_VALID_LOWER_HALF_WORD_BIT);
101 CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data,
102 0xFFFFFFFF, be32_to_cpu(xfrm_params->xs->id.spi));
103
104 return mtk_pce_cls_entry_write(xfrm_params->cdrt->cls);
developer94c513e2023-08-21 17:33:25 +0800105}
106
107static void mtk_xfrm_offload_context_tear_down(struct mtk_xfrm_params *xfrm_params)
108{
109 mtk_xfrm_offload_cdrt_tear_down(xfrm_params);
110
111 /* TODO: free context */
112 devm_kfree(crypto_dev, xfrm_params->p_tr);
113
114 /* TODO: transform record tear down */
115}
116
117static int mtk_xfrm_offload_context_setup(struct mtk_xfrm_params *xfrm_params)
118{
119 u32 *tr;
120 int ret;
121
122 xfrm_params->p_tr = devm_kcalloc(crypto_dev, sizeof(u32),
123 TRANSFORM_RECORD_LEN, GFP_KERNEL);
124 if (unlikely(!xfrm_params->p_tr))
125 return -ENOMEM;
126
127 switch (xfrm_params->xs->outer_mode.encap) {
128 case XFRM_MODE_TUNNEL:
129 tr = mtk_ddk_tr_ipsec_build(xfrm_params, SAB_IPSEC_TUNNEL);
130 break;
131 case XFRM_MODE_TRANSPORT:
132 tr = mtk_ddk_tr_ipsec_build(xfrm_params, SAB_IPSEC_TRANSPORT);
133 break;
134 default:
135 ret = -ENOMEM;
136 goto err_out;
137 }
138
139 if (!tr) {
140 ret = -EINVAL;
141 goto err_out;
142 }
143
144 memcpy(xfrm_params->p_tr, tr, sizeof(u32) * TRANSFORM_RECORD_LEN);
145
146 /* TODO: free tr */
147
148 return mtk_xfrm_offload_cdrt_setup(xfrm_params);
149
150err_out:
151 devm_kfree(crypto_dev, xfrm_params->p_tr);
152
153 return ret;
154}
155
156static int mtk_xfrm_offload_state_add_outbound(struct xfrm_state *xs,
157 struct mtk_xfrm_params *xfrm_params)
158{
159 int ret;
160
161 xfrm_params->cdrt = mtk_pce_cdrt_entry_alloc(CDRT_ENCRYPT);
162 if (IS_ERR(xfrm_params->cdrt))
163 return PTR_ERR(xfrm_params->cdrt);
164
165 xfrm_params->dir = SAB_DIRECTION_OUTBOUND;
166
167 ret = mtk_xfrm_offload_context_setup(xfrm_params);
168 if (ret)
169 goto free_cdrt;
170
171 return ret;
172
173free_cdrt:
174 mtk_pce_cdrt_entry_free(xfrm_params->cdrt);
175
176 return ret;
177}
178
179static int mtk_xfrm_offload_state_add_inbound(struct xfrm_state *xs,
180 struct mtk_xfrm_params *xfrm_params)
181{
182 int ret;
183
184 xfrm_params->cdrt = mtk_pce_cdrt_entry_alloc(CDRT_DECRYPT);
185 if (IS_ERR(xfrm_params->cdrt))
186 return PTR_ERR(xfrm_params->cdrt);
187
188 xfrm_params->dir = SAB_DIRECTION_INBOUND;
189
190 ret = mtk_xfrm_offload_context_setup(xfrm_params);
191 if (ret)
192 goto free_cdrt;
193
194 ret = mtk_xfrm_offload_cls_entry_setup(xfrm_params);
195 if (ret)
196 goto tear_down_context;
197
198 return ret;
199
200tear_down_context:
201 mtk_xfrm_offload_context_tear_down(xfrm_params);
202
203free_cdrt:
204 mtk_pce_cdrt_entry_free(xfrm_params->cdrt);
205
206 return ret;
207}
208
209int mtk_xfrm_offload_state_add(struct xfrm_state *xs)
210{
211 struct mtk_xfrm_params *xfrm_params;
212 int ret = 0;
213
214 /* TODO: maybe support IPv6 in the future? */
215 if (xs->props.family != AF_INET) {
216 CRYPTO_NOTICE("Only IPv4 xfrm states may be offloaded\n");
217 return -EINVAL;
218 }
219
220 /* only support ESP right now */
221 if (xs->id.proto != IPPROTO_ESP) {
222 CRYPTO_NOTICE("Unsupported protocol 0x%04x\n", xs->id.proto);
223 return -EINVAL;
224 }
225
226 /* only support tunnel mode or transport mode */
227 if (!(xs->outer_mode.encap == XFRM_MODE_TUNNEL
228 || xs->outer_mode.encap == XFRM_MODE_TRANSPORT))
229 return -EINVAL;
230
231 xfrm_params = devm_kzalloc(crypto_dev,
232 sizeof(struct mtk_xfrm_params),
233 GFP_KERNEL);
234 if (!xfrm_params)
235 return -ENOMEM;
236
237 xfrm_params->xs = xs;
238 INIT_LIST_HEAD(&xfrm_params->node);
239
240 if (xs->xso.flags & XFRM_OFFLOAD_INBOUND)
241 /* rx path */
242 ret = mtk_xfrm_offload_state_add_inbound(xs, xfrm_params);
243 else
244 /* tx path */
245 ret = mtk_xfrm_offload_state_add_outbound(xs, xfrm_params);
246
247 if (ret) {
248 devm_kfree(crypto_dev, xfrm_params);
249 goto out;
250 }
251
252 xs->xso.offload_handle = (unsigned long)xfrm_params;
253 list_add_tail(&xfrm_params->node, &xfrm_params_head);
254out:
255 return ret;
256}
257
258void mtk_xfrm_offload_state_delete(struct xfrm_state *xs)
259{
260}
261
262void mtk_xfrm_offload_state_free(struct xfrm_state *xs)
263{
264 struct mtk_xfrm_params *xfrm_params;
265
266 if (!xs->xso.offload_handle)
267 return;
268
269 xfrm_params = (struct mtk_xfrm_params *)xs->xso.offload_handle;
270
271 list_del(&xfrm_params->node);
272
273 if (xs->xso.flags & XFRM_OFFLOAD_INBOUND)
developer8ac909d2023-08-25 11:03:33 +0800274 mtk_xfrm_offload_cls_entry_tear_down(xfrm_params);
developer94c513e2023-08-21 17:33:25 +0800275
276 mtk_xfrm_offload_context_tear_down(xfrm_params);
277
278 mtk_pce_cdrt_entry_free(xfrm_params->cdrt);
279
280 devm_kfree(crypto_dev, xfrm_params);
281}
282
283void mtk_xfrm_offload_state_tear_down(void)
284{
285 struct mtk_xfrm_params *xfrm_params, *tmp;
286
287 list_for_each_entry_safe(xfrm_params, tmp, &xfrm_params_head, node)
288 mtk_xfrm_offload_state_free(xfrm_params->xs);
289}
290
291int mtk_xfrm_offload_policy_add(struct xfrm_policy *xp)
292{
293 return 0;
294}
295
developerd0a7d722023-10-19 11:24:25 +0800296static inline struct neighbour *mtk_crypto_find_dst_mac(struct sk_buff *skb, struct xfrm_state *xs)
297{
298 struct neighbour *neigh;
299 u32 nexthop;
300 struct dst_entry *dst = skb_dst(skb);
301 struct rtable *rt = (struct rtable *) dst;
302
303 nexthop = (__force u32) rt_nexthop(rt, xs->id.daddr.a4);
304 neigh = __ipv4_neigh_lookup_noref(dst->dev, nexthop);
305 if (unlikely(!neigh)) {
306 CRYPTO_INFO("%s: %s No neigh (daddr=%pI4)\n", __func__, dst->dev->name,
307 &xs->id.daddr.a4);
308 neigh = __neigh_create(&arp_tbl, &xs->id.daddr.a4, dst->dev, false);
developerfba064e2024-01-09 14:52:17 +0800309 neigh_output(neigh, skb, false);
developerd0a7d722023-10-19 11:24:25 +0800310 return NULL;
311 }
312
313 return neigh;
314}
315
developer94c513e2023-08-21 17:33:25 +0800316bool mtk_xfrm_offload_ok(struct sk_buff *skb,
317 struct xfrm_state *xs)
318{
319 struct mtk_xfrm_params *xfrm_params;
developerd0a7d722023-10-19 11:24:25 +0800320 struct neighbour *neigh;
321 struct dst_entry *dst = skb_dst(skb);
322
323 rcu_read_lock_bh();
324
325 neigh = mtk_crypto_find_dst_mac(skb, xs);
326 if (!neigh) {
327 rcu_read_unlock_bh();
328 return true;
329 }
330
331 skb_push(skb, sizeof(struct ethhdr));
332 skb_reset_mac_header(skb);
333
334 eth_hdr(skb)->h_proto = htons(ETH_P_IP);
335 memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
336 memcpy(eth_hdr(skb)->h_source, dst->dev->dev_addr, ETH_ALEN);
337
338 rcu_read_unlock_bh();
339
340 xfrm_params = (struct mtk_xfrm_params *)xs->xso.offload_handle;
341 skb_hnat_cdrt(skb) = xfrm_params->cdrt->idx;
developer94c513e2023-08-21 17:33:25 +0800342
developer52e00b72023-09-04 11:13:18 +0800343 /*
344 * EIP197 does not support fragmentation. As a result, we can not bind UDP
345 * flow since it may cause network fail due to fragmentation
346 */
developerd0a7d722023-10-19 11:24:25 +0800347 if ((is_tops_udp_tunnel(skb) || is_tcp(skb)) && is_hnat_rate_reach(skb))
348 hnat_bind_crypto_entry(skb, dst->dev);
developer52e00b72023-09-04 11:13:18 +0800349
developerd0a7d722023-10-19 11:24:25 +0800350 /* Since we're going to tx directly, set skb->dev to dst->dev */
351 skb->dev = dst->dev;
352 /* Set magic tag for tport setting, reset to 0 after tport is set */
353 skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
developer05215d12024-01-04 19:14:19 +0800354
355 /*
356 * Since skb headroom may not be copy when segment, we cannot rely on
357 * headroom data (ex. cdrt) to decide packets should send to EIP197.
358 * Here is a workaround that only skb with inner_protocol = ESP will
359 * be sent to EIP197.
360 */
361 skb->inner_protocol = IPPROTO_ESP;
developerd0a7d722023-10-19 11:24:25 +0800362 /*
363 * Tx packet to EIP197.
364 * To avoid conflict of SW and HW sequence number
365 * All offloadable packets send to EIP197
366 */
367 dev_queue_xmit(skb);
developer94c513e2023-08-21 17:33:25 +0800368
developerd0a7d722023-10-19 11:24:25 +0800369 return true;
developer94c513e2023-08-21 17:33:25 +0800370}