diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/Kconfig | 17 | ||||
-rw-r--r-- | net/ipv4/Makefile | 3 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 79 | ||||
-rw-r--r-- | net/ipv4/tunnel4.c | 113 | ||||
-rw-r--r-- | net/ipv4/xfrm4_tunnel.c | 79 |
5 files changed, 165 insertions, 126 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 011cca7ae02b..e40f75322377 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -235,6 +235,7 @@ config IP_PNP_RARP # bool ' IP: ARP support' CONFIG_IP_PNP_ARP config NET_IPIP tristate "IP: tunneling" + select INET_TUNNEL ---help--- Tunneling means encapsulating data of one protocol type within another protocol and sending it over a channel that understands the @@ -395,7 +396,7 @@ config INET_ESP config INET_IPCOMP tristate "IP: IPComp transformation" select XFRM - select INET_TUNNEL + select INET_XFRM_TUNNEL select CRYPTO select CRYPTO_DEFLATE ---help--- @@ -404,14 +405,14 @@ config INET_IPCOMP If unsure, say Y. +config INET_XFRM_TUNNEL + tristate + select INET_TUNNEL + default n + config INET_TUNNEL - tristate "IP: tunnel transformation" - select XFRM - ---help--- - Support for generic IP tunnel transformation, which is required by - the IP tunneling module as well as tunnel mode IPComp. - - If unsure, say Y. + tristate + default n config INET_DIAG tristate "INET: socket monitoring interface" diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 35e5f5999092..9ef50a0b9d2c 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -22,7 +22,8 @@ obj-$(CONFIG_SYN_COOKIES) += syncookies.o obj-$(CONFIG_INET_AH) += ah4.o obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o -obj-$(CONFIG_INET_TUNNEL) += xfrm4_tunnel.o +obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o +obj-$(CONFIG_INET_TUNNEL) += tunnel4.o obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 03d13742a4b8..eef07b0916a3 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -114,7 +114,6 @@ #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> @@ -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(); diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c new file mode 100644 index 000000000000..0d7d386dac22 --- /dev/null +++ b/net/ipv4/tunnel4.c @@ -0,0 +1,113 @@ +/* tunnel4.c: Generic IP tunnel transformer. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <net/protocol.h> +#include <net/xfrm.h> + +static struct xfrm_tunnel *tunnel4_handlers; +static DEFINE_MUTEX(tunnel4_mutex); + +int xfrm4_tunnel_register(struct xfrm_tunnel *handler) +{ + struct xfrm_tunnel **pprev; + int ret = -EEXIST; + int priority = handler->priority; + + mutex_lock(&tunnel4_mutex); + + for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + if ((*pprev)->priority > priority) + break; + if ((*pprev)->priority == priority) + goto err; + } + + handler->next = *pprev; + *pprev = handler; + + ret = 0; + +err: + mutex_unlock(&tunnel4_mutex); + + return ret; +} + +EXPORT_SYMBOL(xfrm4_tunnel_register); + +int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) +{ + struct xfrm_tunnel **pprev; + int ret = -ENOENT; + + mutex_lock(&tunnel4_mutex); + + for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + if (*pprev == handler) { + *pprev = handler->next; + ret = 0; + break; + } + } + + mutex_unlock(&tunnel4_mutex); + + synchronize_net(); + + return ret; +} + +EXPORT_SYMBOL(xfrm4_tunnel_deregister); + +static int tunnel4_rcv(struct sk_buff *skb) +{ + struct xfrm_tunnel *handler; + + for (handler = tunnel4_handlers; handler; handler = handler->next) + if (!handler->handler(skb)) + return 0; + + kfree_skb(skb); + return 0; +} + +static void tunnel4_err(struct sk_buff *skb, u32 info) +{ + struct xfrm_tunnel *handler; + + for (handler = tunnel4_handlers; handler; handler = handler->next) + if (!handler->err_handler(skb, info)) + break; +} + +static struct net_protocol tunnel4_protocol = { + .handler = tunnel4_rcv, + .err_handler = tunnel4_err, + .no_policy = 1, +}; + +static int __init tunnel4_init(void) +{ + if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { + printk(KERN_ERR "tunnel4 init: can't add protocol\n"); + return -EAGAIN; + } + return 0; +} + +static void __exit tunnel4_fini(void) +{ + if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) + printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); +} + +module_init(tunnel4_init); +module_exit(tunnel4_fini); +MODULE_LICENSE("GPL"); diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index b08d56b117f8..2d670935c2b5 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -26,64 +26,6 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s return 0; } -static struct xfrm_tunnel *ipip_handler; -static DEFINE_MUTEX(xfrm4_tunnel_mutex); - -int xfrm4_tunnel_register(struct xfrm_tunnel *handler) -{ - int ret; - - mutex_lock(&xfrm4_tunnel_mutex); - ret = 0; - if (ipip_handler != NULL) - ret = -EINVAL; - if (!ret) - ipip_handler = handler; - mutex_unlock(&xfrm4_tunnel_mutex); - - return ret; -} - -EXPORT_SYMBOL(xfrm4_tunnel_register); - -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) -{ - int ret; - - mutex_lock(&xfrm4_tunnel_mutex); - ret = 0; - if (ipip_handler != handler) - ret = -EINVAL; - if (!ret) - ipip_handler = NULL; - mutex_unlock(&xfrm4_tunnel_mutex); - - synchronize_net(); - - return ret; -} - -EXPORT_SYMBOL(xfrm4_tunnel_deregister); - -static int ipip_rcv(struct sk_buff *skb) -{ - struct xfrm_tunnel *handler = ipip_handler; - - /* Tunnel devices take precedence. */ - if (handler && handler->handler(skb) == 0) - return 0; - - return xfrm4_rcv(skb); -} - -static void ipip_err(struct sk_buff *skb, u32 info) -{ - struct xfrm_tunnel *handler = ipip_handler; - - if (handler) - handler->err_handler(skb, info); -} - static int ipip_init_state(struct xfrm_state *x) { if (!x->props.mode) @@ -111,10 +53,15 @@ static struct xfrm_type ipip_type = { .output = ipip_output }; -static struct net_protocol ipip_protocol = { - .handler = ipip_rcv, - .err_handler = ipip_err, - .no_policy = 1, +static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) +{ + return -ENOENT; +} + +static struct xfrm_tunnel xfrm_tunnel_handler = { + .handler = xfrm4_rcv, + .err_handler = xfrm_tunnel_err, + .priority = 2, }; static int __init ipip_init(void) @@ -123,8 +70,8 @@ static int __init ipip_init(void) printk(KERN_INFO "ipip init: can't add xfrm type\n"); return -EAGAIN; } - if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) { - printk(KERN_INFO "ipip init: can't add protocol\n"); + if (xfrm4_tunnel_register(&xfrm_tunnel_handler)) { + printk(KERN_INFO "ipip init: can't add xfrm handler\n"); xfrm_unregister_type(&ipip_type, AF_INET); return -EAGAIN; } @@ -133,8 +80,8 @@ static int __init ipip_init(void) static void __exit ipip_fini(void) { - if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) - printk(KERN_INFO "ipip close: can't remove protocol\n"); + if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler)) + printk(KERN_INFO "ipip close: can't remove xfrm handler\n"); if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) printk(KERN_INFO "ipip close: can't remove xfrm type\n"); } |