• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *	GRE over IPv4 demultiplexer driver
3  *
4  *	Authors: Dmitry Kozlov (xeb@mail.ru)
5  *
6  *	This program is free software; you can redistribute it and/or
7  *	modify it under the terms of the GNU General Public License
8  *	as published by the Free Software Foundation; either version
9  *	2 of the License, or (at your option) any later version.
10  *
11  */
12 
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/kmod.h>
18 #include <linux/skbuff.h>
19 #include <linux/in.h>
20 #include <linux/ip.h>
21 #include <linux/netdevice.h>
22 #include <linux/if_tunnel.h>
23 #include <linux/spinlock.h>
24 #include <net/protocol.h>
25 #include <net/gre.h>
26 
27 
28 static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
29 static DEFINE_SPINLOCK(gre_proto_lock);
30 
gre_add_protocol(const struct gre_protocol * proto,u8 version)31 int gre_add_protocol(const struct gre_protocol *proto, u8 version)
32 {
33 	if (version >= GREPROTO_MAX)
34 		goto err_out;
35 
36 	spin_lock(&gre_proto_lock);
37 	if (gre_proto[version])
38 		goto err_out_unlock;
39 
40 	RCU_INIT_POINTER(gre_proto[version], proto);
41 	spin_unlock(&gre_proto_lock);
42 	return 0;
43 
44 err_out_unlock:
45 	spin_unlock(&gre_proto_lock);
46 err_out:
47 	return -1;
48 }
49 EXPORT_SYMBOL_GPL(gre_add_protocol);
50 
gre_del_protocol(const struct gre_protocol * proto,u8 version)51 int gre_del_protocol(const struct gre_protocol *proto, u8 version)
52 {
53 	if (version >= GREPROTO_MAX)
54 		goto err_out;
55 
56 	spin_lock(&gre_proto_lock);
57 	if (rcu_dereference_protected(gre_proto[version],
58 			lockdep_is_held(&gre_proto_lock)) != proto)
59 		goto err_out_unlock;
60 	RCU_INIT_POINTER(gre_proto[version], NULL);
61 	spin_unlock(&gre_proto_lock);
62 	synchronize_rcu();
63 	return 0;
64 
65 err_out_unlock:
66 	spin_unlock(&gre_proto_lock);
67 err_out:
68 	return -1;
69 }
70 EXPORT_SYMBOL_GPL(gre_del_protocol);
71 
gre_rcv(struct sk_buff * skb)72 static int gre_rcv(struct sk_buff *skb)
73 {
74 	const struct gre_protocol *proto;
75 	u8 ver;
76 	int ret;
77 
78 	if (!pskb_may_pull(skb, 12))
79 		goto drop;
80 
81 	ver = skb->data[1]&0x7f;
82 	if (ver >= GREPROTO_MAX)
83 		goto drop;
84 
85 	rcu_read_lock();
86 	proto = rcu_dereference(gre_proto[ver]);
87 	if (!proto || !proto->handler)
88 		goto drop_unlock;
89 	ret = proto->handler(skb);
90 	rcu_read_unlock();
91 	return ret;
92 
93 drop_unlock:
94 	rcu_read_unlock();
95 drop:
96 	kfree_skb(skb);
97 	return NET_RX_DROP;
98 }
99 
gre_err(struct sk_buff * skb,u32 info)100 static void gre_err(struct sk_buff *skb, u32 info)
101 {
102 	const struct gre_protocol *proto;
103 	const struct iphdr *iph = (const struct iphdr *)skb->data;
104 	u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
105 
106 	if (ver >= GREPROTO_MAX)
107 		return;
108 
109 	rcu_read_lock();
110 	proto = rcu_dereference(gre_proto[ver]);
111 	if (proto && proto->err_handler)
112 		proto->err_handler(skb, info);
113 	rcu_read_unlock();
114 }
115 
gre_gso_segment(struct sk_buff * skb,netdev_features_t features)116 static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
117 				       netdev_features_t features)
118 {
119 	struct sk_buff *segs = ERR_PTR(-EINVAL);
120 	netdev_features_t enc_features;
121 	int ghl = GRE_HEADER_SECTION;
122 	struct gre_base_hdr *greh;
123 	int mac_len = skb->mac_len;
124 	__be16 protocol = skb->protocol;
125 	int tnl_hlen;
126 	bool csum;
127 
128 	if (unlikely(skb_shinfo(skb)->gso_type &
129 				~(SKB_GSO_TCPV4 |
130 				  SKB_GSO_TCPV6 |
131 				  SKB_GSO_UDP |
132 				  SKB_GSO_DODGY |
133 				  SKB_GSO_TCP_ECN |
134 				  SKB_GSO_GRE)))
135 		goto out;
136 
137 	if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
138 		goto out;
139 
140 	greh = (struct gre_base_hdr *)skb_transport_header(skb);
141 
142 	if (greh->flags & GRE_KEY)
143 		ghl += GRE_HEADER_SECTION;
144 	if (greh->flags & GRE_SEQ)
145 		ghl += GRE_HEADER_SECTION;
146 	if (greh->flags & GRE_CSUM) {
147 		ghl += GRE_HEADER_SECTION;
148 		csum = true;
149 	} else
150 		csum = false;
151 
152 	/* setup inner skb. */
153 	skb->protocol = greh->protocol;
154 	skb->encapsulation = 0;
155 
156 	if (unlikely(!pskb_may_pull(skb, ghl)))
157 		goto out;
158 	__skb_pull(skb, ghl);
159 	skb_reset_mac_header(skb);
160 	skb_set_network_header(skb, skb_inner_network_offset(skb));
161 	skb->mac_len = skb_inner_network_offset(skb);
162 
163 	/* segment inner packet. */
164 	enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
165 	segs = skb_mac_gso_segment(skb, enc_features);
166 	if (!segs || IS_ERR(segs))
167 		goto out;
168 
169 	skb = segs;
170 	tnl_hlen = skb_tnl_header_len(skb);
171 	do {
172 		__skb_push(skb, ghl);
173 		if (csum) {
174 			__be32 *pcsum;
175 
176 			if (skb_has_shared_frag(skb)) {
177 				int err;
178 
179 				err = __skb_linearize(skb);
180 				if (err) {
181 					kfree_skb_list(segs);
182 					segs = ERR_PTR(err);
183 					goto out;
184 				}
185 			}
186 
187 			greh = (struct gre_base_hdr *)(skb->data);
188 			pcsum = (__be32 *)(greh + 1);
189 			*pcsum = 0;
190 			*(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
191 		}
192 		__skb_push(skb, tnl_hlen - ghl);
193 
194 		skb_reset_mac_header(skb);
195 		skb_set_network_header(skb, mac_len);
196 		skb->mac_len = mac_len;
197 		skb->protocol = protocol;
198 	} while ((skb = skb->next));
199 out:
200 	return segs;
201 }
202 
gre_gso_send_check(struct sk_buff * skb)203 static int gre_gso_send_check(struct sk_buff *skb)
204 {
205 	if (!skb->encapsulation)
206 		return -EINVAL;
207 	return 0;
208 }
209 
210 static const struct net_protocol net_gre_protocol = {
211 	.handler     = gre_rcv,
212 	.err_handler = gre_err,
213 	.netns_ok    = 1,
214 };
215 
216 static const struct net_offload gre_offload = {
217 	.callbacks = {
218 		.gso_send_check =	gre_gso_send_check,
219 		.gso_segment    =	gre_gso_segment,
220 	},
221 };
222 
gre_init(void)223 static int __init gre_init(void)
224 {
225 	pr_info("GRE over IPv4 demultiplexor driver\n");
226 
227 	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
228 		pr_err("can't add protocol\n");
229 		return -EAGAIN;
230 	}
231 
232 	if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
233 		pr_err("can't add protocol offload\n");
234 		inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
235 		return -EAGAIN;
236 	}
237 
238 	return 0;
239 }
240 
gre_exit(void)241 static void __exit gre_exit(void)
242 {
243 	inet_del_offload(&gre_offload, IPPROTO_GRE);
244 	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
245 }
246 
247 module_init(gre_init);
248 module_exit(gre_exit);
249 
250 MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
251 MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
252 MODULE_LICENSE("GPL");
253 
254