X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Fxfrm6_tunnel.c;h=8cfc58b96fc2553cbb946765a70c8c6932ba0cff;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=d37768e5064f8c77c9d9b84cb29917accd13d911;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index d37768e50..8cfc58b96 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -28,9 +28,9 @@ #include #include #include +#include #include #include -#include #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG # define X6TDEBUG 3 @@ -351,23 +351,76 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) return 0; } -static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) +static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) { return 0; } -static int xfrm6_tunnel_rcv(struct sk_buff *skb) +static struct xfrm6_tunnel *xfrm6_tunnel_handler; +static DECLARE_MUTEX(xfrm6_tunnel_sem); + +int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) { + int ret; + + down(&xfrm6_tunnel_sem); + ret = 0; + if (xfrm6_tunnel_handler != NULL) + ret = -EINVAL; + if (!ret) + xfrm6_tunnel_handler = handler; + up(&xfrm6_tunnel_sem); + + return ret; +} + +EXPORT_SYMBOL(xfrm6_tunnel_register); + +int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) +{ + int ret; + + down(&xfrm6_tunnel_sem); + ret = 0; + if (xfrm6_tunnel_handler != handler) + ret = -EINVAL; + if (!ret) + xfrm6_tunnel_handler = NULL; + up(&xfrm6_tunnel_sem); + + 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(skb, spi); + return xfrm6_rcv_spi(pskb, spi); } -static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __u32 info) +static void 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: @@ -408,8 +461,7 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, default: break; } - - return 0; + return; } static int xfrm6_tunnel_init_state(struct xfrm_state *x) @@ -440,10 +492,10 @@ static struct xfrm_type xfrm6_tunnel_type = { .output = xfrm6_tunnel_output, }; -static struct xfrm6_tunnel xfrm6_tunnel_handler = { +static struct inet6_protocol xfrm6_tunnel_protocol = { .handler = xfrm6_tunnel_rcv, - .err_handler = xfrm6_tunnel_err, - .priority = 2, + .err_handler = xfrm6_tunnel_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; static int __init xfrm6_tunnel_init(void) @@ -455,16 +507,16 @@ static int __init xfrm6_tunnel_init(void) "xfrm6_tunnel init: can't add xfrm type\n"); return -EAGAIN; } - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { + if (inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) { X6TPRINTK1(KERN_ERR - "xfrm6_tunnel init(): can't add handler\n"); + "xfrm6_tunnel init(): can't add protocol\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"); - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); + inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); return -EAGAIN; } @@ -476,9 +528,9 @@ static void __exit xfrm6_tunnel_fini(void) X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); xfrm6_tunnel_spi_fini(); - if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler)) + if (inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) X6TPRINTK1(KERN_ERR - "xfrm6_tunnel close: can't remove handler\n"); + "xfrm6_tunnel close: can't remove protocol\n"); if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0) X6TPRINTK1(KERN_ERR "xfrm6_tunnel close: can't remove xfrm type\n");