linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / ipv4 / esp4.c
index fc2f8ce..09590f3 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
@@ -89,7 +90,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 
        esph->spi = x->id.spi;
        esph->seq_no = htonl(++x->replay.oseq);
-       xfrm_aevent_doreplay(x);
 
        if (esp->conf.ivlen)
                crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
@@ -132,7 +132,7 @@ error:
  * expensive, so we only support truncated data, which is the recommended
  * and common case.
  */
-static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 {
        struct iphdr *iph;
        struct ip_esp_hdr *esph;
@@ -142,9 +142,10 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
        int alen = esp->auth.icv_trunc_len;
        int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;
        int nfrags;
-       int ihl;
+       int encap_len = 0;
        u8 nexthdr[2];
        struct scatterlist *sg;
+       u8 workbuf[60];
        int padlen;
 
        if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
@@ -175,6 +176,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
        skb->ip_summed = CHECKSUM_NONE;
 
        esph = (struct ip_esp_hdr*)skb->data;
+       iph = skb->nh.iph;
 
        /* Get ivec. This can be wrong, check against another impls. */
        if (esp->conf.ivlen)
@@ -201,12 +203,15 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 
        /* ... check padding bits here. Silly. :-) */ 
 
-       iph = skb->nh.iph;
-       ihl = iph->ihl * 4;
-
        if (x->encap) {
                struct xfrm_encap_tmpl *encap = x->encap;
-               struct udphdr *uh = (void *)(skb->nh.raw + ihl);
+               struct udphdr *uh;
+
+               if (encap->encap_type != decap->decap_type)
+                       goto out;
+
+               uh = (struct udphdr *)(iph + 1);
+               encap_len = (void*)esph - (void*)uh;
 
                /*
                 * 1) if the NAT-T peer's IP or port changed then
@@ -243,7 +248,11 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 
        iph->protocol = nexthdr[1];
        pskb_trim(skb, skb->len - alen - padlen - 2);
-       skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl;
+       memcpy(workbuf, skb->nh.raw, iph->ihl*4);
+       skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
+       skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+       memcpy(skb->nh.raw, workbuf, iph->ihl*4);
+       skb->nh.iph->tot_len = htons(skb->len);
 
        return 0;
 
@@ -316,10 +325,12 @@ static int esp_init_state(struct xfrm_state *x)
        if (x->ealg == NULL)
                goto error;
 
-       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+       esp = kmalloc(sizeof(*esp), GFP_KERNEL);
        if (esp == NULL)
                return -ENOMEM;
 
+       memset(esp, 0, sizeof(*esp));
+
        if (x->aalg) {
                struct xfrm_algo_desc *aalg_desc;