[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 <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Herbert Xu 2006-03-28 01:12:13 -08:00 committed by David S. Miller
parent f0088a50e7
commit d2acc3479c
12 changed files with 344 additions and 247 deletions

View File

@ -864,13 +864,19 @@ struct xfrm_algo_desc {
/* XFRM tunnel handlers. */
struct xfrm_tunnel {
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, __u32 info);
int (*err_handler)(struct sk_buff *skb, __u32 info);
struct xfrm_tunnel *next;
int priority;
};
struct xfrm6_tunnel {
int (*handler)(struct sk_buff **pskb);
void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info);
int (*handler)(struct sk_buff *skb);
int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info);
struct xfrm6_tunnel *next;
int priority;
};
extern void xfrm_init(void);
@ -906,7 +912,7 @@ extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_output(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi);
extern int xfrm6_rcv(struct sk_buff **pskb);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);

View File

@ -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"

View File

@ -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

View File

@ -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();

113
net/ipv4/tunnel4.c Normal file
View File

@ -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");

View File

@ -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");
}

View File

@ -88,7 +88,7 @@ config INET6_IPCOMP
tristate "IPv6: IPComp transformation"
depends on IPV6
select XFRM
select INET6_TUNNEL
select INET6_XFRM_TUNNEL
select CRYPTO
select CRYPTO_DEFLATE
---help---
@ -97,19 +97,18 @@ config INET6_IPCOMP
If unsure, say Y.
config INET6_XFRM_TUNNEL
tristate
select INET6_TUNNEL
default n
config INET6_TUNNEL
tristate "IPv6: tunnel transformation"
depends on IPV6
select XFRM
---help---
Support for generic IPv6-in-IPv6 tunnel transformation, which is
required by the IPv6-in-IPv6 tunneling module as well as tunnel mode
IPComp.
If unsure, say Y.
tristate
default n
config IPV6_TUNNEL
tristate "IPv6: IPv6-in-IPv6 tunnel"
select INET6_TUNNEL
depends on IPV6
---help---
Support for IPv6-in-IPv6 tunnels described in RFC 2473.

View File

@ -18,7 +18,8 @@ ipv6-objs += $(ipv6-y)
obj-$(CONFIG_INET6_AH) += ah6.o
obj-$(CONFIG_INET6_ESP) += esp6.o
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
obj-$(CONFIG_INET6_TUNNEL) += xfrm6_tunnel.o
obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o

View File

@ -44,7 +44,6 @@
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/ip6_tunnel.h>
@ -391,7 +390,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
* to the specifications in RFC 2473.
**/
static void
static int
ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
@ -402,6 +401,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int rel_code = ICMPV6_ADDR_UNREACH;
__u32 rel_info = 0;
__u16 len;
int err = -ENOENT;
/* If the packet doesn't contain the original IPv6 header we are
in trouble since we might need the source address for further
@ -411,6 +411,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
goto out;
err = 0;
switch (type) {
__u32 teli;
struct ipv6_tlv_tnl_enc_lim *tel;
@ -492,6 +494,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
}
out:
read_unlock(&ip6ip6_lock);
return err;
}
static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
@ -511,9 +514,8 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
**/
static int
ip6ip6_rcv(struct sk_buff **pskb)
ip6ip6_rcv(struct sk_buff *skb)
{
struct sk_buff *skb = *pskb;
struct ipv6hdr *ipv6h;
struct ip6_tnl *t;
@ -1112,39 +1114,12 @@ ip6ip6_fb_tnl_dev_init(struct net_device *dev)
return 0;
}
#ifdef CONFIG_INET6_TUNNEL
static struct xfrm6_tunnel ip6ip6_handler = {
.handler = ip6ip6_rcv,
.err_handler = ip6ip6_err,
.priority = 1,
};
static inline int ip6ip6_register(void)
{
return xfrm6_tunnel_register(&ip6ip6_handler);
}
static inline int ip6ip6_unregister(void)
{
return xfrm6_tunnel_deregister(&ip6ip6_handler);
}
#else
static struct inet6_protocol xfrm6_tunnel_protocol = {
.handler = ip6ip6_rcv,
.err_handler = ip6ip6_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
static inline int ip6ip6_register(void)
{
return inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
}
static inline int ip6ip6_unregister(void)
{
return inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
}
#endif
/**
* ip6_tunnel_init - register protocol and reserve needed resources
*
@ -1155,7 +1130,7 @@ static int __init ip6_tunnel_init(void)
{
int err;
if (ip6ip6_register() < 0) {
if (xfrm6_tunnel_register(&ip6ip6_handler)) {
printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
return -EAGAIN;
}
@ -1174,7 +1149,7 @@ static int __init ip6_tunnel_init(void)
}
return 0;
fail:
ip6ip6_unregister();
xfrm6_tunnel_deregister(&ip6ip6_handler);
return err;
}
@ -1184,7 +1159,7 @@ fail:
static void __exit ip6_tunnel_cleanup(void)
{
if (ip6ip6_unregister() < 0)
if (xfrm6_tunnel_deregister(&ip6ip6_handler))
printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
unregister_netdev(ip6ip6_fb_tnl_dev);

131
net/ipv6/tunnel6.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (C)2003,2004 USAGI/WIDE Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors Mitsuru KANDA <mk@linux-ipv6.org>
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*/
#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 xfrm6_tunnel *tunnel6_handlers;
static DEFINE_MUTEX(tunnel6_mutex);
int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
{
struct xfrm6_tunnel **pprev;
int ret = -EEXIST;
int priority = handler->priority;
mutex_lock(&tunnel6_mutex);
for (pprev = &tunnel6_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(&tunnel6_mutex);
return ret;
}
EXPORT_SYMBOL(xfrm6_tunnel_register);
int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
{
struct xfrm6_tunnel **pprev;
int ret = -ENOENT;
mutex_lock(&tunnel6_mutex);
for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) {
if (*pprev == handler) {
*pprev = handler->next;
ret = 0;
break;
}
}
mutex_unlock(&tunnel6_mutex);
synchronize_net();
return ret;
}
EXPORT_SYMBOL(xfrm6_tunnel_deregister);
static int tunnel6_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler;
for (handler = tunnel6_handlers; handler; handler = handler->next)
if (!handler->handler(skb))
return 0;
kfree_skb(skb);
return 0;
}
static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
struct xfrm6_tunnel *handler;
for (handler = tunnel6_handlers; handler; handler = handler->next)
if (!handler->err_handler(skb, opt, type, code, offset, info))
break;
}
static struct inet6_protocol tunnel6_protocol = {
.handler = tunnel6_rcv,
.err_handler = tunnel6_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
static int __init tunnel6_init(void)
{
if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) {
printk(KERN_ERR "tunnel6 init(): can't add protocol\n");
return -EAGAIN;
}
return 0;
}
static void __exit tunnel6_fini(void)
{
if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6))
printk(KERN_ERR "tunnel6 close: can't remove protocol\n");
}
module_init(tunnel6_init);
module_exit(tunnel6_fini);
MODULE_LICENSE("GPL");

View File

@ -28,9 +28,8 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
IP6_ECN_set_ce(inner_iph);
}
int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
{
struct sk_buff *skb = *pskb;
int err;
u32 seq;
struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
@ -159,5 +158,5 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
int xfrm6_rcv(struct sk_buff **pskb)
{
return xfrm6_rcv_spi(pskb, 0);
return xfrm6_rcv_spi(*pskb, 0);
}

View File

@ -28,7 +28,6 @@
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/mutex.h>
@ -357,71 +356,18 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec
return 0;
}
static struct xfrm6_tunnel *xfrm6_tunnel_handler;
static DEFINE_MUTEX(xfrm6_tunnel_mutex);
int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
static int xfrm6_tunnel_rcv(struct sk_buff *skb)
{
int ret;
mutex_lock(&xfrm6_tunnel_mutex);
ret = 0;
if (xfrm6_tunnel_handler != NULL)
ret = -EINVAL;
if (!ret)
xfrm6_tunnel_handler = handler;
mutex_unlock(&xfrm6_tunnel_mutex);
return ret;
}
EXPORT_SYMBOL(xfrm6_tunnel_register);
int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
{
int ret;
mutex_lock(&xfrm6_tunnel_mutex);
ret = 0;
if (xfrm6_tunnel_handler != handler)
ret = -EINVAL;
if (!ret)
xfrm6_tunnel_handler = NULL;
mutex_unlock(&xfrm6_tunnel_mutex);
synchronize_net();
return ret;
}
EXPORT_SYMBOL(xfrm6_tunnel_deregister);
static int xfrm6_tunnel_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
struct ipv6hdr *iph = skb->nh.ipv6h;
u32 spi;
/* device-like_ip6ip6_handler() */
if (handler && handler->handler(pskb) == 0)
return 0;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
return xfrm6_rcv_spi(pskb, spi);
return xfrm6_rcv_spi(skb, spi);
}
static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
/* call here first for device-like ip6ip6 err handling */
if (handler) {
handler->err_handler(skb, opt, type, code, offset, info);
return;
}
/* xfrm6_tunnel native err handling */
switch (type) {
case ICMPV6_DEST_UNREACH:
@ -462,7 +408,8 @@ static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
default:
break;
}
return;
return 0;
}
static int xfrm6_tunnel_init_state(struct xfrm_state *x)
@ -493,10 +440,10 @@ static struct xfrm_type xfrm6_tunnel_type = {
.output = xfrm6_tunnel_output,
};
static struct inet6_protocol xfrm6_tunnel_protocol = {
static struct xfrm6_tunnel xfrm6_tunnel_handler = {
.handler = xfrm6_tunnel_rcv,
.err_handler = xfrm6_tunnel_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
.err_handler = xfrm6_tunnel_err,
.priority = 2,
};
static int __init xfrm6_tunnel_init(void)
@ -508,16 +455,16 @@ static int __init xfrm6_tunnel_init(void)
"xfrm6_tunnel init: can't add xfrm type\n");
return -EAGAIN;
}
if (inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) {
if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) {
X6TPRINTK1(KERN_ERR
"xfrm6_tunnel init(): can't add protocol\n");
"xfrm6_tunnel init(): can't add handler\n");
xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
return -EAGAIN;
}
if (xfrm6_tunnel_spi_init() < 0) {
X6TPRINTK1(KERN_ERR
"xfrm6_tunnel init: failed to initialize spi\n");
inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
xfrm6_tunnel_deregister(&xfrm6_tunnel_handler);
xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
return -EAGAIN;
}
@ -529,9 +476,9 @@ static void __exit xfrm6_tunnel_fini(void)
X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
xfrm6_tunnel_spi_fini();
if (inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0)
if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler))
X6TPRINTK1(KERN_ERR
"xfrm6_tunnel close: can't remove protocol\n");
"xfrm6_tunnel close: can't remove handler\n");
if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0)
X6TPRINTK1(KERN_ERR
"xfrm6_tunnel close: can't remove xfrm type\n");