fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / ipv4 / xfrm4_output.c
index ecc4119..1290ac7 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/netfilter_ipv4.h>
-#include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/icmp.h>
 
 extern int skb_checksum_setup(struct sk_buff *skb);
 
-/* Add encapsulation header.
- *
- * In transport mode, the IP header will be moved forward to make space
- * for the encapsulation header.
- *
- * In tunnel mode, the top IP header will be constructed per RFC 2401.
- * The following fields in it shall be filled in by x->type->output:
- *     tot_len
- *     check
- *
- * On exit, skb->h will be set to the start of the payload to be processed
- * by x->type->output and skb->nh will be set to the top IP header.
- */
-static void xfrm4_encap(struct sk_buff *skb)
-{
-       struct dst_entry *dst = skb->dst;
-       struct xfrm_state *x = dst->xfrm;
-       struct iphdr *iph, *top_iph;
-       int flags;
-
-       iph = skb->nh.iph;
-       skb->h.ipiph = iph;
-
-       skb->nh.raw = skb_push(skb, x->props.header_len);
-       top_iph = skb->nh.iph;
-
-       if (!x->props.mode) {
-               skb->h.raw += iph->ihl*4;
-               memmove(top_iph, iph, iph->ihl*4);
-               return;
-       }
-
-       top_iph->ihl = 5;
-       top_iph->version = 4;
-
-       /* DS disclosed */
-       top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
-
-       flags = x->props.flags;
-       if (flags & XFRM_STATE_NOECN)
-               IP_ECN_clear(top_iph);
-
-       top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
-               0 : (iph->frag_off & htons(IP_DF));
-       if (!top_iph->frag_off)
-               __ip_select_ident(top_iph, dst->child, 0);
-
-       top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
-
-       top_iph->saddr = x->props.saddr.a4;
-       top_iph->daddr = x->id.daddr.a4;
-       top_iph->protocol = IPPROTO_IPIP;
-
-       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-}
-
 static int xfrm4_tunnel_check_size(struct sk_buff *skb)
 {
        int mtu, ret = 0;
@@ -111,13 +54,13 @@ static int xfrm4_output_one(struct sk_buff *skb)
        if (err)
                goto error_nolock;
 
-       if (skb->ip_summed == CHECKSUM_HW) {
-               err = skb_checksum_help(skb, 0);
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               err = skb_checksum_help(skb);
                if (err)
                        goto error_nolock;
        }
 
-       if (x->props.mode) {
+       if (x->props.mode == XFRM_MODE_TUNNEL) {
                err = xfrm4_tunnel_check_size(skb);
                if (err)
                        goto error_nolock;
@@ -129,7 +72,9 @@ static int xfrm4_output_one(struct sk_buff *skb)
                if (err)
                        goto error;
 
-               xfrm4_encap(skb);
+               err = x->mode->output(x, skb);
+               if (err)
+                       goto error;
 
                err = x->type->output(x, skb);
                if (err)
@@ -146,7 +91,7 @@ static int xfrm4_output_one(struct sk_buff *skb)
                }
                dst = skb->dst;
                x = dst->xfrm;
-       } while (x && !x->props.mode);
+       } while (x && (x->props.mode != XFRM_MODE_TUNNEL));
 
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
        err = 0;