|
@@ -114,7 +114,6 @@
|
|
#include <net/sock.h>
|
|
#include <net/sock.h>
|
|
#include <net/ip.h>
|
|
#include <net/ip.h>
|
|
#include <net/icmp.h>
|
|
#include <net/icmp.h>
|
|
-#include <net/protocol.h>
|
|
|
|
#include <net/ipip.h>
|
|
#include <net/ipip.h>
|
|
#include <net/inet_ecn.h>
|
|
#include <net/inet_ecn.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/xfrm.h>
|
|
@@ -274,7 +273,7 @@ static void ipip_tunnel_uninit(struct net_device *dev)
|
|
dev_put(dev);
|
|
dev_put(dev);
|
|
}
|
|
}
|
|
|
|
|
|
-static void ipip_err(struct sk_buff *skb, u32 info)
|
|
|
|
|
|
+static int ipip_err(struct sk_buff *skb, u32 info)
|
|
{
|
|
{
|
|
#ifndef I_WISH_WORLD_WERE_PERFECT
|
|
#ifndef I_WISH_WORLD_WERE_PERFECT
|
|
|
|
|
|
@@ -286,21 +285,22 @@ static void ipip_err(struct sk_buff *skb, u32 info)
|
|
int type = skb->h.icmph->type;
|
|
int type = skb->h.icmph->type;
|
|
int code = skb->h.icmph->code;
|
|
int code = skb->h.icmph->code;
|
|
struct ip_tunnel *t;
|
|
struct ip_tunnel *t;
|
|
|
|
+ int err;
|
|
|
|
|
|
switch (type) {
|
|
switch (type) {
|
|
default:
|
|
default:
|
|
case ICMP_PARAMETERPROB:
|
|
case ICMP_PARAMETERPROB:
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
case ICMP_DEST_UNREACH:
|
|
case ICMP_DEST_UNREACH:
|
|
switch (code) {
|
|
switch (code) {
|
|
case ICMP_SR_FAILED:
|
|
case ICMP_SR_FAILED:
|
|
case ICMP_PORT_UNREACH:
|
|
case ICMP_PORT_UNREACH:
|
|
/* Impossible event. */
|
|
/* Impossible event. */
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
case ICMP_FRAG_NEEDED:
|
|
case ICMP_FRAG_NEEDED:
|
|
/* Soft state for pmtu is maintained by IP core. */
|
|
/* Soft state for pmtu is maintained by IP core. */
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
default:
|
|
default:
|
|
/* All others are translated to HOST_UNREACH.
|
|
/* All others are translated to HOST_UNREACH.
|
|
rfc2003 contains "deep thoughts" about NET_UNREACH,
|
|
rfc2003 contains "deep thoughts" about NET_UNREACH,
|
|
@@ -311,14 +311,18 @@ static void ipip_err(struct sk_buff *skb, u32 info)
|
|
break;
|
|
break;
|
|
case ICMP_TIME_EXCEEDED:
|
|
case ICMP_TIME_EXCEEDED:
|
|
if (code != ICMP_EXC_TTL)
|
|
if (code != ICMP_EXC_TTL)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ err = -ENOENT;
|
|
|
|
+
|
|
read_lock(&ipip_lock);
|
|
read_lock(&ipip_lock);
|
|
t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
|
|
t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
|
|
if (t == NULL || t->parms.iph.daddr == 0)
|
|
if (t == NULL || t->parms.iph.daddr == 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
+
|
|
|
|
+ err = 0;
|
|
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
|
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -329,7 +333,7 @@ static void ipip_err(struct sk_buff *skb, u32 info)
|
|
t->err_time = jiffies;
|
|
t->err_time = jiffies;
|
|
out:
|
|
out:
|
|
read_unlock(&ipip_lock);
|
|
read_unlock(&ipip_lock);
|
|
- return;
|
|
|
|
|
|
+ return err;
|
|
#else
|
|
#else
|
|
struct iphdr *iph = (struct iphdr*)dp;
|
|
struct iphdr *iph = (struct iphdr*)dp;
|
|
int hlen = iph->ihl<<2;
|
|
int hlen = iph->ihl<<2;
|
|
@@ -344,15 +348,15 @@ out:
|
|
struct rtable *rt;
|
|
struct rtable *rt;
|
|
|
|
|
|
if (len < hlen + sizeof(struct iphdr))
|
|
if (len < hlen + sizeof(struct iphdr))
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
eiph = (struct iphdr*)(dp + hlen);
|
|
eiph = (struct iphdr*)(dp + hlen);
|
|
|
|
|
|
switch (type) {
|
|
switch (type) {
|
|
default:
|
|
default:
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
case ICMP_PARAMETERPROB:
|
|
case ICMP_PARAMETERPROB:
|
|
if (skb->h.icmph->un.gateway < hlen)
|
|
if (skb->h.icmph->un.gateway < hlen)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
/* So... This guy found something strange INSIDE encapsulated
|
|
/* So... This guy found something strange INSIDE encapsulated
|
|
packet. Well, he is fool, but what can we do ?
|
|
packet. Well, he is fool, but what can we do ?
|
|
@@ -366,16 +370,16 @@ out:
|
|
case ICMP_SR_FAILED:
|
|
case ICMP_SR_FAILED:
|
|
case ICMP_PORT_UNREACH:
|
|
case ICMP_PORT_UNREACH:
|
|
/* Impossible event. */
|
|
/* Impossible event. */
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
case ICMP_FRAG_NEEDED:
|
|
case ICMP_FRAG_NEEDED:
|
|
/* And it is the only really necessary thing :-) */
|
|
/* And it is the only really necessary thing :-) */
|
|
rel_info = ntohs(skb->h.icmph->un.frag.mtu);
|
|
rel_info = ntohs(skb->h.icmph->un.frag.mtu);
|
|
if (rel_info < hlen+68)
|
|
if (rel_info < hlen+68)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
rel_info -= hlen;
|
|
rel_info -= hlen;
|
|
/* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
|
|
/* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
|
|
if (rel_info > ntohs(eiph->tot_len))
|
|
if (rel_info > ntohs(eiph->tot_len))
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
/* All others are translated to HOST_UNREACH.
|
|
/* All others are translated to HOST_UNREACH.
|
|
@@ -389,14 +393,14 @@ out:
|
|
break;
|
|
break;
|
|
case ICMP_TIME_EXCEEDED:
|
|
case ICMP_TIME_EXCEEDED:
|
|
if (code != ICMP_EXC_TTL)
|
|
if (code != ICMP_EXC_TTL)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Prepare fake skb to feed it to icmp_send */
|
|
/* Prepare fake skb to feed it to icmp_send */
|
|
skb2 = skb_clone(skb, GFP_ATOMIC);
|
|
skb2 = skb_clone(skb, GFP_ATOMIC);
|
|
if (skb2 == NULL)
|
|
if (skb2 == NULL)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
dst_release(skb2->dst);
|
|
dst_release(skb2->dst);
|
|
skb2->dst = NULL;
|
|
skb2->dst = NULL;
|
|
skb_pull(skb2, skb->data - (u8*)eiph);
|
|
skb_pull(skb2, skb->data - (u8*)eiph);
|
|
@@ -409,7 +413,7 @@ out:
|
|
fl.proto = IPPROTO_IPIP;
|
|
fl.proto = IPPROTO_IPIP;
|
|
if (ip_route_output_key(&rt, &key)) {
|
|
if (ip_route_output_key(&rt, &key)) {
|
|
kfree_skb(skb2);
|
|
kfree_skb(skb2);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
skb2->dev = rt->u.dst.dev;
|
|
skb2->dev = rt->u.dst.dev;
|
|
|
|
|
|
@@ -424,14 +428,14 @@ out:
|
|
rt->u.dst.dev->type != ARPHRD_TUNNEL) {
|
|
rt->u.dst.dev->type != ARPHRD_TUNNEL) {
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
kfree_skb(skb2);
|
|
kfree_skb(skb2);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
ip_rt_put(rt);
|
|
ip_rt_put(rt);
|
|
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
|
|
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
|
|
skb2->dst->dev->type != ARPHRD_TUNNEL) {
|
|
skb2->dst->dev->type != ARPHRD_TUNNEL) {
|
|
kfree_skb(skb2);
|
|
kfree_skb(skb2);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -439,7 +443,7 @@ out:
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
if (rel_info > dst_mtu(skb2->dst)) {
|
|
if (rel_info > dst_mtu(skb2->dst)) {
|
|
kfree_skb(skb2);
|
|
kfree_skb(skb2);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
|
|
skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
|
|
rel_info = htonl(rel_info);
|
|
rel_info = htonl(rel_info);
|
|
@@ -453,7 +457,7 @@ out:
|
|
|
|
|
|
icmp_send(skb2, rel_type, rel_code, rel_info);
|
|
icmp_send(skb2, rel_type, rel_code, rel_info);
|
|
kfree_skb(skb2);
|
|
kfree_skb(skb2);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
@@ -855,39 +859,12 @@ static int __init ipip_fb_tunnel_init(struct net_device *dev)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_INET_TUNNEL
|
|
|
|
static struct xfrm_tunnel ipip_handler = {
|
|
static struct xfrm_tunnel ipip_handler = {
|
|
.handler = ipip_rcv,
|
|
.handler = ipip_rcv,
|
|
.err_handler = ipip_err,
|
|
.err_handler = ipip_err,
|
|
|
|
+ .priority = 1,
|
|
};
|
|
};
|
|
|
|
|
|
-static inline int ipip_register(void)
|
|
|
|
-{
|
|
|
|
- return xfrm4_tunnel_register(&ipip_handler);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline int ipip_unregister(void)
|
|
|
|
-{
|
|
|
|
- return xfrm4_tunnel_deregister(&ipip_handler);
|
|
|
|
-}
|
|
|
|
-#else
|
|
|
|
-static struct net_protocol ipip_protocol = {
|
|
|
|
- .handler = ipip_rcv,
|
|
|
|
- .err_handler = ipip_err,
|
|
|
|
- .no_policy = 1,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static inline int ipip_register(void)
|
|
|
|
-{
|
|
|
|
- return inet_add_protocol(&ipip_protocol, IPPROTO_IPIP);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline int ipip_unregister(void)
|
|
|
|
-{
|
|
|
|
- return inet_del_protocol(&ipip_protocol, IPPROTO_IPIP);
|
|
|
|
-}
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
static char banner[] __initdata =
|
|
static char banner[] __initdata =
|
|
KERN_INFO "IPv4 over IPv4 tunneling driver\n";
|
|
KERN_INFO "IPv4 over IPv4 tunneling driver\n";
|
|
|
|
|
|
@@ -897,7 +874,7 @@ static int __init ipip_init(void)
|
|
|
|
|
|
printk(banner);
|
|
printk(banner);
|
|
|
|
|
|
- if (ipip_register() < 0) {
|
|
|
|
|
|
+ if (xfrm4_tunnel_register(&ipip_handler)) {
|
|
printk(KERN_INFO "ipip init: can't register tunnel\n");
|
|
printk(KERN_INFO "ipip init: can't register tunnel\n");
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
}
|
|
}
|
|
@@ -919,7 +896,7 @@ static int __init ipip_init(void)
|
|
err2:
|
|
err2:
|
|
free_netdev(ipip_fb_tunnel_dev);
|
|
free_netdev(ipip_fb_tunnel_dev);
|
|
err1:
|
|
err1:
|
|
- ipip_unregister();
|
|
|
|
|
|
+ xfrm4_tunnel_deregister(&ipip_handler);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -939,7 +916,7 @@ static void __exit ipip_destroy_tunnels(void)
|
|
|
|
|
|
static void __exit ipip_fini(void)
|
|
static void __exit ipip_fini(void)
|
|
{
|
|
{
|
|
- if (ipip_unregister() < 0)
|
|
|
|
|
|
+ if (xfrm4_tunnel_deregister(&ipip_handler))
|
|
printk(KERN_INFO "ipip close: can't deregister tunnel\n");
|
|
printk(KERN_INFO "ipip close: can't deregister tunnel\n");
|
|
|
|
|
|
rtnl_lock();
|
|
rtnl_lock();
|