-struct ipcomp6_tfms {
- struct list_head list;
- struct crypto_tfm **tfms;
- int users;
-};
-
-static DEFINE_MUTEX(ipcomp6_resource_mutex);
-static void **ipcomp6_scratches;
-static int ipcomp6_scratch_users;
-static LIST_HEAD(ipcomp6_tfms_list);
-
-static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
-{
- int err = -ENOMEM;
- struct ipv6hdr *iph;
- struct ipv6_comp_hdr *ipch;
- int plen, dlen;
- struct ipcomp_data *ipcd = x->data;
- u8 *start, *scratch;
- struct crypto_tfm *tfm;
- int cpu;
-
- if (skb_linearize_cow(skb))
- goto out;
-
- skb->ip_summed = CHECKSUM_NONE;
-
- /* Remove ipcomp header and decompress original payload */
- iph = skb->nh.ipv6h;
- ipch = (void *)skb->data;
- skb->h.raw = skb->nh.raw + sizeof(*ipch);
- __skb_pull(skb, sizeof(*ipch));
-
- /* decompression */
- plen = skb->len;
- dlen = IPCOMP_SCRATCH_SIZE;
- start = skb->data;
-
- cpu = get_cpu();
- scratch = *per_cpu_ptr(ipcomp6_scratches, cpu);
- tfm = *per_cpu_ptr(ipcd->tfms, cpu);
-
- err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
- if (err) {
- err = -EINVAL;
- goto out_put_cpu;
- }
-
- if (dlen < (plen + sizeof(struct ipv6_comp_hdr))) {
- err = -EINVAL;
- goto out_put_cpu;
- }
-
- err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
- if (err) {
- goto out_put_cpu;
- }
-
- skb->truesize += dlen - plen;
- __skb_put(skb, dlen - plen);
- memcpy(skb->data, scratch, dlen);
- err = ipch->nexthdr;
-
-out_put_cpu:
- put_cpu();
-out:
- return err;
-}
-
-static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
-{
- int err;
- struct ipv6hdr *top_iph;
- int hdr_len;
- struct ipv6_comp_hdr *ipch;
- struct ipcomp_data *ipcd = x->data;
- int plen, dlen;
- u8 *start, *scratch;
- struct crypto_tfm *tfm;
- int cpu;
-
- hdr_len = skb->h.raw - skb->data;
-
- /* check whether datagram len is larger than threshold */
- if ((skb->len - hdr_len) < ipcd->threshold) {
- goto out_ok;
- }
-
- if (skb_linearize_cow(skb))
- goto out_ok;
-
- /* compression */
- plen = skb->len - hdr_len;
- dlen = IPCOMP_SCRATCH_SIZE;
- start = skb->h.raw;
-
- cpu = get_cpu();
- scratch = *per_cpu_ptr(ipcomp6_scratches, cpu);
- tfm = *per_cpu_ptr(ipcd->tfms, cpu);
-
- err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
- if (err || (dlen + sizeof(struct ipv6_comp_hdr)) >= plen) {
- put_cpu();
- goto out_ok;
- }
- memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
- put_cpu();
- pskb_trim(skb, hdr_len + dlen + sizeof(struct ip_comp_hdr));
-
- /* insert ipcomp header and replace datagram */
- top_iph = (struct ipv6hdr *)skb->data;
-
- top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
-
- ipch = (struct ipv6_comp_hdr *)start;
- ipch->nexthdr = *skb->nh.raw;
- ipch->flags = 0;
- ipch->cpi = htons((u16 )ntohl(x->id.spi));
- *skb->nh.raw = IPPROTO_COMP;
-
-out_ok:
- return 0;
-}
-