Blame view

net/ipv4/gre_demux.c 4.66 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
2
3
4
5
  /*
   *	GRE over IPv4 demultiplexer driver
   *
   *	Authors: Dmitry Kozlov (xeb@mail.ru)
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
6
   */
afd465030   Joe Perches   net: ipv4: Standa...
7
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
8
  #include <linux/module.h>
bda7bb463   Pravin B Shelar   gre: Allow multip...
9
10
  #include <linux/if.h>
  #include <linux/icmp.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
11
12
13
14
  #include <linux/kernel.h>
  #include <linux/kmod.h>
  #include <linux/skbuff.h>
  #include <linux/in.h>
559fafb94   xeb@mail.ru   gre: fix improper...
15
  #include <linux/ip.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
16
  #include <linux/netdevice.h>
68c331631   Pravin B Shelar   v4 GRE: Add TCP s...
17
  #include <linux/if_tunnel.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
18
19
20
  #include <linux/spinlock.h>
  #include <net/protocol.h>
  #include <net/gre.h>
cb73ee40b   Lorenzo Bianconi   net: ip_gre: use ...
21
  #include <net/erspan.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
22

bda7bb463   Pravin B Shelar   gre: Allow multip...
23
24
25
  #include <net/icmp.h>
  #include <net/route.h>
  #include <net/xfrm.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
26

6f0bcf152   Eric Dumazet   tunnels: add _rcu...
27
  static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
28
29
30
31
  
  int gre_add_protocol(const struct gre_protocol *proto, u8 version)
  {
  	if (version >= GREPROTO_MAX)
20fd4d1f0   Pravin B Shelar   gre: Simplify gre...
32
  		return -EINVAL;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
33

20fd4d1f0   Pravin B Shelar   gre: Simplify gre...
34
35
  	return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
  		0 : -EBUSY;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
36
37
38
39
40
  }
  EXPORT_SYMBOL_GPL(gre_add_protocol);
  
  int gre_del_protocol(const struct gre_protocol *proto, u8 version)
  {
20fd4d1f0   Pravin B Shelar   gre: Simplify gre...
41
  	int ret;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
42
  	if (version >= GREPROTO_MAX)
20fd4d1f0   Pravin B Shelar   gre: Simplify gre...
43
44
45
46
47
48
49
  		return -EINVAL;
  
  	ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
  		0 : -EBUSY;
  
  	if (ret)
  		return ret;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
50
51
  	synchronize_rcu();
  	return 0;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
52
53
  }
  EXPORT_SYMBOL_GPL(gre_del_protocol);
f132ae7c4   Jiri Benc   gre: change gre_p...
54
  /* Fills in tpi and returns header length to be pulled. */
95f5c64c3   Tom Herbert   gre: Move utility...
55
  int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
e582615ad   Eric Dumazet   gre: fix error ha...
56
  		     bool *csum_err, __be16 proto, int nhs)
95f5c64c3   Tom Herbert   gre: Move utility...
57
58
59
60
  {
  	const struct gre_base_hdr *greh;
  	__be32 *options;
  	int hdr_len;
e582615ad   Eric Dumazet   gre: fix error ha...
61
  	if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr))))
95f5c64c3   Tom Herbert   gre: Move utility...
62
  		return -EINVAL;
e582615ad   Eric Dumazet   gre: fix error ha...
63
  	greh = (struct gre_base_hdr *)(skb->data + nhs);
95f5c64c3   Tom Herbert   gre: Move utility...
64
65
66
67
68
  	if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
  		return -EINVAL;
  
  	tpi->flags = gre_flags_to_tnl_flags(greh->flags);
  	hdr_len = gre_calc_hlen(tpi->flags);
e582615ad   Eric Dumazet   gre: fix error ha...
69
  	if (!pskb_may_pull(skb, nhs + hdr_len))
95f5c64c3   Tom Herbert   gre: Move utility...
70
  		return -EINVAL;
e582615ad   Eric Dumazet   gre: fix error ha...
71
  	greh = (struct gre_base_hdr *)(skb->data + nhs);
95f5c64c3   Tom Herbert   gre: Move utility...
72
73
74
75
  	tpi->proto = greh->protocol;
  
  	options = (__be32 *)(greh + 1);
  	if (greh->flags & GRE_CSUM) {
b0350d51f   Haishuang Yan   ip_gre: fix parsi...
76
  		if (!skb_checksum_simple_validate(skb)) {
e4aa33ad5   Li RongQing   net: remove unuse...
77
  			skb_checksum_try_convert(skb, IPPROTO_GRE,
b0350d51f   Haishuang Yan   ip_gre: fix parsi...
78
79
  						 null_compute_pseudo);
  		} else if (csum_err) {
95f5c64c3   Tom Herbert   gre: Move utility...
80
81
82
  			*csum_err = true;
  			return -EINVAL;
  		}
95f5c64c3   Tom Herbert   gre: Move utility...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  		options++;
  	}
  
  	if (greh->flags & GRE_KEY) {
  		tpi->key = *options;
  		options++;
  	} else {
  		tpi->key = 0;
  	}
  	if (unlikely(greh->flags & GRE_SEQ)) {
  		tpi->seq = *options;
  		options++;
  	} else {
  		tpi->seq = 0;
  	}
  	/* WCCP version 1 and 2 protocol decoding.
da73b4e95   Haishuang Yan   gre: Fix wrong tp...
99
  	 * - Change protocol to IPv4/IPv6
95f5c64c3   Tom Herbert   gre: Move utility...
100
101
102
  	 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
  	 */
  	if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
da73b4e95   Haishuang Yan   gre: Fix wrong tp...
103
  		tpi->proto = proto;
00b203402   Jiri Benc   gre: remove super...
104
  		if ((*(u8 *)options & 0xF0) != 0x40)
95f5c64c3   Tom Herbert   gre: Move utility...
105
  			hdr_len += 4;
95f5c64c3   Tom Herbert   gre: Move utility...
106
  	}
9b8c6d7bf   Eric Dumazet   gre: better suppo...
107
  	tpi->hdr_len = hdr_len;
cb73ee40b   Lorenzo Bianconi   net: ip_gre: use ...
108
109
110
111
112
113
114
115
116
117
118
  
  	/* ERSPAN ver 1 and 2 protocol sets GRE key field
  	 * to 0 and sets the configured key in the
  	 * inner erspan header field
  	 */
  	if (greh->protocol == htons(ETH_P_ERSPAN) ||
  	    greh->protocol == htons(ETH_P_ERSPAN2)) {
  		struct erspan_base_hdr *ershdr;
  
  		if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr)))
  			return -EINVAL;
23fbdd5d1   Cong Wang   gre: refetch ersp...
119
  		ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len);
cb73ee40b   Lorenzo Bianconi   net: ip_gre: use ...
120
121
  		tpi->key = cpu_to_be32(get_session_id(ershdr));
  	}
f132ae7c4   Jiri Benc   gre: change gre_p...
122
  	return hdr_len;
95f5c64c3   Tom Herbert   gre: Move utility...
123
124
  }
  EXPORT_SYMBOL(gre_parse_header);
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  static int gre_rcv(struct sk_buff *skb)
  {
  	const struct gre_protocol *proto;
  	u8 ver;
  	int ret;
  
  	if (!pskb_may_pull(skb, 12))
  		goto drop;
  
  	ver = skb->data[1]&0x7f;
  	if (ver >= GREPROTO_MAX)
  		goto drop;
  
  	rcu_read_lock();
  	proto = rcu_dereference(gre_proto[ver]);
  	if (!proto || !proto->handler)
  		goto drop_unlock;
  	ret = proto->handler(skb);
  	rcu_read_unlock();
  	return ret;
  
  drop_unlock:
  	rcu_read_unlock();
  drop:
  	kfree_skb(skb);
  	return NET_RX_DROP;
  }
32bbd8793   Stefano Brivio   net: Convert prot...
152
  static int gre_err(struct sk_buff *skb, u32 info)
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
153
154
  {
  	const struct gre_protocol *proto;
559fafb94   xeb@mail.ru   gre: fix improper...
155
156
  	const struct iphdr *iph = (const struct iphdr *)skb->data;
  	u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
32bbd8793   Stefano Brivio   net: Convert prot...
157
  	int err = 0;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
158

00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
159
  	if (ver >= GREPROTO_MAX)
32bbd8793   Stefano Brivio   net: Convert prot...
160
  		return -EINVAL;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
161
162
163
  
  	rcu_read_lock();
  	proto = rcu_dereference(gre_proto[ver]);
559fafb94   xeb@mail.ru   gre: fix improper...
164
165
  	if (proto && proto->err_handler)
  		proto->err_handler(skb, info);
32bbd8793   Stefano Brivio   net: Convert prot...
166
167
  	else
  		err = -EPROTONOSUPPORT;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
168
  	rcu_read_unlock();
32bbd8793   Stefano Brivio   net: Convert prot...
169
170
  
  	return err;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
171
172
173
174
175
176
177
178
179
180
  }
  
  static const struct net_protocol net_gre_protocol = {
  	.handler     = gre_rcv,
  	.err_handler = gre_err,
  	.netns_ok    = 1,
  };
  
  static int __init gre_init(void)
  {
afd465030   Joe Perches   net: ipv4: Standa...
181
182
  	pr_info("GRE over IPv4 demultiplexor driver
  ");
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
183
184
  
  	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
afd465030   Joe Perches   net: ipv4: Standa...
185
186
  		pr_err("can't add protocol
  ");
9f57c67c3   Pravin B Shelar   gre: Remove suppo...
187
  		return -EAGAIN;
bda7bb463   Pravin B Shelar   gre: Allow multip...
188
  	}
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	return 0;
  }
  
  static void __exit gre_exit(void)
  {
  	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
  }
  
  module_init(gre_init);
  module_exit(gre_exit);
  
  MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
  MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
  MODULE_LICENSE("GPL");