blob: 8b9a373890ab2eee38be5c4fd8b1c03c2de51dad [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 Shelarbda7bb42013-06-17 17:49:38 -070064static __sum16 check_checksum(struct sk_buff *skb)
65{
66 __sum16 csum = 0;
67
68 switch (skb->ip_summed) {
69 case CHECKSUM_COMPLETE:
70 csum = csum_fold(skb->csum);
71
72 if (!csum)
73 break;
74 /* Fall through. */
75
76 case CHECKSUM_NONE:
77 skb->csum = 0;
78 csum = __skb_checksum_complete(skb);
79 skb->ip_summed = CHECKSUM_COMPLETE;
80 break;
81 }
82
83 return csum;
84}
85
86static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
87 bool *csum_err)
88{
89 unsigned int ip_hlen = ip_hdrlen(skb);
90 const struct gre_base_hdr *greh;
91 __be32 *options;
92 int hdr_len;
93
94 if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
95 return -EINVAL;
96
97 greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
98 if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
99 return -EINVAL;
100
101 tpi->flags = gre_flags_to_tnl_flags(greh->flags);
102 hdr_len = ip_gre_calc_hlen(tpi->flags);
103
104 if (!pskb_may_pull(skb, hdr_len))
105 return -EINVAL;
106
107 greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
108 tpi->proto = greh->protocol;
109
110 options = (__be32 *)(greh + 1);
111 if (greh->flags & GRE_CSUM) {
112 if (check_checksum(skb)) {
113 *csum_err = true;
114 return -EINVAL;
115 }
116 options++;
117 }
118
119 if (greh->flags & GRE_KEY) {
120 tpi->key = *options;
121 options++;
122 } else
123 tpi->key = 0;
124
125 if (unlikely(greh->flags & GRE_SEQ)) {
126 tpi->seq = *options;
127 options++;
128 } else
129 tpi->seq = 0;
130
131 /* WCCP version 1 and 2 protocol decoding.
132 * - Change protocol to IP
133 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
134 */
135 if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
136 tpi->proto = htons(ETH_P_IP);
137 if ((*(u8 *)options & 0xF0) != 0x40) {
138 hdr_len += 4;
139 if (!pskb_may_pull(skb, hdr_len))
140 return -EINVAL;
141 }
142 }
143 return 0;
144}
145
146static int gre_cisco_rcv(struct sk_buff *skb)
147{
148 struct tnl_ptk_info tpi;
149 int i;
150 bool csum_err = false;
151
152 if (parse_gre_header(skb, &tpi, &csum_err) < 0)
153 goto drop;
154
155 rcu_read_lock();
156 for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
157 struct gre_cisco_protocol *proto;
158 int ret;
159
160 proto = rcu_dereference(gre_cisco_proto_list[i]);
161 if (!proto)
162 continue;
163 ret = proto->handler(skb, &tpi);
164 if (ret == PACKET_RCVD) {
165 rcu_read_unlock();
166 return 0;
167 }
168 }
169 rcu_read_unlock();
170
171 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
172drop:
173 kfree_skb(skb);
174 return 0;
175}
176
177static void gre_cisco_err(struct sk_buff *skb, u32 info)
178{
179 /* All the routers (except for Linux) return only
180 * 8 bytes of packet payload. It means, that precise relaying of
181 * ICMP in the real Internet is absolutely infeasible.
182 *
183 * Moreover, Cisco "wise men" put GRE key to the third word
184 * in GRE header. It makes impossible maintaining even soft
185 * state for keyed
186 * GRE tunnels with enabled checksum. Tell them "thank you".
187 *
188 * Well, I wonder, rfc1812 was written by Cisco employee,
189 * what the hell these idiots break standards established
190 * by themselves???
191 */
192
193 const int type = icmp_hdr(skb)->type;
194 const int code = icmp_hdr(skb)->code;
195 struct tnl_ptk_info tpi;
196 bool csum_err = false;
197 int i;
198
199 if (parse_gre_header(skb, &tpi, &csum_err)) {
200 if (!csum_err) /* ignore csum errors. */
201 return;
202 }
203
204 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
205 ipv4_update_pmtu(skb, dev_net(skb->dev), info,
206 skb->dev->ifindex, 0, IPPROTO_GRE, 0);
207 return;
208 }
209 if (type == ICMP_REDIRECT) {
210 ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
211 IPPROTO_GRE, 0);
212 return;
213 }
214
215 rcu_read_lock();
216 for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
217 struct gre_cisco_protocol *proto;
218
219 proto = rcu_dereference(gre_cisco_proto_list[i]);
220 if (!proto)
221 continue;
222
223 if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD)
224 goto out;
225
226 }
227out:
228 rcu_read_unlock();
229}
230
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700231static int gre_rcv(struct sk_buff *skb)
232{
233 const struct gre_protocol *proto;
234 u8 ver;
235 int ret;
236
237 if (!pskb_may_pull(skb, 12))
238 goto drop;
239
240 ver = skb->data[1]&0x7f;
241 if (ver >= GREPROTO_MAX)
242 goto drop;
243
244 rcu_read_lock();
245 proto = rcu_dereference(gre_proto[ver]);
246 if (!proto || !proto->handler)
247 goto drop_unlock;
248 ret = proto->handler(skb);
249 rcu_read_unlock();
250 return ret;
251
252drop_unlock:
253 rcu_read_unlock();
254drop:
255 kfree_skb(skb);
256 return NET_RX_DROP;
257}
258
259static void gre_err(struct sk_buff *skb, u32 info)
260{
261 const struct gre_protocol *proto;
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000262 const struct iphdr *iph = (const struct iphdr *)skb->data;
263 u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700264
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700265 if (ver >= GREPROTO_MAX)
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000266 return;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700267
268 rcu_read_lock();
269 proto = rcu_dereference(gre_proto[ver]);
xeb@mail.ru559fafb2011-07-22 20:49:40 +0000270 if (proto && proto->err_handler)
271 proto->err_handler(skb, info);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700272 rcu_read_unlock();
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700273}
274
Pravin B Shelar68c33162013-02-14 14:02:41 +0000275static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
276 netdev_features_t features)
277{
278 struct sk_buff *segs = ERR_PTR(-EINVAL);
279 netdev_features_t enc_features;
280 int ghl = GRE_HEADER_SECTION;
281 struct gre_base_hdr *greh;
282 int mac_len = skb->mac_len;
Pravin B Shelar9b3eb5e2013-05-02 16:14:19 +0000283 __be16 protocol = skb->protocol;
Pravin B Shelar9cb690d2013-03-24 17:36:16 +0000284 int tnl_hlen;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000285 bool csum;
286
287 if (unlikely(skb_shinfo(skb)->gso_type &
288 ~(SKB_GSO_TCPV4 |
289 SKB_GSO_TCPV6 |
290 SKB_GSO_UDP |
291 SKB_GSO_DODGY |
292 SKB_GSO_TCP_ECN |
293 SKB_GSO_GRE)))
294 goto out;
295
296 if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
297 goto out;
298
299 greh = (struct gre_base_hdr *)skb_transport_header(skb);
300
301 if (greh->flags & GRE_KEY)
302 ghl += GRE_HEADER_SECTION;
303 if (greh->flags & GRE_SEQ)
304 ghl += GRE_HEADER_SECTION;
305 if (greh->flags & GRE_CSUM) {
306 ghl += GRE_HEADER_SECTION;
307 csum = true;
308 } else
309 csum = false;
310
311 /* setup inner skb. */
Pravin B Shelar19acc322013-05-07 20:41:07 +0000312 skb->protocol = greh->protocol;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000313 skb->encapsulation = 0;
314
315 if (unlikely(!pskb_may_pull(skb, ghl)))
316 goto out;
317 __skb_pull(skb, ghl);
318 skb_reset_mac_header(skb);
319 skb_set_network_header(skb, skb_inner_network_offset(skb));
320 skb->mac_len = skb_inner_network_offset(skb);
321
322 /* segment inner packet. */
323 enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
324 segs = skb_mac_gso_segment(skb, enc_features);
325 if (!segs || IS_ERR(segs))
326 goto out;
327
328 skb = segs;
329 tnl_hlen = skb_tnl_header_len(skb);
330 do {
331 __skb_push(skb, ghl);
332 if (csum) {
333 __be32 *pcsum;
334
335 if (skb_has_shared_frag(skb)) {
336 int err;
337
338 err = __skb_linearize(skb);
339 if (err) {
340 kfree_skb(segs);
341 segs = ERR_PTR(err);
342 goto out;
343 }
344 }
345
346 greh = (struct gre_base_hdr *)(skb->data);
347 pcsum = (__be32 *)(greh + 1);
348 *pcsum = 0;
349 *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
350 }
351 __skb_push(skb, tnl_hlen - ghl);
352
353 skb_reset_mac_header(skb);
354 skb_set_network_header(skb, mac_len);
355 skb->mac_len = mac_len;
Pravin B Shelar9b3eb5e2013-05-02 16:14:19 +0000356 skb->protocol = protocol;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000357 } while ((skb = skb->next));
358out:
359 return segs;
360}
361
362static int gre_gso_send_check(struct sk_buff *skb)
363{
364 if (!skb->encapsulation)
365 return -EINVAL;
366 return 0;
367}
368
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700369static const struct net_protocol net_gre_protocol = {
370 .handler = gre_rcv,
371 .err_handler = gre_err,
372 .netns_ok = 1,
373};
374
Pravin B Shelar68c33162013-02-14 14:02:41 +0000375static const struct net_offload gre_offload = {
376 .callbacks = {
377 .gso_send_check = gre_gso_send_check,
378 .gso_segment = gre_gso_segment,
379 },
380};
381
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700382static const struct gre_protocol ipgre_protocol = {
383 .handler = gre_cisco_rcv,
384 .err_handler = gre_cisco_err,
385};
386
387int gre_cisco_register(struct gre_cisco_protocol *newp)
388{
389 struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
390 &gre_cisco_proto_list[newp->priority];
391
392 return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY;
393}
394EXPORT_SYMBOL_GPL(gre_cisco_register);
395
396int gre_cisco_unregister(struct gre_cisco_protocol *del_proto)
397{
398 struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
399 &gre_cisco_proto_list[del_proto->priority];
400 int ret;
401
402 ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL;
403
404 if (ret)
405 return ret;
406
407 synchronize_net();
408 return 0;
409}
410EXPORT_SYMBOL_GPL(gre_cisco_unregister);
411
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700412static int __init gre_init(void)
413{
Joe Perchesafd465032012-03-12 07:03:32 +0000414 pr_info("GRE over IPv4 demultiplexor driver\n");
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700415
416 if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
Joe Perchesafd465032012-03-12 07:03:32 +0000417 pr_err("can't add protocol\n");
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700418 goto err;
419 }
420
421 if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) {
422 pr_info("%s: can't add ipgre handler\n", __func__);
423 goto err_gre;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700424 }
425
Pravin B Shelar68c33162013-02-14 14:02:41 +0000426 if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
427 pr_err("can't add protocol offload\n");
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700428 goto err_gso;
Pravin B Shelar68c33162013-02-14 14:02:41 +0000429 }
430
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700431 return 0;
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700432err_gso:
433 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
434err_gre:
435 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
436err:
437 return -EAGAIN;
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700438}
439
440static void __exit gre_exit(void)
441{
Pravin B Shelar68c33162013-02-14 14:02:41 +0000442 inet_del_offload(&gre_offload, IPPROTO_GRE);
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700443 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -0700444 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
445}
446
447module_init(gre_init);
448module_exit(gre_exit);
449
450MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
451MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
452MODULE_LICENSE("GPL");