blob: 1cbc46536d1fda02bf8bf3737faa0c4534875345 [file] [log] [blame]
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001/*
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
Joe Perchesafd465032012-03-12 07:03:32 +000013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070015#include <linux/module.h>
Pravin B Shelarbda7bb42013-06-17 17:49:38 -070016#include <linux/if.h>
17#include <linux/icmp.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070018#include <linux/kernel.h>
19#include <linux/kmod.h>
20#include <linux/skbuff.h>
21#include <linux/in.h>
xeb@mail.ru559fafb2011-07-22 20:49:40 +000022#include <linux/ip.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070023#include <linux/netdevice.h>
Pravin B Shelar68c33162013-02-14 14:02:41 +000024#include <linux/if_tunnel.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070025#include <linux/spinlock.h>
26#include <net/protocol.h>
27#include <net/gre.h>
28
Pravin B Shelarbda7bb42013-06-17 17:49:38 -070029#include <net/icmp.h>
30#include <net/route.h>
31#include <net/xfrm.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070032
Eric Dumazet6f0bcf12010-10-24 21:33:16 +000033static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
Pravin B Shelarbda7bb42013-06-17 17:49:38 -070034static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX];
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070035
36int gre_add_protocol(const struct gre_protocol *proto, u8 version)
37{
38 if (version >= GREPROTO_MAX)
Pravin B Shelar20fd4d12013-06-17 17:49:32 -070039 return -EINVAL;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070040
Pravin B Shelar20fd4d12013-06-17 17:49:32 -070041 return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
42 0 : -EBUSY;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070043}
44EXPORT_SYMBOL_GPL(gre_add_protocol);
45
46int gre_del_protocol(const struct gre_protocol *proto, u8 version)
47{
Pravin B Shelar20fd4d12013-06-17 17:49:32 -070048 int ret;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070049
Pravin B Shelar20fd4d12013-06-17 17:49:32 -070050 if (version >= GREPROTO_MAX)
51 return -EINVAL;
52
53 ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
54 0 : -EBUSY;
55
56 if (ret)
57 return ret;
58
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070059 synchronize_rcu();
60 return 0;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070061}
62EXPORT_SYMBOL_GPL(gre_del_protocol);
63
Pravin B Shelar752f36d2013-06-17 17:49:45 -070064void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
65 int hdr_len)
66{
67 struct gre_base_hdr *greh;
68
69 skb_push(skb, hdr_len);
70
71 greh = (struct gre_base_hdr *)skb->data;
72 greh->flags = tnl_flags_to_gre_flags(tpi->flags);
73 greh->protocol = tpi->proto;
74
75 if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
76 __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
77
78 if (tpi->flags&TUNNEL_SEQ) {
79 *ptr = tpi->seq;
80 ptr--;
81 }
82 if (tpi->flags&TUNNEL_KEY) {
83 *ptr = tpi->key;
84 ptr--;
85 }
86 if (tpi->flags&TUNNEL_CSUM &&
87 !(skb_shinfo(skb)->gso_type & SKB_GSO_GRE)) {
88 *ptr = 0;
89 *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
90 skb->len, 0));
91 }
92 }
93}
94EXPORT_SYMBOL_GPL(gre_build_header);
95
Pravin B Shelarbda7bb42013-06-17 17:49:38 -070096static __sum16 check_checksum(struct sk_buff *skb)
97{
98 __sum16 csum = 0;
99
100 switch (skb->ip_summed) {
101 case CHECKSUM_COMPLETE:
102 csum = csum_fold(skb->csum);
103
104 if (!csum)
105 break;
106 /* Fall through. */
107
108 case CHECKSUM_NONE:
109 skb->csum = 0;
110 csum = __skb_checksum_complete(skb);
111 skb->ip_summed = CHECKSUM_COMPLETE;
112 break;
113 }
114
115 return csum;
116}
117
118static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
119 bool *csum_err)
120{
121 unsigned int ip_hlen = ip_hdrlen(skb);
122 const struct gre_base_hdr *greh;
123 __be32 *options;
124 int hdr_len;
125
126 if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
127 return -EINVAL;
128
129 greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
130 if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
131 return -EINVAL;
132
133 tpi->flags = gre_flags_to_tnl_flags(greh->flags);
134 hdr_len = ip_gre_calc_hlen(tpi->flags);
135
136 if (!pskb_may_pull(skb, hdr_len))
137 return -EINVAL;
138
139 greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
140 tpi->proto = greh->protocol;
141
142 options = (__be32 *)(greh + 1);
143 if (greh->flags & GRE_CSUM) {
144 if (check_checksum(skb)) {
145 *csum_err = true;
146 return -EINVAL;
147 }
148 options++;
149 }
150
151 if (greh->flags & GRE_KEY) {
152 tpi->key = *options;
153 options++;
154 } else
155 tpi->key = 0;
156
157 if (unlikely(greh->flags & GRE_SEQ)) {
158 tpi->seq = *options;
159 options++;
160 } else
161 tpi->seq = 0;
162
163 /* WCCP version 1 and 2 protocol decoding.
164 * - Change protocol to IP
165 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
166 */
167 if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
168 tpi->proto = htons(ETH_P_IP);
169 if ((*(u8 *)options & 0xF0) != 0x40) {
170 hdr_len += 4;
171 if (!pskb_may_pull(skb, hdr_len))
172 return -EINVAL;
173 }
174 }
175 return 0;
176}
177
178static int gre_cisco_rcv(struct sk_buff *skb)
179{
180 struct tnl_ptk_info tpi;
181 int i;
182 bool csum_err = false;
183
184 if (parse_gre_header(skb, &tpi, &csum_err) < 0)
185 goto drop;
186
187 rcu_read_lock();
188 for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
189 struct gre_cisco_protocol *proto;
190 int ret;
191
192 proto = rcu_dereference(gre_cisco_proto_list[i]);
193 if (!proto)
194 continue;
195 ret = proto->handler(skb, &tpi);
196 if (ret == PACKET_RCVD) {
197 rcu_read_unlock();
198 return 0;
199 }
200 }
201 rcu_read_unlock();
202
203 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
204drop:
205 kfree_skb(skb);
206 return 0;
207}
208
209static void gre_cisco_err(struct sk_buff *skb, u32 info)
210{
211 /* All the routers (except for Linux) return only
212 * 8 bytes of packet payload. It means, that precise relaying of
213 * ICMP in the real Internet is absolutely infeasible.
214 *
215 * Moreover, Cisco "wise men" put GRE key to the third word
216 * in GRE header. It makes impossible maintaining even soft
217 * state for keyed
218 * GRE tunnels with enabled checksum. Tell them "thank you".
219 *
220 * Well, I wonder, rfc1812 was written by Cisco employee,
221 * what the hell these idiots break standards established
222 * by themselves???
223 */
224
225 const int type = icmp_hdr(skb)->type;
226 const int code = icmp_hdr(skb)->code;
227 struct tnl_ptk_info tpi;
228 bool csum_err = false;
229 int i;
230
231 if (parse_gre_header(skb, &tpi, &csum_err)) {
232 if (!csum_err) /* ignore csum errors. */
233 return;
234 }
235
236 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
237 ipv4_update_pmtu(skb, dev_net(skb->dev), info,
238 skb->dev->ifindex, 0, IPPROTO_GRE, 0);
239 return;
240 }
241 if (type == ICMP_REDIRECT) {
242 ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
243 IPPROTO_GRE, 0);
244 return;
245 }
246
247 rcu_read_lock();
248 for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
249 struct gre_cisco_protocol *proto;
250
251 proto = rcu_dereference(gre_cisco_proto_list[i]);
252 if (!proto)
253 continue;
254
255 if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD)
256 goto out;
257
258 }
259out:
260 rcu_read_unlock();
261}
262
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700263static int gre_rcv(struct sk_buff *skb)
264{
265 const struct gre_protocol *proto;
266 u8 ver;
267 int ret;
268
269 if (!pskb_may_pull(skb, 12))
270 goto drop;
271
272 ver = skb->data[1]&0x7f;
273 if (ver >= GREPROTO_MAX)
274 goto drop;
275
276 rcu_read_lock();
277 proto = rcu_dereference(gre_proto[ver]);
278 if (!proto || !proto->handler)
279 goto drop_unlock;
280 ret = proto->handler(skb);
281 rcu_read_unlock();
282 return ret;
283
284drop_unlock:
285 rcu_read_unlock();
286drop:
287 kfree_skb(skb);
288 return NET_RX_DROP;
289}
290
291static void gre_err(struct sk_buff *skb, u32 info)
292{
293 const struct gre_protocol *proto;
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000294 const struct iphdr *iph = (const struct iphdr *)skb->data;
295 u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700296
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700297 if (ver >= GREPROTO_MAX)
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000298 return;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700299
300 rcu_read_lock();
301 proto = rcu_dereference(gre_proto[ver]);
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000302 if (proto && proto->err_handler)
303 proto->err_handler(skb, info);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700304 rcu_read_unlock();
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700305}
306
Pravin B Shelar68c33162013-02-14 14:02:41 +0000307static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
308 netdev_features_t features)
309{
310 struct sk_buff *segs = ERR_PTR(-EINVAL);
311 netdev_features_t enc_features;
312 int ghl = GRE_HEADER_SECTION;
313 struct gre_base_hdr *greh;
314 int mac_len = skb->mac_len;
Pravin B Shelar9b3eb5e2013-05-02 16:14:19 +0000315 __be16 protocol = skb->protocol;
Pravin B Shelar9cb690d2013-03-24 17:36:16 +0000316 int tnl_hlen;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000317 bool csum;
318
319 if (unlikely(skb_shinfo(skb)->gso_type &
320 ~(SKB_GSO_TCPV4 |
321 SKB_GSO_TCPV6 |
322 SKB_GSO_UDP |
323 SKB_GSO_DODGY |
324 SKB_GSO_TCP_ECN |
325 SKB_GSO_GRE)))
326 goto out;
327
328 if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
329 goto out;
330
331 greh = (struct gre_base_hdr *)skb_transport_header(skb);
332
333 if (greh->flags & GRE_KEY)
334 ghl += GRE_HEADER_SECTION;
335 if (greh->flags & GRE_SEQ)
336 ghl += GRE_HEADER_SECTION;
337 if (greh->flags & GRE_CSUM) {
338 ghl += GRE_HEADER_SECTION;
339 csum = true;
340 } else
341 csum = false;
342
343 /* setup inner skb. */
Pravin B Shelar19acc322013-05-07 20:41:07 +0000344 skb->protocol = greh->protocol;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000345 skb->encapsulation = 0;
346
347 if (unlikely(!pskb_may_pull(skb, ghl)))
348 goto out;
349 __skb_pull(skb, ghl);
350 skb_reset_mac_header(skb);
351 skb_set_network_header(skb, skb_inner_network_offset(skb));
352 skb->mac_len = skb_inner_network_offset(skb);
353
354 /* segment inner packet. */
355 enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
356 segs = skb_mac_gso_segment(skb, enc_features);
357 if (!segs || IS_ERR(segs))
358 goto out;
359
360 skb = segs;
361 tnl_hlen = skb_tnl_header_len(skb);
362 do {
363 __skb_push(skb, ghl);
364 if (csum) {
365 __be32 *pcsum;
366
367 if (skb_has_shared_frag(skb)) {
368 int err;
369
370 err = __skb_linearize(skb);
371 if (err) {
372 kfree_skb(segs);
373 segs = ERR_PTR(err);
374 goto out;
375 }
376 }
377
378 greh = (struct gre_base_hdr *)(skb->data);
379 pcsum = (__be32 *)(greh + 1);
380 *pcsum = 0;
381 *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
382 }
383 __skb_push(skb, tnl_hlen - ghl);
384
385 skb_reset_mac_header(skb);
386 skb_set_network_header(skb, mac_len);
387 skb->mac_len = mac_len;
Pravin B Shelar9b3eb5e2013-05-02 16:14:19 +0000388 skb->protocol = protocol;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000389 } while ((skb = skb->next));
390out:
391 return segs;
392}
393
394static int gre_gso_send_check(struct sk_buff *skb)
395{
396 if (!skb->encapsulation)
397 return -EINVAL;
398 return 0;
399}
400
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700401static const struct net_protocol net_gre_protocol = {
402 .handler = gre_rcv,
403 .err_handler = gre_err,
404 .netns_ok = 1,
405};
406
Pravin B Shelar68c33162013-02-14 14:02:41 +0000407static const struct net_offload gre_offload = {
408 .callbacks = {
409 .gso_send_check = gre_gso_send_check,
410 .gso_segment = gre_gso_segment,
411 },
412};
413
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700414static const struct gre_protocol ipgre_protocol = {
415 .handler = gre_cisco_rcv,
416 .err_handler = gre_cisco_err,
417};
418
419int gre_cisco_register(struct gre_cisco_protocol *newp)
420{
421 struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
422 &gre_cisco_proto_list[newp->priority];
423
424 return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY;
425}
426EXPORT_SYMBOL_GPL(gre_cisco_register);
427
428int gre_cisco_unregister(struct gre_cisco_protocol *del_proto)
429{
430 struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
431 &gre_cisco_proto_list[del_proto->priority];
432 int ret;
433
434 ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL;
435
436 if (ret)
437 return ret;
438
439 synchronize_net();
440 return 0;
441}
442EXPORT_SYMBOL_GPL(gre_cisco_unregister);
443
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700444static int __init gre_init(void)
445{
Joe Perchesafd465032012-03-12 07:03:32 +0000446 pr_info("GRE over IPv4 demultiplexor driver\n");
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700447
448 if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
Joe Perchesafd465032012-03-12 07:03:32 +0000449 pr_err("can't add protocol\n");
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700450 goto err;
451 }
452
453 if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) {
454 pr_info("%s: can't add ipgre handler\n", __func__);
455 goto err_gre;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700456 }
457
Pravin B Shelar68c33162013-02-14 14:02:41 +0000458 if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
459 pr_err("can't add protocol offload\n");
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700460 goto err_gso;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000461 }
462
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700463 return 0;
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700464err_gso:
465 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
466err_gre:
467 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
468err:
469 return -EAGAIN;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700470}
471
472static void __exit gre_exit(void)
473{
Pravin B Shelar68c33162013-02-14 14:02:41 +0000474 inet_del_offload(&gre_offload, IPPROTO_GRE);
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700475 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700476 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
477}
478
479module_init(gre_init);
480module_exit(gre_exit);
481
482MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
483MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
484MODULE_LICENSE("GPL");