xref: /OK3568_Linux_fs/kernel/net/ipv4/gre_demux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *	GRE over IPv4 demultiplexer driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *	Authors: Dmitry Kozlov (xeb@mail.ru)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/if.h>
12*4882a593Smuzhiyun #include <linux/icmp.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/kmod.h>
15*4882a593Smuzhiyun #include <linux/skbuff.h>
16*4882a593Smuzhiyun #include <linux/in.h>
17*4882a593Smuzhiyun #include <linux/ip.h>
18*4882a593Smuzhiyun #include <linux/netdevice.h>
19*4882a593Smuzhiyun #include <linux/if_tunnel.h>
20*4882a593Smuzhiyun #include <linux/spinlock.h>
21*4882a593Smuzhiyun #include <net/protocol.h>
22*4882a593Smuzhiyun #include <net/gre.h>
23*4882a593Smuzhiyun #include <net/erspan.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <net/icmp.h>
26*4882a593Smuzhiyun #include <net/route.h>
27*4882a593Smuzhiyun #include <net/xfrm.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
30*4882a593Smuzhiyun 
gre_add_protocol(const struct gre_protocol * proto,u8 version)31*4882a593Smuzhiyun int gre_add_protocol(const struct gre_protocol *proto, u8 version)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	if (version >= GREPROTO_MAX)
34*4882a593Smuzhiyun 		return -EINVAL;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
37*4882a593Smuzhiyun 		0 : -EBUSY;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gre_add_protocol);
40*4882a593Smuzhiyun 
gre_del_protocol(const struct gre_protocol * proto,u8 version)41*4882a593Smuzhiyun int gre_del_protocol(const struct gre_protocol *proto, u8 version)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	int ret;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if (version >= GREPROTO_MAX)
46*4882a593Smuzhiyun 		return -EINVAL;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
49*4882a593Smuzhiyun 		0 : -EBUSY;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (ret)
52*4882a593Smuzhiyun 		return ret;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	synchronize_rcu();
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gre_del_protocol);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* Fills in tpi and returns header length to be pulled.
60*4882a593Smuzhiyun  * Note that caller must use pskb_may_pull() before pulling GRE header.
61*4882a593Smuzhiyun  */
gre_parse_header(struct sk_buff * skb,struct tnl_ptk_info * tpi,bool * csum_err,__be16 proto,int nhs)62*4882a593Smuzhiyun int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
63*4882a593Smuzhiyun 		     bool *csum_err, __be16 proto, int nhs)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	const struct gre_base_hdr *greh;
66*4882a593Smuzhiyun 	__be32 *options;
67*4882a593Smuzhiyun 	int hdr_len;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr))))
70*4882a593Smuzhiyun 		return -EINVAL;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	greh = (struct gre_base_hdr *)(skb->data + nhs);
73*4882a593Smuzhiyun 	if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
74*4882a593Smuzhiyun 		return -EINVAL;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	tpi->flags = gre_flags_to_tnl_flags(greh->flags);
77*4882a593Smuzhiyun 	hdr_len = gre_calc_hlen(tpi->flags);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, nhs + hdr_len))
80*4882a593Smuzhiyun 		return -EINVAL;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	greh = (struct gre_base_hdr *)(skb->data + nhs);
83*4882a593Smuzhiyun 	tpi->proto = greh->protocol;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	options = (__be32 *)(greh + 1);
86*4882a593Smuzhiyun 	if (greh->flags & GRE_CSUM) {
87*4882a593Smuzhiyun 		if (!skb_checksum_simple_validate(skb)) {
88*4882a593Smuzhiyun 			skb_checksum_try_convert(skb, IPPROTO_GRE,
89*4882a593Smuzhiyun 						 null_compute_pseudo);
90*4882a593Smuzhiyun 		} else if (csum_err) {
91*4882a593Smuzhiyun 			*csum_err = true;
92*4882a593Smuzhiyun 			return -EINVAL;
93*4882a593Smuzhiyun 		}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 		options++;
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (greh->flags & GRE_KEY) {
99*4882a593Smuzhiyun 		tpi->key = *options;
100*4882a593Smuzhiyun 		options++;
101*4882a593Smuzhiyun 	} else {
102*4882a593Smuzhiyun 		tpi->key = 0;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	if (unlikely(greh->flags & GRE_SEQ)) {
105*4882a593Smuzhiyun 		tpi->seq = *options;
106*4882a593Smuzhiyun 		options++;
107*4882a593Smuzhiyun 	} else {
108*4882a593Smuzhiyun 		tpi->seq = 0;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 	/* WCCP version 1 and 2 protocol decoding.
111*4882a593Smuzhiyun 	 * - Change protocol to IPv4/IPv6
112*4882a593Smuzhiyun 	 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
113*4882a593Smuzhiyun 	 */
114*4882a593Smuzhiyun 	if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
115*4882a593Smuzhiyun 		u8 _val, *val;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 		val = skb_header_pointer(skb, nhs + hdr_len,
118*4882a593Smuzhiyun 					 sizeof(_val), &_val);
119*4882a593Smuzhiyun 		if (!val)
120*4882a593Smuzhiyun 			return -EINVAL;
121*4882a593Smuzhiyun 		tpi->proto = proto;
122*4882a593Smuzhiyun 		if ((*val & 0xF0) != 0x40)
123*4882a593Smuzhiyun 			hdr_len += 4;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	tpi->hdr_len = hdr_len;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* ERSPAN ver 1 and 2 protocol sets GRE key field
128*4882a593Smuzhiyun 	 * to 0 and sets the configured key in the
129*4882a593Smuzhiyun 	 * inner erspan header field
130*4882a593Smuzhiyun 	 */
131*4882a593Smuzhiyun 	if ((greh->protocol == htons(ETH_P_ERSPAN) && hdr_len != 4) ||
132*4882a593Smuzhiyun 	    greh->protocol == htons(ETH_P_ERSPAN2)) {
133*4882a593Smuzhiyun 		struct erspan_base_hdr *ershdr;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr)))
136*4882a593Smuzhiyun 			return -EINVAL;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len);
139*4882a593Smuzhiyun 		tpi->key = cpu_to_be32(get_session_id(ershdr));
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return hdr_len;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun EXPORT_SYMBOL(gre_parse_header);
145*4882a593Smuzhiyun 
gre_rcv(struct sk_buff * skb)146*4882a593Smuzhiyun static int gre_rcv(struct sk_buff *skb)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	const struct gre_protocol *proto;
149*4882a593Smuzhiyun 	u8 ver;
150*4882a593Smuzhiyun 	int ret;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, 12))
153*4882a593Smuzhiyun 		goto drop;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	ver = skb->data[1]&0x7f;
156*4882a593Smuzhiyun 	if (ver >= GREPROTO_MAX)
157*4882a593Smuzhiyun 		goto drop;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	rcu_read_lock();
160*4882a593Smuzhiyun 	proto = rcu_dereference(gre_proto[ver]);
161*4882a593Smuzhiyun 	if (!proto || !proto->handler)
162*4882a593Smuzhiyun 		goto drop_unlock;
163*4882a593Smuzhiyun 	ret = proto->handler(skb);
164*4882a593Smuzhiyun 	rcu_read_unlock();
165*4882a593Smuzhiyun 	return ret;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun drop_unlock:
168*4882a593Smuzhiyun 	rcu_read_unlock();
169*4882a593Smuzhiyun drop:
170*4882a593Smuzhiyun 	kfree_skb(skb);
171*4882a593Smuzhiyun 	return NET_RX_DROP;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
gre_err(struct sk_buff * skb,u32 info)174*4882a593Smuzhiyun static int gre_err(struct sk_buff *skb, u32 info)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	const struct gre_protocol *proto;
177*4882a593Smuzhiyun 	const struct iphdr *iph = (const struct iphdr *)skb->data;
178*4882a593Smuzhiyun 	u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
179*4882a593Smuzhiyun 	int err = 0;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (ver >= GREPROTO_MAX)
182*4882a593Smuzhiyun 		return -EINVAL;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	rcu_read_lock();
185*4882a593Smuzhiyun 	proto = rcu_dereference(gre_proto[ver]);
186*4882a593Smuzhiyun 	if (proto && proto->err_handler)
187*4882a593Smuzhiyun 		proto->err_handler(skb, info);
188*4882a593Smuzhiyun 	else
189*4882a593Smuzhiyun 		err = -EPROTONOSUPPORT;
190*4882a593Smuzhiyun 	rcu_read_unlock();
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return err;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun static const struct net_protocol net_gre_protocol = {
196*4882a593Smuzhiyun 	.handler     = gre_rcv,
197*4882a593Smuzhiyun 	.err_handler = gre_err,
198*4882a593Smuzhiyun 	.netns_ok    = 1,
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
gre_init(void)201*4882a593Smuzhiyun static int __init gre_init(void)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	pr_info("GRE over IPv4 demultiplexor driver\n");
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
206*4882a593Smuzhiyun 		pr_err("can't add protocol\n");
207*4882a593Smuzhiyun 		return -EAGAIN;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 	return 0;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
gre_exit(void)212*4882a593Smuzhiyun static void __exit gre_exit(void)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun module_init(gre_init);
218*4882a593Smuzhiyun module_exit(gre_exit);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
221*4882a593Smuzhiyun MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
222*4882a593Smuzhiyun MODULE_LICENSE("GPL");
223