blob: d00d3c0f4c1e93217766843cf5ecae7c22450580 [file] [log] [blame]
developer0fb30d52023-12-04 09:51:36 +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/netdevice.h>
10
11#include <pce/cls.h>
12#include <pce/netsys.h>
13#include <pce/pce.h>
14
15#include "tops/internal.h"
16#include "tops/protocol/mac/ppp.h"
17#include "tops/protocol/transport/udp.h"
18#include "tops/protocol/tunnel/l2tp/l2tpv2.h"
19#include "tops/tunnel.h"
20
21static int l2tpv2_cls_entry_setup(struct tops_tnl_info *tnl_info,
22 struct cls_desc *cdesc)
23{
24 CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
25 CLS_DESC_DATA(cdesc, tport_idx, 0x4);
26 CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_USR);
27 CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
28 CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_UDP);
29 CLS_DESC_MASK_DATA(cdesc, l4_valid,
30 CLS_DESC_L4_VALID_MASK,
31 CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
32 CLS_DESC_VALID_LOWER_HALF_WORD_BIT |
33 CLS_DESC_VALID_DPORT_BIT);
34 CLS_DESC_MASK_DATA(cdesc, l4_dport, CLS_DESC_L4_DPORT_MASK, 1701);
35 CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x80030000, 0x00020000);
36
37 return 0;
38}
39
40static inline bool l2tpv2_offload_valid(struct sk_buff *skb)
41{
42 struct udp_l2tp_data_hdr *l2tp;
43 struct udp_l2tp_data_hdr l2tph;
44 u16 hdrflags;
45
46 l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
47 if (!l2tp)
48 return false;
49
50 hdrflags = ntohs(l2tp->flag_ver);
51
52 return ((hdrflags & L2TP_HDR_VER_MASK) == L2TP_HDR_VER_2 &&
53 !(hdrflags & L2TP_HDRFLAG_T));
54}
55
56static int l2tpv2_tnl_decap_param_setup(struct sk_buff *skb,
57 struct tops_params *params)
58{
59 struct tops_l2tp_params *l2tpp;
60 struct udp_l2tp_data_hdr *l2tp;
61 struct udp_l2tp_data_hdr l2tph;
62 int ret = 0;
63
64 /* ppp */
65 skb_push(skb, sizeof(struct ppp_hdr));
66 if (unlikely(!mtk_tops_ppp_valid(skb))) {
67 ret = -EINVAL;
68 goto restore_ppp;
69 }
70
71 /* l2tp */
72 skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
73 if (unlikely(!l2tpv2_offload_valid(skb))) {
74 ret = -EINVAL;
75 goto restore_l2tp;
76 }
77
78 l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
79 if (unlikely(!l2tp)) {
80 ret = -EINVAL;
81 goto restore_l2tp;
82 }
83
84 params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
85
86 l2tpp = &params->tunnel.l2tp;
87 l2tpp->tid = l2tp->tid;
88 l2tpp->sid = l2tp->sid;
89
90 ret = mtk_tops_transport_decap_param_setup(skb, params);
91
92restore_l2tp:
93 skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
94
95restore_ppp:
96 skb_pull(skb, sizeof(struct ppp_hdr));
97
98 return ret;
99}
100
101static int l2tpv2_tnl_encap_param_setup(struct sk_buff *skb,
102 struct tops_params *params)
103{
104 struct tops_l2tp_params *l2tpp;
105 struct udp_l2tp_data_hdr *l2tp;
106 struct udp_l2tp_data_hdr l2tph;
107
108 if (unlikely(!l2tpv2_offload_valid(skb)))
109 return -EINVAL;
110
111 l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
112 if (unlikely(!l2tp))
113 return -EINVAL;
114
115 params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
116
117 l2tpp = &params->tunnel.l2tp;
118 l2tpp->tid = l2tp->tid;
119 l2tpp->sid = l2tp->sid;
120
121 return 0;
122}
123
124static int l2tpv2_tnl_debug_param_setup(const char *buf, int *ofs,
125 struct tops_params *params)
126{
127 struct tops_l2tp_params *l2tpp;
128 int nchar = 0;
129 int ret;
130 u16 tid = 0;
131 u16 sid = 0;
132
133 params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
134 l2tpp = &params->tunnel.l2tp;
135
136 ret = sscanf(buf + *ofs, "%hu %hu %n", &tid, &sid, &nchar);
137 if (ret != 2)
138 return -EINVAL;
139
140 l2tpp->tid = htons(tid);
141 l2tpp->sid = htons(sid);
142
143 *ofs += nchar;
144
145 return 0;
146}
147
148static int l2tpv2_tnl_l2_param_update(struct sk_buff *skb,
149 struct tops_params *params)
150{
151 struct ethhdr *eth = eth_hdr(skb);
152 struct tops_mac_params *mac = &params->mac;
153
154 memcpy(&mac->eth.h_source, eth->h_source, sizeof(u8) * ETH_ALEN);
155 memcpy(&mac->eth.h_dest, eth->h_dest, sizeof(u8) * ETH_ALEN);
156
157 return 1;
158}
159
160static bool l2tpv2_tnl_decap_offloadable(struct sk_buff *skb)
161{
162 struct iphdr *ip;
163 bool ret = true;
164 u32 ip_len;
165
166 ip = ip_hdr(skb);
167 if (ip->protocol != IPPROTO_UDP)
168 return false;
169
170 ip_len = ip_hdr(skb)->ihl * 4;
171
172 skb_pull(skb, ip_len + sizeof(struct udphdr));
173 if (!l2tpv2_offload_valid(skb)) {
174 ret = false;
175 goto restore_ip_udp;
176 }
177
178 skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
179 if (!mtk_tops_ppp_valid(skb)) {
180 ret = false;
181 goto restore_l2tp;
182 }
183
184restore_l2tp:
185 skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
186restore_ip_udp:
187 skb_push(skb, ip_len + sizeof(struct udphdr));
188
189 return ret;
190}
191
192static void l2tpv2_tnl_param_dump(struct seq_file *s, struct tops_params *params)
193{
194 struct tops_l2tp_params *l2tpp = &params->tunnel.l2tp;
195
196 seq_puts(s, "\tTunnel Type: L2TPv2 ");
197 seq_printf(s, "tunnel ID: %05u session ID: %05u\n",
198 ntohs(l2tpp->tid), ntohs(l2tpp->sid));
199}
200
201static struct tops_tnl_type l2tpv2_type = {
202 .type_name = "l2tpv2",
203 .cls_entry_setup = l2tpv2_cls_entry_setup,
204 .tnl_decap_param_setup = l2tpv2_tnl_decap_param_setup,
205 .tnl_encap_param_setup = l2tpv2_tnl_encap_param_setup,
206 .tnl_debug_param_setup = l2tpv2_tnl_debug_param_setup,
207 .tnl_decap_offloadable = l2tpv2_tnl_decap_offloadable,
208 .tnl_l2_param_update = l2tpv2_tnl_l2_param_update,
209 .tnl_param_dump = l2tpv2_tnl_param_dump,
210 .tnl_proto_type = TOPS_TUNNEL_L2TP_V2,
211 .has_inner_eth = false,
212};
213
214int mtk_tops_l2tpv2_init(void)
215{
216 return mtk_tops_tnl_type_register(&l2tpv2_type);
217}
218
219void mtk_tops_l2tpv2_deinit(void)
220{
221 mtk_tops_tnl_type_unregister(&l2tpv2_type);
222}