diff options
Diffstat (limited to 'linux/net/ipsec/ipcomp.c')
-rw-r--r-- | linux/net/ipsec/ipcomp.c | 725 |
1 files changed, 725 insertions, 0 deletions
diff --git a/linux/net/ipsec/ipcomp.c b/linux/net/ipsec/ipcomp.c new file mode 100644 index 000000000..ff12f2cdd --- /dev/null +++ b/linux/net/ipsec/ipcomp.c @@ -0,0 +1,725 @@ +/* + * IPCOMP zlib interface code. + * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk> + * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca> + * + * 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) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +char ipcomp_c_version[] = "RCSID $Id: ipcomp.c,v 1.2 2004/06/13 19:57:49 as Exp $"; + +/* SSS */ + +#include <linux/config.h> +#include <linux/version.h> + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/kernel.h> /* printk() */ + +#include "freeswan/ipsec_param.h" + +#ifdef MALLOC_SLAB +# include <linux/slab.h> /* kmalloc() */ +#else /* MALLOC_SLAB */ +# include <linux/malloc.h> /* kmalloc() */ +#endif /* MALLOC_SLAB */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/ip.h> +#include <linux/skbuff.h> + +#include <linux/netdevice.h> /* struct device, and other headers */ +#include <linux/etherdevice.h> /* eth_type_trans */ +#include <linux/ip.h> /* struct iphdr */ +#include <linux/skbuff.h> + +#include <freeswan.h> + +#ifdef NET_21 +# include <net/dst.h> +# include <asm/uaccess.h> +# include <linux/in6.h> +# define proto_priv cb +#endif /* NET21 */ +#include <asm/checksum.h> +#include <net/ip.h> + +#include "freeswan/radij.h" +#include "freeswan/ipsec_encap.h" +#include "freeswan/ipsec_sa.h" + +#include "freeswan/ipsec_xform.h" +#include "freeswan/ipsec_tunnel.h" +#include "freeswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */ +#include "freeswan/ipcomp.h" +#include "zlib/zlib.h" +#include "zlib/zutil.h" + +#include <pfkeyv2.h> /* SADB_X_CALG_DEFLATE */ + +#ifdef CONFIG_IPSEC_DEBUG +int sysctl_ipsec_debug_ipcomp = 0; +#endif /* CONFIG_IPSEC_DEBUG */ + +static +struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask); + +static +voidpf my_zcalloc(voidpf opaque, uInt items, uInt size) +{ + return (voidpf) kmalloc(items*size, GFP_ATOMIC); +} + +static +void my_zfree(voidpf opaque, voidpf address) +{ + kfree(address); +} + +struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags) +{ + struct iphdr *iph; + unsigned int iphlen, pyldsz, cpyldsz; + unsigned char *buffer; + z_stream zs; + int zresult; + + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: .\n"); + + if(skb == NULL) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "passed in NULL skb, returning ERROR.\n"); + if(flags != NULL) { + *flags |= IPCOMP_PARMERROR; + } + return skb; + } + + if(ips == NULL) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n"); + if(flags) { + *flags |= IPCOMP_PARMERROR; + } + return skb; + } + + if (flags == NULL) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "passed in NULL flags, returning ERROR.\n"); + ipsec_kfree_skb(skb); + return NULL; + } + +#ifdef NET_21 + iph = skb->nh.iph; +#else /* NET_21 */ + iph = skb->ip_hdr; +#endif /* NET_21 */ + + switch (iph->protocol) { + case IPPROTO_COMP: + case IPPROTO_AH: + case IPPROTO_ESP: + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "skipping compression of packet with ip protocol %d.\n", + iph->protocol); + *flags |= IPCOMP_UNCOMPRESSABLE; + return skb; + } + + /* Don't compress packets already fragmented */ + if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "skipping compression of fragmented packet.\n"); + *flags |= IPCOMP_UNCOMPRESSABLE; + return skb; + } + + iphlen = iph->ihl << 2; + pyldsz = ntohs(iph->tot_len) - iphlen; + + /* Don't compress less than 90 bytes (rfc 2394) */ + if (pyldsz < 90) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "skipping compression of tiny packet, len=%d.\n", + pyldsz); + *flags |= IPCOMP_UNCOMPRESSABLE; + return skb; + } + + /* Adaptive decision */ + if (ips->ips_comp_adapt_skip) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "skipping compression: ips_comp_adapt_skip=%d.\n", + ips->ips_comp_adapt_skip); + ips->ips_comp_adapt_skip--; + *flags |= IPCOMP_UNCOMPRESSABLE; + return skb; + } + + zs.zalloc = my_zcalloc; + zs.zfree = my_zfree; + zs.opaque = 0; + + /* We want to use deflateInit2 because we don't want the adler + header. */ + zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11, + DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (zresult != Z_OK) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_compress: " + "deflateInit2() returned error %d (%s), " + "skipping compression.\n", + zresult, + zs.msg ? zs.msg : zError(zresult)); + *flags |= IPCOMP_COMPRESSIONERROR; + return skb; + } + + + /* Max output size. Result should be max this size. + * Implementation specific tweak: + * If it's not at least 32 bytes and 6.25% smaller than + * the original packet, it's probably not worth wasting + * the receiver's CPU cycles decompressing it. + * Your mileage may vary. + */ + cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4); + + buffer = kmalloc(cpyldsz, GFP_ATOMIC); + if (!buffer) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_compress: " + "unable to kmalloc(%d, GFP_ATOMIC), " + "skipping compression.\n", + cpyldsz); + *flags |= IPCOMP_COMPRESSIONERROR; + deflateEnd(&zs); + return skb; + } + +#ifdef CONFIG_IPSEC_DEBUG + if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) { + __u8 *c; + int i; + + c = (__u8*)iph + iphlen; + for(i = 0; i < pyldsz; i++, c++) { + if(!(i % 16)) { + printk(KERN_INFO "skb_compress: before:"); + } + printk("%02x ", *c); + if(!((i + 1) % 16)) { + printk("\n"); + } + } + if(i % 16) { + printk("\n"); + } + } +#endif /* CONFIG_IPSEC_DEBUG */ + + zs.next_in = (char *) iph + iphlen; /* start of payload */ + zs.avail_in = pyldsz; + zs.next_out = buffer; /* start of compressed payload */ + zs.avail_out = cpyldsz; + + /* Finish compression in one step */ + zresult = deflate(&zs, Z_FINISH); + + /* Free all dynamically allocated buffers */ + deflateEnd(&zs); + if (zresult != Z_STREAM_END) { + *flags |= IPCOMP_UNCOMPRESSABLE; + kfree(buffer); + + /* Adjust adaptive counters */ + if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "first %d packets didn't compress, " + "skipping next %d\n", + IPCOMP_ADAPT_INITIAL_TRIES, + IPCOMP_ADAPT_INITIAL_SKIP); + ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP; + } + else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "next %d packets didn't compress, " + "skipping next %d\n", + IPCOMP_ADAPT_SUBSEQ_TRIES, + IPCOMP_ADAPT_SUBSEQ_SKIP); + ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP; + ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES; + } + + return skb; + } + + /* resulting compressed size */ + cpyldsz -= zs.avail_out; + + /* Insert IPCOMP header */ + ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol; + ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0; + /* use the bottom 16 bits of the spi for the cpi. The top 16 bits are + for internal reference only. */ + ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff)); + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_compress: " + "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n", + ntohl(ips->ips_said.spi), + ntohl(ips->ips_said.spi) & 0x0000ffff, + ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi), + pyldsz, + cpyldsz); + + /* Update IP header */ + iph->protocol = IPPROTO_COMP; + iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz); +#if 1 /* XXX checksum is done by ipsec_tunnel ? */ + iph->check = 0; + iph->check = ip_fast_csum((char *) iph, iph->ihl); +#endif + + /* Copy compressed payload */ + memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr), + buffer, + cpyldsz); + kfree(buffer); + + /* Update skb length/tail by "unputting" the shrinkage */ + skb_put(skb, + cpyldsz + sizeof(struct ipcomphdr) - pyldsz); + +#ifdef CONFIG_IPSEC_DEBUG + if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) { + __u8 *c; + int i; + + c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr); + for(i = 0; i < cpyldsz; i++, c++) { + if(!(i % 16)) { + printk(KERN_INFO "skb_compress: result:"); + } + printk("%02x ", *c); + if(!((i + 1) % 16)) { + printk("\n"); + } + } + if(i % 16) { + printk("\n"); + } + } +#endif /* CONFIG_IPSEC_DEBUG */ + + ips->ips_comp_adapt_skip = 0; + ips->ips_comp_adapt_tries = 0; + + return skb; +} + +struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags) +{ + struct sk_buff *nskb = NULL; + + /* original ip header */ + struct iphdr *oiph, *iph; + unsigned int iphlen, pyldsz, cpyldsz; + z_stream zs; + int zresult; + + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_decompress: .\n"); + + if(!skb) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "passed in NULL skb, returning ERROR.\n"); + if (flags) *flags |= IPCOMP_PARMERROR; + return skb; + } + + if(!ips && sysctl_ipsec_inbound_policy_check) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n"); + if (flags) *flags |= IPCOMP_PARMERROR; + return skb; + } + + if (!flags) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "passed in NULL flags, returning ERROR.\n"); + ipsec_kfree_skb(skb); + return NULL; + } + +#ifdef NET_21 + oiph = skb->nh.iph; +#else /* NET_21 */ + oiph = skb->ip_hdr; +#endif /* NET_21 */ + + iphlen = oiph->ihl << 2; + + if (oiph->protocol != IPPROTO_COMP) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "called with non-IPCOMP packet (protocol=%d)," + "skipping decompression.\n", + oiph->protocol); + *flags |= IPCOMP_PARMERROR; + return skb; + } + + if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0) + || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi + != htons(SADB_X_CALG_DEFLATE)) + && sysctl_ipsec_inbound_policy_check + && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "called with incompatible IPCOMP packet (flags=%d, " + "cpi=%d), ips-compalg=%d, skipping decompression.\n", + ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags), + ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi), + ips ? ips->ips_encalg : 0); + *flags |= IPCOMP_PARMERROR; + + return skb; + } + + if (ntohs(oiph->frag_off) & ~0x4000) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "called with fragmented IPCOMP packet, " + "skipping decompression.\n"); + *flags |= IPCOMP_PARMERROR; + return skb; + } + + /* original compressed payload size */ + cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr); + + zs.zalloc = my_zcalloc; + zs.zfree = my_zfree; + zs.opaque = 0; + + zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr); + zs.avail_in = cpyldsz; + + /* Maybe we should be a bit conservative about memory + requirements and use inflateInit2 */ + /* Beware, that this might make us unable to decompress packets + from other implementations - HINT: check PGPnet source code */ + /* We want to use inflateInit2 because we don't want the adler + header. */ + zresult = inflateInit2(&zs, -15); + if (zresult != Z_OK) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "inflateInit2() returned error %d (%s), " + "skipping decompression.\n", + zresult, + zs.msg ? zs.msg : zError(zresult)); + *flags |= IPCOMP_DECOMPRESSIONERROR; + + return skb; + } + + /* We have no way of knowing the exact length of the resulting + decompressed output before we have actually done the decompression. + For now, we guess that the packet will not be bigger than the + attached ipsec device's mtu or 16260, whichever is biggest. + This may be wrong, since the sender's mtu may be bigger yet. + XXX This must be dealt with later XXX + */ + + /* max payload size */ + pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu) + : (65520 - iphlen); + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_decompress: " + "max payload size: %d\n", pyldsz); + + while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) && + (nskb = skb_copy_ipcomp(skb, + pyldsz - cpyldsz - sizeof(struct ipcomphdr), + GFP_ATOMIC)) == NULL) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), " + "trying with less payload size.\n", + (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr))); + pyldsz >>=1; + } + + if (!nskb) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "unable to allocate memory, dropping packet.\n"); + *flags |= IPCOMP_DECOMPRESSIONERROR; + inflateEnd(&zs); + + return skb; + } + +#ifdef CONFIG_IPSEC_DEBUG + if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) { + __u8 *c; + int i; + + c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr); + for(i = 0; i < cpyldsz; i++, c++) { + if(!(i % 16)) { + printk(KERN_INFO "skb_decompress: before:"); + } + printk("%02x ", *c); + if(!((i + 1) % 16)) { + printk("\n"); + } + } + if(i % 16) { + printk("\n"); + } + } +#endif /* CONFIG_IPSEC_DEBUG */ + +#ifdef NET_21 + iph = nskb->nh.iph; +#else /* NET_21 */ + iph = nskb->ip_hdr; +#endif /* NET_21 */ + zs.next_out = (char *)iph + iphlen; + zs.avail_out = pyldsz; + + zresult = inflate(&zs, Z_SYNC_FLUSH); + + /* work around a bug in zlib, which sometimes wants to taste an extra + * byte when being used in the (undocumented) raw deflate mode. + */ + if (zresult == Z_OK && !zs.avail_in && zs.avail_out) { + __u8 zerostuff = 0; + + zs.next_in = &zerostuff; + zs.avail_in = 1; + zresult = inflate(&zs, Z_FINISH); + } + + inflateEnd(&zs); + if (zresult != Z_STREAM_END) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_error:skb_decompress: " + "inflate() returned error %d (%s), " + "skipping decompression.\n", + zresult, + zs.msg ? zs.msg : zError(zresult)); + *flags |= IPCOMP_DECOMPRESSIONERROR; + ipsec_kfree_skb(nskb); + + return skb; + } + + /* Update IP header */ + /* resulting decompressed size */ + pyldsz -= zs.avail_out; + iph->tot_len = htons(iphlen + pyldsz); + iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh; + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_decompress: " + "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n", + ips ? ntohl(ips->ips_said.spi) : 0, + ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0, + ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi), + cpyldsz, + pyldsz, + iph->protocol); + +#if 1 /* XXX checksum is done by ipsec_rcv ? */ + iph->check = 0; + iph->check = ip_fast_csum((char*) iph, iph->ihl); +#endif + + /* Update skb length/tail by "unputting" the unused data area */ + skb_put(nskb, -zs.avail_out); + + ipsec_kfree_skb(skb); + + if (iph->protocol == IPPROTO_COMP) + { +#ifdef CONFIG_IPSEC_DEBUG + if(sysctl_ipsec_debug_ipcomp) + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_decompress: " + "Eh? inner packet is also compressed, dropping.\n"); +#endif /* CONFIG_IPSEC_DEBUG */ + + ipsec_kfree_skb(nskb); + return NULL; + } + +#ifdef CONFIG_IPSEC_DEBUG + if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) { + __u8 *c; + int i; + + c = (__u8*)iph + iphlen; + for(i = 0; i < pyldsz; i++, c++) { + if(!(i % 16)) { + printk(KERN_INFO "skb_decompress: result:"); + } + printk("%02x ", *c); + if(!((i + 1) % 16)) { + printk("\n"); + } + } + if(i % 16) { + printk("\n"); + } + } +#endif /* CONFIG_IPSEC_DEBUG */ + + return nskb; +} + + +/* this is derived from skb_copy() in linux 2.2.14 */ +/* May be incompatible with other kernel versions!! */ +static +struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask) +{ + struct sk_buff *n; + struct iphdr *iph; + unsigned long offset; + unsigned int iphlen; + + if(!skb) { + KLIPS_PRINT(sysctl_ipsec_debug_ipcomp, + "klips_debug:skb_copy_ipcomp: " + "passed in NULL skb, returning NULL.\n"); + return NULL; + } + + /* + * Allocate the copy buffer + */ + +#ifdef NET_21 + iph = skb->nh.iph; +#else /* NET_21 */ + iph = skb->ip_hdr; +#endif /* NET_21 */ + if (!iph) return NULL; + iphlen = iph->ihl << 2; + + n=alloc_skb(skb->end - skb->head + data_growth, gfp_mask); + if(n==NULL) + return NULL; + + /* + * Shift between the two data areas in bytes + */ + + offset=n->head-skb->head; + + /* Set the data pointer */ + skb_reserve(n,skb->data-skb->head); + /* Set the tail pointer and length */ + skb_put(n,skb->len+data_growth); + /* Copy the bytes up to and including the ip header */ + memcpy(n->head, + skb->head, + ((char *)iph - (char *)skb->head) + iphlen); + n->list=NULL; + n->next=NULL; + n->prev=NULL; + n->sk=NULL; + n->dev=skb->dev; + if (skb->h.raw) + n->h.raw=skb->h.raw+offset; + else + n->h.raw=NULL; + n->protocol=skb->protocol; +#ifdef NET_21 + n->csum = 0; + n->priority=skb->priority; + n->dst=dst_clone(skb->dst); + n->nh.raw=skb->nh.raw+offset; +#ifndef NETDEV_23 + n->is_clone=0; +#endif /* NETDEV_23 */ + atomic_set(&n->users, 1); + n->destructor = NULL; + n->security=skb->security; + memcpy(n->cb, skb->cb, sizeof(skb->cb)); +#ifdef CONFIG_IP_FIREWALL + n->fwmark = skb->fwmark; +#endif +#else /* NET_21 */ + n->link3=NULL; + n->when=skb->when; + n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset); + n->saddr=skb->saddr; + n->daddr=skb->daddr; + n->raddr=skb->raddr; + n->seq=skb->seq; + n->end_seq=skb->end_seq; + n->ack_seq=skb->ack_seq; + n->acked=skb->acked; + n->free=1; + n->arp=skb->arp; + n->tries=0; + n->lock=0; + n->users=0; + memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); +#endif /* NET_21 */ + if (skb->mac.raw) + n->mac.raw=skb->mac.raw+offset; + else + n->mac.raw=NULL; +#ifndef NETDEV_23 + n->used=skb->used; +#endif /* !NETDEV_23 */ + n->pkt_type=skb->pkt_type; +#ifndef NETDEV_23 + n->pkt_bridged=skb->pkt_bridged; +#endif /* NETDEV_23 */ + n->ip_summed=0; + n->stamp=skb->stamp; +#ifndef NETDEV_23 /* this seems to have been removed in 2.4 */ +#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) + n->shapelatency=skb->shapelatency; /* Latency on frame */ + n->shapeclock=skb->shapeclock; /* Time it should go out */ + n->shapelen=skb->shapelen; /* Frame length in clocks */ + n->shapestamp=skb->shapestamp; /* Stamp for shaper */ + n->shapepend=skb->shapepend; /* Pending */ +#endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */ +#endif /* NETDEV_23 */ +#ifdef CONFIG_HIPPI + n->private.ifield=skb->private.ifield; +#endif /* CONFIG_HIPPI */ + + return n; +} |