From d2acc3479cbccd5cfbca6c787be713ef1de12ec6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 28 Mar 2006 01:12:13 -0800 Subject: [INET]: Introduce tunnel4/tunnel6 Basically this patch moves the generic tunnel protocol stuff out of xfrm4_tunnel/xfrm6_tunnel and moves it into the new files of tunnel4.c and tunnel6 respectively. The reason for this is that the problem that Hugo uncovered is only the tip of the iceberg. The real problem is that when we removed the dependency of ipip on xfrm4_tunnel we didn't really consider the module case at all. For instance, as it is it's possible to build both ipip and xfrm4_tunnel as modules and if the latter is loaded then ipip simply won't load. After considering the alternatives I've decided that the best way out of this is to restore the dependency of ipip on the non-xfrm-specific part of xfrm4_tunnel. This is acceptable IMHO because the intention of the removal was really to be able to use ipip without the xfrm subsystem. This is still preserved by this patch. So now both ipip/xfrm4_tunnel depend on the new tunnel4.c which handles the arbitration between the two. The order of processing is determined by a simple integer which ensures that ipip gets processed before xfrm4_tunnel. The situation for ICMP handling is a little bit more complicated since we may not have enough information to determine who it's for. It's not a big deal at the moment since the xfrm ICMP handlers are basically no-ops. In future we can deal with this when we look at ICMP caching in general. The user-visible change to this is the removal of the TUNNEL Kconfig prompts. This makes sense because it can only be used through IPCOMP as it stands. The addition of the new modules shouldn't introduce any problems since module dependency will cause them to be loaded. Oh and I also turned some unnecessary pskb's in IPv6 related to this patch to skb's. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 79 ++++++++++++++++++++------------------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 03d1374..eef07b0 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -114,7 +114,6 @@ #include #include #include -#include #include #include #include @@ -274,7 +273,7 @@ static void ipip_tunnel_uninit(struct net_device *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 @@ -286,21 +285,22 @@ static void ipip_err(struct sk_buff *skb, u32 info) 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; + return 0; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; case ICMP_FRAG_NEEDED: /* Soft state for pmtu is maintained by IP core. */ - return; + return 0; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, @@ -311,14 +311,18 @@ static void ipip_err(struct sk_buff *skb, u32 info) break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; 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; @@ -329,7 +333,7 @@ static void ipip_err(struct sk_buff *skb, u32 info) t->err_time = jiffies; out: read_unlock(&ipip_lock); - return; + return err; #else struct iphdr *iph = (struct iphdr*)dp; int hlen = iph->ihl<<2; @@ -344,15 +348,15 @@ out: struct rtable *rt; if (len < hlen + sizeof(struct iphdr)) - return; + return 0; eiph = (struct iphdr*)(dp + hlen); switch (type) { default: - return; + return 0; case ICMP_PARAMETERPROB: if (skb->h.icmph->un.gateway < hlen) - return; + return 0; /* So... This guy found something strange INSIDE encapsulated packet. Well, he is fool, but what can we do ? @@ -366,16 +370,16 @@ out: case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; 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; + return 0; rel_info -= hlen; /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ if (rel_info > ntohs(eiph->tot_len)) - return; + return 0; break; default: /* All others are translated to HOST_UNREACH. @@ -389,14 +393,14 @@ out: break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; break; } /* Prepare fake skb to feed it to icmp_send */ skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) - return; + return 0; dst_release(skb2->dst); skb2->dst = NULL; skb_pull(skb2, skb->data - (u8*)eiph); @@ -409,7 +413,7 @@ out: fl.proto = IPPROTO_IPIP; if (ip_route_output_key(&rt, &key)) { kfree_skb(skb2); - return; + return 0; } skb2->dev = rt->u.dst.dev; @@ -424,14 +428,14 @@ out: rt->u.dst.dev->type != ARPHRD_TUNNEL) { ip_rt_put(rt); kfree_skb(skb2); - return; + return 0; } } 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; + return 0; } } @@ -439,7 +443,7 @@ out: if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { if (rel_info > dst_mtu(skb2->dst)) { kfree_skb(skb2); - return; + return 0; } skb2->dst->ops->update_pmtu(skb2->dst, rel_info); rel_info = htonl(rel_info); @@ -453,7 +457,7 @@ out: icmp_send(skb2, rel_type, rel_code, rel_info); kfree_skb(skb2); - return; + return 0; #endif } @@ -855,39 +859,12 @@ static int __init ipip_fb_tunnel_init(struct net_device *dev) 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"; @@ -897,7 +874,7 @@ static int __init ipip_init(void) printk(banner); - if (ipip_register() < 0) { + if (xfrm4_tunnel_register(&ipip_handler)) { printk(KERN_INFO "ipip init: can't register tunnel\n"); return -EAGAIN; } @@ -919,7 +896,7 @@ static int __init ipip_init(void) err2: free_netdev(ipip_fb_tunnel_dev); err1: - ipip_unregister(); + xfrm4_tunnel_deregister(&ipip_handler); goto out; } @@ -939,7 +916,7 @@ static void __exit ipip_destroy_tunnels(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"); rtnl_lock(); -- cgit v1.1