*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
+ * Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* Todo:
static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
{
- int err, plen, dlen;
struct ipcomp_data *ipcd = x->data;
- u8 *start, *scratch;
- struct crypto_comp *tfm;
- int cpu;
-
- plen = skb->len;
- dlen = IPCOMP_SCRATCH_SIZE;
- start = skb->data;
-
- cpu = get_cpu();
- scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
- tfm = *per_cpu_ptr(ipcd->tfms, cpu);
+ const int plen = skb->len;
+ int dlen = IPCOMP_SCRATCH_SIZE;
+ const u8 *start = skb->data;
+ const int cpu = get_cpu();
+ u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
+ struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
+ int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
- err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
if (err)
goto out;
err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
if (err)
goto out;
-
+
skb->truesize += dlen - plen;
__skb_put(skb, dlen - plen);
- memcpy(skb->data, scratch, dlen);
-out:
+ skb_copy_to_linear_data(skb, scratch, dlen);
+out:
put_cpu();
return err;
}
static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
{
int err = -ENOMEM;
- struct iphdr *iph;
struct ip_comp_hdr *ipch;
if (skb_linearize_cow(skb))
- goto out;
+ goto out;
skb->ip_summed = CHECKSUM_NONE;
- /* Remove ipcomp header and decompress original payload */
- iph = skb->nh.iph;
+ /* Remove ipcomp header and decompress original payload */
ipch = (void *)skb->data;
- iph->protocol = ipch->nexthdr;
- skb->h.raw = skb->nh.raw + sizeof(*ipch);
+ skb->transport_header = skb->network_header + sizeof(*ipch);
__skb_pull(skb, sizeof(*ipch));
err = ipcomp_decompress(x, skb);
+ if (err)
+ goto out;
+
+ err = ipch->nexthdr;
-out:
+out:
return err;
}
static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
{
- int err, plen, dlen, ihlen;
- struct iphdr *iph = skb->nh.iph;
struct ipcomp_data *ipcd = x->data;
- u8 *start, *scratch;
- struct crypto_comp *tfm;
- int cpu;
-
- ihlen = iph->ihl * 4;
- plen = skb->len - ihlen;
- dlen = IPCOMP_SCRATCH_SIZE;
- start = skb->data + ihlen;
+ const int plen = skb->len;
+ int dlen = IPCOMP_SCRATCH_SIZE;
+ u8 *start = skb->data;
+ const int cpu = get_cpu();
+ u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
+ struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
+ int err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
- cpu = get_cpu();
- scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
- tfm = *per_cpu_ptr(ipcd->tfms, cpu);
-
- err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
if (err)
goto out;
err = -EMSGSIZE;
goto out;
}
-
+
memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
put_cpu();
- pskb_trim(skb, ihlen + dlen + sizeof(struct ip_comp_hdr));
+ pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
return 0;
-
-out:
+
+out:
put_cpu();
return err;
}
static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
- struct iphdr *iph;
struct ip_comp_hdr *ipch;
struct ipcomp_data *ipcd = x->data;
- int hdr_len = 0;
- iph = skb->nh.iph;
- iph->tot_len = htons(skb->len);
- hdr_len = iph->ihl * 4;
- if ((skb->len - hdr_len) < ipcd->threshold) {
+ if (skb->len < ipcd->threshold) {
/* Don't bother compressing */
goto out_ok;
}
if (skb_linearize_cow(skb))
goto out_ok;
-
+
err = ipcomp_compress(x, skb);
- iph = skb->nh.iph;
if (err) {
goto out_ok;
}
/* Install ipcomp header, convert into ipcomp datagram. */
- iph->tot_len = htons(skb->len);
- ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4);
- ipch->nexthdr = iph->protocol;
+ ipch = ip_comp_hdr(skb);
+ ipch->nexthdr = *skb_mac_header(skb);
ipch->flags = 0;
ipch->cpi = htons((u16 )ntohl(x->id.spi));
- iph->protocol = IPPROTO_COMP;
- ip_send_check(iph);
- return 0;
-
+ *skb_mac_header(skb) = IPPROTO_COMP;
out_ok:
- if (x->props.mode == XFRM_MODE_TUNNEL)
- ip_send_check(iph);
+ skb_push(skb, -skb_network_offset(skb));
return 0;
}
struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
struct xfrm_state *x;
- if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
- skb->h.icmph->code != ICMP_FRAG_NEEDED)
+ if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
+ icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
return;
spi = htonl(ntohs(ipch->cpi));
x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr,
- spi, IPPROTO_COMP, AF_INET);
+ spi, IPPROTO_COMP, AF_INET);
if (!x)
return;
NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%u.%u.%u.%u\n",
xfrm_state_put(x);
}
-/* We always hold one tunnel user reference to indicate a tunnel */
+/* We always hold one tunnel user reference to indicate a tunnel */
static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
{
struct xfrm_state *t;
-
+ u8 mode = XFRM_MODE_TUNNEL;
+
t = xfrm_state_alloc();
if (t == NULL)
goto out;
t->id.daddr.a4 = x->id.daddr.a4;
memcpy(&t->sel, &x->sel, sizeof(t->sel));
t->props.family = AF_INET;
- t->props.mode = XFRM_MODE_TUNNEL;
+ if (x->props.mode == XFRM_MODE_BEET)
+ mode = x->props.mode;
+ t->props.mode = mode;
t->props.saddr.a4 = x->props.saddr.a4;
t->props.flags = x->props.flags;
struct xfrm_state *t;
t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4,
- x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
+ x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
if (!t) {
t = ipcomp_tunnel_create(x);
if (!t) {
MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173");
MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
+MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_COMP);