blob: bde94e5069b6904e8464fe8d02859324a71a4ddd [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>
15#include <pce/pce.h>
16
17#include "protocol/l2tp/l2tp.h"
18#include "protocol/ppp/ppp.h"
19#include "tunnel.h"
20
21static struct cls_entry udp_l2tp_data_cls_entry = {
22 .entry = CLS_ENTRY_UDP_L2TP_DATA,
23 .cdesc = {
24 .fport = 0x3,
25 .tport_idx = 0x4,
26 .tag_m = 0x3,
27 .tag = 0x2,
28 .dip_match_m = 0x1,
29 .dip_match = 0x1,
30 .l4_type_m = 0xFF,
31 .l4_type = 0x11,
32 .l4_valid_m = 0x7,
33 .l4_valid = 0x7,
34 .l4_dport_m = 0xFFFF,
35 .l4_dport = 1701,
36 .l4_hdr_usr_data_m = 0x80030000,
37 .l4_hdr_usr_data = 0x00020000,
38 },
39};
40
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
238static bool udp_l2tp_data_tnl_info_match(struct tops_tnl_params *params1,
239 struct tops_tnl_params *params2)
240{
241 if (params1->sip == params2->sip
242 && params1->dip == params2->dip
243 && params1->sport == params2->sport
244 && params1->dport == params2->dport
245 && params1->priv.l2tp.tid == params2->priv.l2tp.tid
246 && params1->priv.l2tp.sid == params2->priv.l2tp.sid
247 && !memcmp(params1->saddr, params2->saddr, sizeof(u8) * ETH_ALEN)
248 && !memcmp(params1->daddr, params2->daddr, sizeof(u8) * ETH_ALEN))
249 return true;
250
251 return false;
252}
253
254static bool udp_l2tp_data_tnl_decap_offloadable(struct sk_buff *skb)
255{
256 struct udp_l2tp_data_hdr *l2tp;
257 struct udp_l2tp_data_hdr l2tph;
258 struct ppp_hdr *ppp;
259 struct ppp_hdr ppph;
260 struct udphdr *udp;
261 struct iphdr *ip;
262
263 ip = ip_hdr(skb);
264 if (ip->protocol != IPPROTO_UDP)
265 return false;
266
267 udp = udp_hdr(skb);
268 if (ntohs(udp->dest) != UDP_L2TP_PORT)
269 return false;
270
271 l2tp = skb_header_pointer(skb, ip_hdr(skb)->ihl * 4 + sizeof(struct udphdr),
272 sizeof(struct udp_l2tp_data_hdr), &l2tph);
273
274 if (unlikely(!l2tp))
275 return false;
276
277 if (unlikely(!l2tpv2_offload_match(l2tp)))
278 return false;
279
280 ppp = skb_header_pointer(skb, (ip_hdr(skb)->ihl * 4 +
281 sizeof(struct udphdr) +
282 sizeof(struct udp_l2tp_data_hdr)),
283 sizeof(struct ppp_hdr), &ppph);
284
285 if (unlikely(!ppp))
286 return false;
287
288 if (unlikely(!ppp_offload_match(ppp)))
289 return false;
290
291 return true;
292}
293
294static struct tops_tnl_type udp_l2tp_data_type = {
295 .type_name = "udp-l2tp-data",
296 .tnl_decap_param_setup = udp_l2tp_data_tnl_decap_param_setup,
297 .tnl_encap_param_setup = udp_l2tp_data_tnl_encap_param_setup,
298 .tnl_debug_param_setup = udp_l2tp_data_tnl_debug_param_setup,
299 .tnl_info_match = udp_l2tp_data_tnl_info_match,
300 .tnl_decap_offloadable = udp_l2tp_data_tnl_decap_offloadable,
301 .tops_entry = TOPS_ENTRY_UDP_L2TP_DATA,
302 .has_inner_eth = false,
303};
304
305int mtk_tops_udp_l2tp_data_init(void)
306{
307 int ret = 0;
308
309 ret = mtk_tops_tnl_type_register(&udp_l2tp_data_type);
310 if (ret)
311 return ret;
312
313 ret = mtk_pce_cls_entry_register(&udp_l2tp_data_cls_entry);
314 if (ret) {
315 mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
316 return ret;
317 }
318
319 return ret;
320}
321
322void mtk_tops_udp_l2tp_data_deinit(void)
323{
324 mtk_pce_cls_entry_unregister(&udp_l2tp_data_cls_entry);
325
326 mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
327}