blob: 592271dd391881b99662c7fc77b5cd86c9e274a2 [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Frank-zj Lin <rank-zj.lin@mediatek.com>
6 * Ren-Ting Wang <ren-ting.wang@mediatek.com>
7 */
8
9#include <linux/if_ether.h>
10#include <linux/netdevice.h>
11#include <linux/ppp_defs.h>
12#include <linux/udp.h>
13
14#include <pce/cls.h>
developer15ee46c2023-08-24 16:35:34 +080015#include <pce/netsys.h>
developere5e687d2023-08-08 16:05:33 +080016#include <pce/pce.h>
17
18#include "protocol/l2tp/l2tp.h"
19#include "protocol/ppp/ppp.h"
20#include "tunnel.h"
21
developer15ee46c2023-08-24 16:35:34 +080022static int udp_l2tp_data_cls_entry_setup(struct tops_tnl_info *tnl_info,
23 struct cls_desc *cdesc)
24{
25 CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
26 CLS_DESC_DATA(cdesc, tport_idx, 0x4);
27 CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_USR);
28 CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
29 CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_UDP);
30 CLS_DESC_MASK_DATA(cdesc, l4_valid,
31 CLS_DESC_L4_VALID_MASK,
32 CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
33 CLS_DESC_VALID_LOWER_HALF_WORD_BIT |
34 CLS_DESC_VALID_DPORT_BIT);
35 CLS_DESC_MASK_DATA(cdesc, l4_dport, CLS_DESC_L4_DPORT_MASK, 1701);
36 CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x80030000, 0x00020000);
37
38 return 0;
39}
developere5e687d2023-08-08 16:05:33 +080040
41static inline bool l2tpv2_offload_match(struct udp_l2tp_data_hdr *l2tp)
42{
43 u16 hdrflags = ntohs(l2tp->flag_ver);
44
45 return ((hdrflags & L2TP_HDR_VER_MASK) == L2TP_HDR_VER_2 &&
46 !(hdrflags & L2TP_HDRFLAG_T));
47}
48
49static inline bool ppp_offload_match(struct ppp_hdr *ppp)
50{
51 return (ppp->addr == PPP_ALLSTATIONS &&
52 ppp->ctrl == PPP_UI && ntohs(ppp->proto) == PPP_IP);
53}
54
55static int udp_l2tp_data_tnl_decap_param_setup(struct sk_buff *skb,
56 struct tops_tnl_params *tnl_params)
57{
58 struct udp_l2tp_data_hdr *l2tp;
59 struct udp_l2tp_data_hdr l2tph;
60 struct ppp_hdr *ppp;
61 struct ppp_hdr ppph;
62 struct udphdr *udp;
63 struct udphdr udph;
64 struct ethhdr *eth;
65 struct ethhdr ethh;
66 struct iphdr *ip;
67 struct iphdr iph;
68 int ret = 0;
69
70 /* ppp */
71 skb_push(skb, sizeof(struct ppp_hdr));
72 ppp = skb_header_pointer(skb, 0, sizeof(struct ppp_hdr), &ppph);
73
74 if (unlikely(!ppp)) {
75 ret = -EINVAL;
76 goto restore_ppp;
77 }
78
79 if (unlikely(!ppp_offload_match(ppp))) {
80 pr_notice("ppp offload unmatched\n");
81 ret = -EINVAL;
82 goto restore_ppp;
83 }
84
85 /* l2tp */
86 skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
87 l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
88 if (unlikely(!l2tp)) {
89 ret = -EINVAL;
90 goto restore_l2tp;
91 }
92
93 if (unlikely(!l2tpv2_offload_match(l2tp))) {
94 ret = -EINVAL;
95 goto restore_l2tp;
96 }
97
98 tnl_params->priv.l2tp.tid = l2tp->tid;
99 tnl_params->priv.l2tp.sid = l2tp->sid;
100
101 /* udp */
102 skb_push(skb, sizeof(struct udphdr));
103 udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
104 if (unlikely(!udp)) {
105 ret = -EINVAL;
106 goto restore_udp;
107 }
108
109 if (unlikely(ntohs(udp->dest) != UDP_L2TP_PORT)) {
110 pr_notice("udp port 0x%x unmatched\n", ntohs(udp->dest));
111 ret = -EINVAL;
112 goto restore_udp;
113 }
114
115 tnl_params->sport = udp->dest;
116 tnl_params->dport = udp->source;
117
118 /* ip */
119 skb_push(skb, sizeof(struct iphdr));
120 ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
121 if (unlikely(!ip)) {
122 ret = -EINVAL;
123 goto restore_ip;
124 }
125
126 if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_UDP)) {
127 pr_notice("ip: %p version or protocol unmatched, ver: 0x%x, proto: 0x%x\n",
128 ip, ip->version, ip->protocol);
129 ret = -EINVAL;
130 goto restore_ip;
131 }
132
133 tnl_params->protocol = ip->protocol;
134 tnl_params->sip = ip->daddr;
135 tnl_params->dip = ip->saddr;
136
137 /* eth */
138 skb_push(skb, sizeof(struct ethhdr));
139 eth = skb_header_pointer(skb, 0, sizeof(struct ethhdr), &ethh);
140 if (unlikely(!eth)) {
141 ret = -EINVAL;
142 goto restore_eth;
143 }
144
145 if (unlikely(ntohs(eth->h_proto) != ETH_P_IP)) {
146 pr_notice("eth proto not supported, proto: 0x%x\n",
147 ntohs(eth->h_proto));
148 ret = -EINVAL;
149 goto restore_eth;
150 }
151
152 memcpy(&tnl_params->saddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
153 memcpy(&tnl_params->daddr, eth->h_source, sizeof(u8) * ETH_ALEN);
154
155restore_eth:
156 skb_pull(skb, sizeof(struct ethhdr));
157restore_ip:
158 skb_pull(skb, sizeof(struct iphdr));
159restore_udp:
160 skb_pull(skb, sizeof(struct udphdr));
161restore_l2tp:
162 skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
163restore_ppp:
164 skb_pull(skb, sizeof(struct ppp_hdr));
165
166 return ret;
167}
168
169static int udp_l2tp_data_tnl_encap_param_setup(struct sk_buff *skb,
170 struct tops_tnl_params *tnl_params)
171{
172 struct ethhdr *eth = eth_hdr(skb);
173 struct iphdr *ip = ip_hdr(skb);
174 struct udp_l2tp_data_hdr *l2tp;
175 struct udp_l2tp_data_hdr l2tph;
176 struct udphdr *udp;
177 struct udphdr udph;
178 int ret = 0;
179
180 if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_UDP)) {
181 pr_notice("eth proto: 0x%x, ip ver: 0x%x, proto: 0x%x is not support\n",
182 ntohs(eth->h_proto),
183 ip->version,
184 ip->protocol);
185 ret = -EINVAL;
186 goto out;
187 }
188
189 skb_pull(skb, sizeof(struct iphdr));
190 udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
191 if (unlikely(!udp)) {
192 ret = -EINVAL;
193 goto restore_ip;
194 }
195
196 if (unlikely(ntohs(udp->dest) != UDP_L2TP_PORT)) {
197 pr_notice("udp port 0x%x unmatched\n", ntohs(udp->dest));
198 ret = -EINVAL;
199 goto restore_ip;
200 }
201
202 skb_pull(skb, sizeof(struct udphdr));
203 l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
204 if (unlikely(!l2tp)) {
205 ret = -EINVAL;
206 goto restore_udp;
207 }
208
209 if (unlikely(!l2tpv2_offload_match(l2tp))) {
210 ret = -EINVAL;
211 goto restore_udp;
212 }
213
214 memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
215 memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
216 tnl_params->protocol = ip->protocol;
217 tnl_params->sip = ip->saddr;
218 tnl_params->dip = ip->daddr;
219 tnl_params->sport = udp->source;
220 tnl_params->dport = udp->dest;
221 tnl_params->priv.l2tp.tid = l2tp->tid;
222 tnl_params->priv.l2tp.sid = l2tp->sid;
223
224restore_udp:
225 skb_push(skb, sizeof(struct udphdr));
226restore_ip:
227 skb_push(skb, sizeof(struct iphdr));
228out:
229 return ret;
230}
231
232static int udp_l2tp_data_tnl_debug_param_setup(const char *buf, int *ofs,
233 struct tops_tnl_params *tnl_params)
234{
235 return -EPERM; //TODO: not implemented
236}
237
developer48e08de2023-08-29 10:59:47 +0800238static int udp_l2tp_data_tnl_l2_param_update(struct sk_buff *skb,
239 struct tops_tnl_params *tnl_params)
240{
241 struct ethhdr *eth = eth_hdr(skb);
242
243 memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
244 memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
245
246 return 1;
247}
248
developere5e687d2023-08-08 16:05:33 +0800249static bool udp_l2tp_data_tnl_info_match(struct tops_tnl_params *params1,
250 struct tops_tnl_params *params2)
251{
252 if (params1->sip == params2->sip
253 && params1->dip == params2->dip
254 && params1->sport == params2->sport
255 && params1->dport == params2->dport
256 && params1->priv.l2tp.tid == params2->priv.l2tp.tid
developer48e08de2023-08-29 10:59:47 +0800257 && params1->priv.l2tp.sid == params2->priv.l2tp.sid)
developere5e687d2023-08-08 16:05:33 +0800258 return true;
259
260 return false;
261}
262
263static bool udp_l2tp_data_tnl_decap_offloadable(struct sk_buff *skb)
264{
265 struct udp_l2tp_data_hdr *l2tp;
266 struct udp_l2tp_data_hdr l2tph;
267 struct ppp_hdr *ppp;
268 struct ppp_hdr ppph;
269 struct udphdr *udp;
270 struct iphdr *ip;
271
272 ip = ip_hdr(skb);
273 if (ip->protocol != IPPROTO_UDP)
274 return false;
275
276 udp = udp_hdr(skb);
277 if (ntohs(udp->dest) != UDP_L2TP_PORT)
278 return false;
279
280 l2tp = skb_header_pointer(skb, ip_hdr(skb)->ihl * 4 + sizeof(struct udphdr),
281 sizeof(struct udp_l2tp_data_hdr), &l2tph);
282
283 if (unlikely(!l2tp))
284 return false;
285
286 if (unlikely(!l2tpv2_offload_match(l2tp)))
287 return false;
288
289 ppp = skb_header_pointer(skb, (ip_hdr(skb)->ihl * 4 +
290 sizeof(struct udphdr) +
291 sizeof(struct udp_l2tp_data_hdr)),
292 sizeof(struct ppp_hdr), &ppph);
293
294 if (unlikely(!ppp))
295 return false;
296
297 if (unlikely(!ppp_offload_match(ppp)))
298 return false;
299
300 return true;
301}
302
303static struct tops_tnl_type udp_l2tp_data_type = {
304 .type_name = "udp-l2tp-data",
developer15ee46c2023-08-24 16:35:34 +0800305 .cls_entry_setup = udp_l2tp_data_cls_entry_setup,
developere5e687d2023-08-08 16:05:33 +0800306 .tnl_decap_param_setup = udp_l2tp_data_tnl_decap_param_setup,
307 .tnl_encap_param_setup = udp_l2tp_data_tnl_encap_param_setup,
308 .tnl_debug_param_setup = udp_l2tp_data_tnl_debug_param_setup,
developer48e08de2023-08-29 10:59:47 +0800309 .tnl_l2_param_update = udp_l2tp_data_tnl_l2_param_update,
developere5e687d2023-08-08 16:05:33 +0800310 .tnl_info_match = udp_l2tp_data_tnl_info_match,
311 .tnl_decap_offloadable = udp_l2tp_data_tnl_decap_offloadable,
312 .tops_entry = TOPS_ENTRY_UDP_L2TP_DATA,
313 .has_inner_eth = false,
314};
315
316int mtk_tops_udp_l2tp_data_init(void)
317{
developer15ee46c2023-08-24 16:35:34 +0800318 return mtk_tops_tnl_type_register(&udp_l2tp_data_type);
developere5e687d2023-08-08 16:05:33 +0800319}
320
321void mtk_tops_udp_l2tp_data_deinit(void)
322{
developere5e687d2023-08-08 16:05:33 +0800323 mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
324}