X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fxfrm4_tunnel.c;h=f110af5b1319f0968a4278283cdaa171761d6e75;hb=refs%2Fheads%2Fvserver;hp=3c9d4aaa21be383d66481c5fd7ecf70793fbce0a;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 3c9d4aaa2..f110af5b1 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -4,150 +4,36 @@ */ #include +#include +#include #include #include -#include -#include +#include -int xfrm4_tunnel_check_size(struct sk_buff *skb) +static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) { - int mtu, ret = 0; - struct dst_entry *dst; - struct iphdr *iph = skb->nh.iph; - - if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) - goto out; - - IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; + struct iphdr *iph; - if (!(iph->frag_off & htons(IP_DF))) - goto out; - - dst = skb->dst; - mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len; - if (skb->len > mtu) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - ret = -EMSGSIZE; - } -out: - return ret; -} - -static int ipip_output(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - int tos, err; - - if ((err = xfrm4_tunnel_check_size(skb)) != 0) - goto error_nolock; - iph = skb->nh.iph; + iph->tot_len = htons(skb->len); + ip_send_check(iph); - spin_lock_bh(&x->lock); - - tos = iph->tos; - - top_iph = (struct iphdr *) skb_push(skb, x->props.header_len); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = INET_ECN_encapsulate(tos, iph->tos); - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = iph->frag_off & ~htons(IP_MF|IP_OFFSET); - if (!(iph->frag_off & htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; - top_iph->protocol = IPPROTO_IPIP; - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock_bh(&x->lock); - - if ((skb->dst = dst_pop(dst)) == NULL) { - kfree_skb(skb); - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error_nolock: - kfree_skb(skb); - return err; -} - -static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ return 0; } -static struct xfrm_tunnel *ipip_handler; -static DECLARE_MUTEX(xfrm4_tunnel_sem); - -int xfrm4_tunnel_register(struct xfrm_tunnel *handler) +static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) { - int ret; - - down(&xfrm4_tunnel_sem); - ret = 0; - if (ipip_handler != NULL) - ret = -EINVAL; - if (!ret) - ipip_handler = handler; - up(&xfrm4_tunnel_sem); - - return ret; -} - -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) -{ - int ret; - - down(&xfrm4_tunnel_sem); - ret = 0; - if (ipip_handler != handler) - ret = -EINVAL; - if (!ret) - ipip_handler = NULL; - up(&xfrm4_tunnel_sem); - - synchronize_net(); - - return ret; -} - -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_encap(skb, 0); + return 0; } -static void ipip_err(struct sk_buff *skb, u32 info) +static int ipip_init_state(struct xfrm_state *x) { - struct xfrm_tunnel *handler = ipip_handler; - u32 arg = info; - - if (handler) - handler->err_handler(skb, &arg); -} + if (x->props.mode != XFRM_MODE_TUNNEL) + return -EINVAL; -static int ipip_init_state(struct xfrm_state *x, void *args) -{ - if (!x->props.mode) + if (x->encap) return -EINVAL; + x->props.header_len = sizeof(struct iphdr); return 0; @@ -167,10 +53,15 @@ static struct xfrm_type ipip_type = { .output = ipip_output }; -static struct inet_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) @@ -179,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; } @@ -189,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"); }