]> git.ipfire.org Git - people/ms/strongswan.git/blob - linux/net/ipsec/ipcomp.c
ff12f2cddc32466eff7b956d66a20130eadc6a8c
[people/ms/strongswan.git] / linux / net / ipsec / ipcomp.c
1 /*
2 * IPCOMP zlib interface code.
3 * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
4 * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 char ipcomp_c_version[] = "RCSID $Id: ipcomp.c,v 1.2 2004/06/13 19:57:49 as Exp $";
18
19 /* SSS */
20
21 #include <linux/config.h>
22 #include <linux/version.h>
23
24 #define __NO_VERSION__
25 #include <linux/module.h>
26 #include <linux/kernel.h> /* printk() */
27
28 #include "freeswan/ipsec_param.h"
29
30 #ifdef MALLOC_SLAB
31 # include <linux/slab.h> /* kmalloc() */
32 #else /* MALLOC_SLAB */
33 # include <linux/malloc.h> /* kmalloc() */
34 #endif /* MALLOC_SLAB */
35 #include <linux/errno.h> /* error codes */
36 #include <linux/types.h>
37 #include <linux/netdevice.h>
38 #include <linux/ip.h>
39 #include <linux/skbuff.h>
40
41 #include <linux/netdevice.h> /* struct device, and other headers */
42 #include <linux/etherdevice.h> /* eth_type_trans */
43 #include <linux/ip.h> /* struct iphdr */
44 #include <linux/skbuff.h>
45
46 #include <freeswan.h>
47
48 #ifdef NET_21
49 # include <net/dst.h>
50 # include <asm/uaccess.h>
51 # include <linux/in6.h>
52 # define proto_priv cb
53 #endif /* NET21 */
54 #include <asm/checksum.h>
55 #include <net/ip.h>
56
57 #include "freeswan/radij.h"
58 #include "freeswan/ipsec_encap.h"
59 #include "freeswan/ipsec_sa.h"
60
61 #include "freeswan/ipsec_xform.h"
62 #include "freeswan/ipsec_tunnel.h"
63 #include "freeswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */
64 #include "freeswan/ipcomp.h"
65 #include "zlib/zlib.h"
66 #include "zlib/zutil.h"
67
68 #include <pfkeyv2.h> /* SADB_X_CALG_DEFLATE */
69
70 #ifdef CONFIG_IPSEC_DEBUG
71 int sysctl_ipsec_debug_ipcomp = 0;
72 #endif /* CONFIG_IPSEC_DEBUG */
73
74 static
75 struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask);
76
77 static
78 voidpf my_zcalloc(voidpf opaque, uInt items, uInt size)
79 {
80 return (voidpf) kmalloc(items*size, GFP_ATOMIC);
81 }
82
83 static
84 void my_zfree(voidpf opaque, voidpf address)
85 {
86 kfree(address);
87 }
88
89 struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
90 {
91 struct iphdr *iph;
92 unsigned int iphlen, pyldsz, cpyldsz;
93 unsigned char *buffer;
94 z_stream zs;
95 int zresult;
96
97 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
98 "klips_debug:skb_compress: .\n");
99
100 if(skb == NULL) {
101 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
102 "klips_debug:skb_compress: "
103 "passed in NULL skb, returning ERROR.\n");
104 if(flags != NULL) {
105 *flags |= IPCOMP_PARMERROR;
106 }
107 return skb;
108 }
109
110 if(ips == NULL) {
111 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
112 "klips_debug:skb_compress: "
113 "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n");
114 if(flags) {
115 *flags |= IPCOMP_PARMERROR;
116 }
117 return skb;
118 }
119
120 if (flags == NULL) {
121 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
122 "klips_debug:skb_compress: "
123 "passed in NULL flags, returning ERROR.\n");
124 ipsec_kfree_skb(skb);
125 return NULL;
126 }
127
128 #ifdef NET_21
129 iph = skb->nh.iph;
130 #else /* NET_21 */
131 iph = skb->ip_hdr;
132 #endif /* NET_21 */
133
134 switch (iph->protocol) {
135 case IPPROTO_COMP:
136 case IPPROTO_AH:
137 case IPPROTO_ESP:
138 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
139 "klips_debug:skb_compress: "
140 "skipping compression of packet with ip protocol %d.\n",
141 iph->protocol);
142 *flags |= IPCOMP_UNCOMPRESSABLE;
143 return skb;
144 }
145
146 /* Don't compress packets already fragmented */
147 if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) {
148 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
149 "klips_debug:skb_compress: "
150 "skipping compression of fragmented packet.\n");
151 *flags |= IPCOMP_UNCOMPRESSABLE;
152 return skb;
153 }
154
155 iphlen = iph->ihl << 2;
156 pyldsz = ntohs(iph->tot_len) - iphlen;
157
158 /* Don't compress less than 90 bytes (rfc 2394) */
159 if (pyldsz < 90) {
160 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
161 "klips_debug:skb_compress: "
162 "skipping compression of tiny packet, len=%d.\n",
163 pyldsz);
164 *flags |= IPCOMP_UNCOMPRESSABLE;
165 return skb;
166 }
167
168 /* Adaptive decision */
169 if (ips->ips_comp_adapt_skip) {
170 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
171 "klips_debug:skb_compress: "
172 "skipping compression: ips_comp_adapt_skip=%d.\n",
173 ips->ips_comp_adapt_skip);
174 ips->ips_comp_adapt_skip--;
175 *flags |= IPCOMP_UNCOMPRESSABLE;
176 return skb;
177 }
178
179 zs.zalloc = my_zcalloc;
180 zs.zfree = my_zfree;
181 zs.opaque = 0;
182
183 /* We want to use deflateInit2 because we don't want the adler
184 header. */
185 zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11,
186 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
187 if (zresult != Z_OK) {
188 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
189 "klips_error:skb_compress: "
190 "deflateInit2() returned error %d (%s), "
191 "skipping compression.\n",
192 zresult,
193 zs.msg ? zs.msg : zError(zresult));
194 *flags |= IPCOMP_COMPRESSIONERROR;
195 return skb;
196 }
197
198
199 /* Max output size. Result should be max this size.
200 * Implementation specific tweak:
201 * If it's not at least 32 bytes and 6.25% smaller than
202 * the original packet, it's probably not worth wasting
203 * the receiver's CPU cycles decompressing it.
204 * Your mileage may vary.
205 */
206 cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4);
207
208 buffer = kmalloc(cpyldsz, GFP_ATOMIC);
209 if (!buffer) {
210 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
211 "klips_error:skb_compress: "
212 "unable to kmalloc(%d, GFP_ATOMIC), "
213 "skipping compression.\n",
214 cpyldsz);
215 *flags |= IPCOMP_COMPRESSIONERROR;
216 deflateEnd(&zs);
217 return skb;
218 }
219
220 #ifdef CONFIG_IPSEC_DEBUG
221 if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
222 __u8 *c;
223 int i;
224
225 c = (__u8*)iph + iphlen;
226 for(i = 0; i < pyldsz; i++, c++) {
227 if(!(i % 16)) {
228 printk(KERN_INFO "skb_compress: before:");
229 }
230 printk("%02x ", *c);
231 if(!((i + 1) % 16)) {
232 printk("\n");
233 }
234 }
235 if(i % 16) {
236 printk("\n");
237 }
238 }
239 #endif /* CONFIG_IPSEC_DEBUG */
240
241 zs.next_in = (char *) iph + iphlen; /* start of payload */
242 zs.avail_in = pyldsz;
243 zs.next_out = buffer; /* start of compressed payload */
244 zs.avail_out = cpyldsz;
245
246 /* Finish compression in one step */
247 zresult = deflate(&zs, Z_FINISH);
248
249 /* Free all dynamically allocated buffers */
250 deflateEnd(&zs);
251 if (zresult != Z_STREAM_END) {
252 *flags |= IPCOMP_UNCOMPRESSABLE;
253 kfree(buffer);
254
255 /* Adjust adaptive counters */
256 if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) {
257 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
258 "klips_debug:skb_compress: "
259 "first %d packets didn't compress, "
260 "skipping next %d\n",
261 IPCOMP_ADAPT_INITIAL_TRIES,
262 IPCOMP_ADAPT_INITIAL_SKIP);
263 ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP;
264 }
265 else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) {
266 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
267 "klips_debug:skb_compress: "
268 "next %d packets didn't compress, "
269 "skipping next %d\n",
270 IPCOMP_ADAPT_SUBSEQ_TRIES,
271 IPCOMP_ADAPT_SUBSEQ_SKIP);
272 ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP;
273 ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES;
274 }
275
276 return skb;
277 }
278
279 /* resulting compressed size */
280 cpyldsz -= zs.avail_out;
281
282 /* Insert IPCOMP header */
283 ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol;
284 ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0;
285 /* use the bottom 16 bits of the spi for the cpi. The top 16 bits are
286 for internal reference only. */
287 ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff));
288 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
289 "klips_debug:skb_compress: "
290 "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n",
291 ntohl(ips->ips_said.spi),
292 ntohl(ips->ips_said.spi) & 0x0000ffff,
293 ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi),
294 pyldsz,
295 cpyldsz);
296
297 /* Update IP header */
298 iph->protocol = IPPROTO_COMP;
299 iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz);
300 #if 1 /* XXX checksum is done by ipsec_tunnel ? */
301 iph->check = 0;
302 iph->check = ip_fast_csum((char *) iph, iph->ihl);
303 #endif
304
305 /* Copy compressed payload */
306 memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr),
307 buffer,
308 cpyldsz);
309 kfree(buffer);
310
311 /* Update skb length/tail by "unputting" the shrinkage */
312 skb_put(skb,
313 cpyldsz + sizeof(struct ipcomphdr) - pyldsz);
314
315 #ifdef CONFIG_IPSEC_DEBUG
316 if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
317 __u8 *c;
318 int i;
319
320 c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr);
321 for(i = 0; i < cpyldsz; i++, c++) {
322 if(!(i % 16)) {
323 printk(KERN_INFO "skb_compress: result:");
324 }
325 printk("%02x ", *c);
326 if(!((i + 1) % 16)) {
327 printk("\n");
328 }
329 }
330 if(i % 16) {
331 printk("\n");
332 }
333 }
334 #endif /* CONFIG_IPSEC_DEBUG */
335
336 ips->ips_comp_adapt_skip = 0;
337 ips->ips_comp_adapt_tries = 0;
338
339 return skb;
340 }
341
342 struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
343 {
344 struct sk_buff *nskb = NULL;
345
346 /* original ip header */
347 struct iphdr *oiph, *iph;
348 unsigned int iphlen, pyldsz, cpyldsz;
349 z_stream zs;
350 int zresult;
351
352 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
353 "klips_debug:skb_decompress: .\n");
354
355 if(!skb) {
356 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
357 "klips_error:skb_decompress: "
358 "passed in NULL skb, returning ERROR.\n");
359 if (flags) *flags |= IPCOMP_PARMERROR;
360 return skb;
361 }
362
363 if(!ips && sysctl_ipsec_inbound_policy_check) {
364 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
365 "klips_error:skb_decompress: "
366 "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n");
367 if (flags) *flags |= IPCOMP_PARMERROR;
368 return skb;
369 }
370
371 if (!flags) {
372 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
373 "klips_error:skb_decompress: "
374 "passed in NULL flags, returning ERROR.\n");
375 ipsec_kfree_skb(skb);
376 return NULL;
377 }
378
379 #ifdef NET_21
380 oiph = skb->nh.iph;
381 #else /* NET_21 */
382 oiph = skb->ip_hdr;
383 #endif /* NET_21 */
384
385 iphlen = oiph->ihl << 2;
386
387 if (oiph->protocol != IPPROTO_COMP) {
388 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
389 "klips_error:skb_decompress: "
390 "called with non-IPCOMP packet (protocol=%d),"
391 "skipping decompression.\n",
392 oiph->protocol);
393 *flags |= IPCOMP_PARMERROR;
394 return skb;
395 }
396
397 if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0)
398 || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi
399 != htons(SADB_X_CALG_DEFLATE))
400 && sysctl_ipsec_inbound_policy_check
401 && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) {
402 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
403 "klips_error:skb_decompress: "
404 "called with incompatible IPCOMP packet (flags=%d, "
405 "cpi=%d), ips-compalg=%d, skipping decompression.\n",
406 ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags),
407 ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi),
408 ips ? ips->ips_encalg : 0);
409 *flags |= IPCOMP_PARMERROR;
410
411 return skb;
412 }
413
414 if (ntohs(oiph->frag_off) & ~0x4000) {
415 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
416 "klips_error:skb_decompress: "
417 "called with fragmented IPCOMP packet, "
418 "skipping decompression.\n");
419 *flags |= IPCOMP_PARMERROR;
420 return skb;
421 }
422
423 /* original compressed payload size */
424 cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr);
425
426 zs.zalloc = my_zcalloc;
427 zs.zfree = my_zfree;
428 zs.opaque = 0;
429
430 zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr);
431 zs.avail_in = cpyldsz;
432
433 /* Maybe we should be a bit conservative about memory
434 requirements and use inflateInit2 */
435 /* Beware, that this might make us unable to decompress packets
436 from other implementations - HINT: check PGPnet source code */
437 /* We want to use inflateInit2 because we don't want the adler
438 header. */
439 zresult = inflateInit2(&zs, -15);
440 if (zresult != Z_OK) {
441 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
442 "klips_error:skb_decompress: "
443 "inflateInit2() returned error %d (%s), "
444 "skipping decompression.\n",
445 zresult,
446 zs.msg ? zs.msg : zError(zresult));
447 *flags |= IPCOMP_DECOMPRESSIONERROR;
448
449 return skb;
450 }
451
452 /* We have no way of knowing the exact length of the resulting
453 decompressed output before we have actually done the decompression.
454 For now, we guess that the packet will not be bigger than the
455 attached ipsec device's mtu or 16260, whichever is biggest.
456 This may be wrong, since the sender's mtu may be bigger yet.
457 XXX This must be dealt with later XXX
458 */
459
460 /* max payload size */
461 pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu)
462 : (65520 - iphlen);
463 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
464 "klips_debug:skb_decompress: "
465 "max payload size: %d\n", pyldsz);
466
467 while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) &&
468 (nskb = skb_copy_ipcomp(skb,
469 pyldsz - cpyldsz - sizeof(struct ipcomphdr),
470 GFP_ATOMIC)) == NULL) {
471 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
472 "klips_error:skb_decompress: "
473 "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), "
474 "trying with less payload size.\n",
475 (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr)));
476 pyldsz >>=1;
477 }
478
479 if (!nskb) {
480 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
481 "klips_error:skb_decompress: "
482 "unable to allocate memory, dropping packet.\n");
483 *flags |= IPCOMP_DECOMPRESSIONERROR;
484 inflateEnd(&zs);
485
486 return skb;
487 }
488
489 #ifdef CONFIG_IPSEC_DEBUG
490 if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
491 __u8 *c;
492 int i;
493
494 c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr);
495 for(i = 0; i < cpyldsz; i++, c++) {
496 if(!(i % 16)) {
497 printk(KERN_INFO "skb_decompress: before:");
498 }
499 printk("%02x ", *c);
500 if(!((i + 1) % 16)) {
501 printk("\n");
502 }
503 }
504 if(i % 16) {
505 printk("\n");
506 }
507 }
508 #endif /* CONFIG_IPSEC_DEBUG */
509
510 #ifdef NET_21
511 iph = nskb->nh.iph;
512 #else /* NET_21 */
513 iph = nskb->ip_hdr;
514 #endif /* NET_21 */
515 zs.next_out = (char *)iph + iphlen;
516 zs.avail_out = pyldsz;
517
518 zresult = inflate(&zs, Z_SYNC_FLUSH);
519
520 /* work around a bug in zlib, which sometimes wants to taste an extra
521 * byte when being used in the (undocumented) raw deflate mode.
522 */
523 if (zresult == Z_OK && !zs.avail_in && zs.avail_out) {
524 __u8 zerostuff = 0;
525
526 zs.next_in = &zerostuff;
527 zs.avail_in = 1;
528 zresult = inflate(&zs, Z_FINISH);
529 }
530
531 inflateEnd(&zs);
532 if (zresult != Z_STREAM_END) {
533 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
534 "klips_error:skb_decompress: "
535 "inflate() returned error %d (%s), "
536 "skipping decompression.\n",
537 zresult,
538 zs.msg ? zs.msg : zError(zresult));
539 *flags |= IPCOMP_DECOMPRESSIONERROR;
540 ipsec_kfree_skb(nskb);
541
542 return skb;
543 }
544
545 /* Update IP header */
546 /* resulting decompressed size */
547 pyldsz -= zs.avail_out;
548 iph->tot_len = htons(iphlen + pyldsz);
549 iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh;
550 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
551 "klips_debug:skb_decompress: "
552 "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n",
553 ips ? ntohl(ips->ips_said.spi) : 0,
554 ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0,
555 ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi),
556 cpyldsz,
557 pyldsz,
558 iph->protocol);
559
560 #if 1 /* XXX checksum is done by ipsec_rcv ? */
561 iph->check = 0;
562 iph->check = ip_fast_csum((char*) iph, iph->ihl);
563 #endif
564
565 /* Update skb length/tail by "unputting" the unused data area */
566 skb_put(nskb, -zs.avail_out);
567
568 ipsec_kfree_skb(skb);
569
570 if (iph->protocol == IPPROTO_COMP)
571 {
572 #ifdef CONFIG_IPSEC_DEBUG
573 if(sysctl_ipsec_debug_ipcomp)
574 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
575 "klips_debug:skb_decompress: "
576 "Eh? inner packet is also compressed, dropping.\n");
577 #endif /* CONFIG_IPSEC_DEBUG */
578
579 ipsec_kfree_skb(nskb);
580 return NULL;
581 }
582
583 #ifdef CONFIG_IPSEC_DEBUG
584 if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
585 __u8 *c;
586 int i;
587
588 c = (__u8*)iph + iphlen;
589 for(i = 0; i < pyldsz; i++, c++) {
590 if(!(i % 16)) {
591 printk(KERN_INFO "skb_decompress: result:");
592 }
593 printk("%02x ", *c);
594 if(!((i + 1) % 16)) {
595 printk("\n");
596 }
597 }
598 if(i % 16) {
599 printk("\n");
600 }
601 }
602 #endif /* CONFIG_IPSEC_DEBUG */
603
604 return nskb;
605 }
606
607
608 /* this is derived from skb_copy() in linux 2.2.14 */
609 /* May be incompatible with other kernel versions!! */
610 static
611 struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask)
612 {
613 struct sk_buff *n;
614 struct iphdr *iph;
615 unsigned long offset;
616 unsigned int iphlen;
617
618 if(!skb) {
619 KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
620 "klips_debug:skb_copy_ipcomp: "
621 "passed in NULL skb, returning NULL.\n");
622 return NULL;
623 }
624
625 /*
626 * Allocate the copy buffer
627 */
628
629 #ifdef NET_21
630 iph = skb->nh.iph;
631 #else /* NET_21 */
632 iph = skb->ip_hdr;
633 #endif /* NET_21 */
634 if (!iph) return NULL;
635 iphlen = iph->ihl << 2;
636
637 n=alloc_skb(skb->end - skb->head + data_growth, gfp_mask);
638 if(n==NULL)
639 return NULL;
640
641 /*
642 * Shift between the two data areas in bytes
643 */
644
645 offset=n->head-skb->head;
646
647 /* Set the data pointer */
648 skb_reserve(n,skb->data-skb->head);
649 /* Set the tail pointer and length */
650 skb_put(n,skb->len+data_growth);
651 /* Copy the bytes up to and including the ip header */
652 memcpy(n->head,
653 skb->head,
654 ((char *)iph - (char *)skb->head) + iphlen);
655 n->list=NULL;
656 n->next=NULL;
657 n->prev=NULL;
658 n->sk=NULL;
659 n->dev=skb->dev;
660 if (skb->h.raw)
661 n->h.raw=skb->h.raw+offset;
662 else
663 n->h.raw=NULL;
664 n->protocol=skb->protocol;
665 #ifdef NET_21
666 n->csum = 0;
667 n->priority=skb->priority;
668 n->dst=dst_clone(skb->dst);
669 n->nh.raw=skb->nh.raw+offset;
670 #ifndef NETDEV_23
671 n->is_clone=0;
672 #endif /* NETDEV_23 */
673 atomic_set(&n->users, 1);
674 n->destructor = NULL;
675 n->security=skb->security;
676 memcpy(n->cb, skb->cb, sizeof(skb->cb));
677 #ifdef CONFIG_IP_FIREWALL
678 n->fwmark = skb->fwmark;
679 #endif
680 #else /* NET_21 */
681 n->link3=NULL;
682 n->when=skb->when;
683 n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
684 n->saddr=skb->saddr;
685 n->daddr=skb->daddr;
686 n->raddr=skb->raddr;
687 n->seq=skb->seq;
688 n->end_seq=skb->end_seq;
689 n->ack_seq=skb->ack_seq;
690 n->acked=skb->acked;
691 n->free=1;
692 n->arp=skb->arp;
693 n->tries=0;
694 n->lock=0;
695 n->users=0;
696 memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
697 #endif /* NET_21 */
698 if (skb->mac.raw)
699 n->mac.raw=skb->mac.raw+offset;
700 else
701 n->mac.raw=NULL;
702 #ifndef NETDEV_23
703 n->used=skb->used;
704 #endif /* !NETDEV_23 */
705 n->pkt_type=skb->pkt_type;
706 #ifndef NETDEV_23
707 n->pkt_bridged=skb->pkt_bridged;
708 #endif /* NETDEV_23 */
709 n->ip_summed=0;
710 n->stamp=skb->stamp;
711 #ifndef NETDEV_23 /* this seems to have been removed in 2.4 */
712 #if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
713 n->shapelatency=skb->shapelatency; /* Latency on frame */
714 n->shapeclock=skb->shapeclock; /* Time it should go out */
715 n->shapelen=skb->shapelen; /* Frame length in clocks */
716 n->shapestamp=skb->shapestamp; /* Stamp for shaper */
717 n->shapepend=skb->shapepend; /* Pending */
718 #endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */
719 #endif /* NETDEV_23 */
720 #ifdef CONFIG_HIPPI
721 n->private.ifield=skb->private.ifield;
722 #endif /* CONFIG_HIPPI */
723
724 return n;
725 }