+#include <linux/config.h>
#include <linux/module.h>
#include <net/ip.h>
#include <net/xfrm.h>
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)))
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)
/* ... 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;
+
+ uh = (struct udphdr *)(iph + 1);
+ encap_len = (void*)esph - (void*)uh;
/*
* 1) if the NAT-T peer's IP or port changed then
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;
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;