#include <linux/capability.h>
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
+#include <net/protocol.h>
#include <net/ipip.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
dev_put(dev);
}
-static int ipip_err(struct sk_buff *skb, u32 info)
+static void ipip_err(struct sk_buff *skb, u32 info)
{
#ifndef I_WISH_WORLD_WERE_PERFECT
int type = skb->h.icmph->type;
int code = skb->h.icmph->code;
struct ip_tunnel *t;
- int err;
switch (type) {
default:
case ICMP_PARAMETERPROB:
- return 0;
+ return;
case ICMP_DEST_UNREACH:
switch (code) {
case ICMP_SR_FAILED:
case ICMP_PORT_UNREACH:
/* Impossible event. */
- return 0;
+ return;
case ICMP_FRAG_NEEDED:
/* Soft state for pmtu is maintained by IP core. */
- return 0;
+ return;
default:
/* All others are translated to HOST_UNREACH.
rfc2003 contains "deep thoughts" about NET_UNREACH,
break;
case ICMP_TIME_EXCEEDED:
if (code != ICMP_EXC_TTL)
- return 0;
+ return;
break;
}
- err = -ENOENT;
-
read_lock(&ipip_lock);
t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
if (t == NULL || t->parms.iph.daddr == 0)
goto out;
-
- err = 0;
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
goto out;
t->err_time = jiffies;
out:
read_unlock(&ipip_lock);
- return err;
+ return;
#else
struct iphdr *iph = (struct iphdr*)dp;
int hlen = iph->ihl<<2;
struct rtable *rt;
if (len < hlen + sizeof(struct iphdr))
- return 0;
+ return;
eiph = (struct iphdr*)(dp + hlen);
switch (type) {
default:
- return 0;
+ return;
case ICMP_PARAMETERPROB:
if (skb->h.icmph->un.gateway < hlen)
- return 0;
+ return;
/* So... This guy found something strange INSIDE encapsulated
packet. Well, he is fool, but what can we do ?
case ICMP_SR_FAILED:
case ICMP_PORT_UNREACH:
/* Impossible event. */
- return 0;
+ return;
case ICMP_FRAG_NEEDED:
/* And it is the only really necessary thing :-) */
rel_info = ntohs(skb->h.icmph->un.frag.mtu);
if (rel_info < hlen+68)
- return 0;
+ return;
rel_info -= hlen;
/* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
if (rel_info > ntohs(eiph->tot_len))
- return 0;
+ return;
break;
default:
/* All others are translated to HOST_UNREACH.
break;
case ICMP_TIME_EXCEEDED:
if (code != ICMP_EXC_TTL)
- return 0;
+ return;
break;
}
/* Prepare fake skb to feed it to icmp_send */
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2 == NULL)
- return 0;
+ return;
dst_release(skb2->dst);
skb2->dst = NULL;
skb_pull(skb2, skb->data - (u8*)eiph);
fl.proto = IPPROTO_IPIP;
if (ip_route_output_key(&rt, &key)) {
kfree_skb(skb2);
- return 0;
+ return;
}
skb2->dev = rt->u.dst.dev;
rt->u.dst.dev->type != ARPHRD_TUNNEL) {
ip_rt_put(rt);
kfree_skb(skb2);
- return 0;
+ return;
}
} else {
ip_rt_put(rt);
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
skb2->dst->dev->type != ARPHRD_TUNNEL) {
kfree_skb(skb2);
- return 0;
+ return;
}
}
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
if (rel_info > dst_mtu(skb2->dst)) {
kfree_skb(skb2);
- return 0;
+ return;
}
skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
rel_info = htonl(rel_info);
icmp_send(skb2, rel_type, rel_code, rel_info);
kfree_skb(skb2);
- return 0;
+ return;
#endif
}
struct iphdr *iph;
struct ip_tunnel *tunnel;
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ goto out;
+
iph = skb->nh.iph;
read_lock(&ipip_lock);
skb->mac.raw = skb->nh.raw;
skb->nh.raw = skb->data;
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
skb->protocol = htons(ETH_P_IP);
skb->pkt_type = PACKET_HOST;
}
read_unlock(&ipip_lock);
+out:
return -1;
}
return 0;
}
+#ifdef CONFIG_INET_TUNNEL
static struct xfrm_tunnel ipip_handler = {
.handler = ipip_rcv,
.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 =
KERN_INFO "IPv4 over IPv4 tunneling driver\n";
printk(banner);
- if (xfrm4_tunnel_register(&ipip_handler)) {
+ if (ipip_register() < 0) {
printk(KERN_INFO "ipip init: can't register tunnel\n");
return -EAGAIN;
}
err2:
free_netdev(ipip_fb_tunnel_dev);
err1:
- xfrm4_tunnel_deregister(&ipip_handler);
+ ipip_unregister();
goto out;
}
static void __exit ipip_fini(void)
{
- if (xfrm4_tunnel_deregister(&ipip_handler))
+ if (ipip_unregister() < 0)
printk(KERN_INFO "ipip close: can't deregister tunnel\n");
rtnl_lock();