]> git.ipfire.org Git - people/ms/strongswan.git/blob - linux/net/ipsec/ipsec_sa.c
(no commit message)
[people/ms/strongswan.git] / linux / net / ipsec / ipsec_sa.c
1 /*
2 * Common routines for IPsec SA maintenance routines.
3 *
4 * Copyright (C) 1996, 1997 John Ioannidis.
5 * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * RCSID $Id: ipsec_sa.c,v 1.3 2004/06/13 19:57:50 as Exp $
18 *
19 * This is the file formerly known as "ipsec_xform.h"
20 *
21 */
22
23 #include <linux/config.h>
24 #include <linux/version.h>
25 #include <linux/kernel.h> /* printk() */
26
27 #include "freeswan/ipsec_param.h"
28
29 #ifdef MALLOC_SLAB
30 # include <linux/slab.h> /* kmalloc() */
31 #else /* MALLOC_SLAB */
32 # include <linux/malloc.h> /* kmalloc() */
33 #endif /* MALLOC_SLAB */
34 #include <linux/vmalloc.h> /* vmalloc() */
35 #include <linux/errno.h> /* error codes */
36 #include <linux/types.h> /* size_t */
37 #include <linux/interrupt.h> /* mark_bh */
38
39 #include <linux/netdevice.h> /* struct device, and other headers */
40 #include <linux/etherdevice.h> /* eth_type_trans */
41 #include <linux/ip.h> /* struct iphdr */
42 #include <linux/skbuff.h>
43 #include <freeswan.h>
44 #ifdef SPINLOCK
45 #ifdef SPINLOCK_23
46 #include <linux/spinlock.h> /* *lock* */
47 #else /* SPINLOCK_23 */
48 #include <asm/spinlock.h> /* *lock* */
49 #endif /* SPINLOCK_23 */
50 #endif /* SPINLOCK */
51 #ifdef NET_21
52 #include <asm/uaccess.h>
53 #include <linux/in6.h>
54 #endif
55 #include <asm/checksum.h>
56 #include <net/ip.h>
57
58 #include "freeswan/radij.h"
59
60 #include "freeswan/ipsec_stats.h"
61 #include "freeswan/ipsec_life.h"
62 #include "freeswan/ipsec_sa.h"
63 #include "freeswan/ipsec_xform.h"
64
65 #include "freeswan/ipsec_encap.h"
66 #include "freeswan/ipsec_radij.h"
67 #include "freeswan/ipsec_xform.h"
68 #include "freeswan/ipsec_ipe4.h"
69 #include "freeswan/ipsec_ah.h"
70 #include "freeswan/ipsec_esp.h"
71
72 #include <pfkeyv2.h>
73 #include <pfkey.h>
74
75 #include "freeswan/ipsec_proto.h"
76 #include "freeswan/ipsec_alg.h"
77
78
79 #ifdef CONFIG_IPSEC_DEBUG
80 int debug_xform = 0;
81 #endif /* CONFIG_IPSEC_DEBUG */
82
83 #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
84
85 struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
86 #ifdef SPINLOCK
87 spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
88 #else /* SPINLOCK */
89 spinlock_t tdb_lock;
90 #endif /* SPINLOCK */
91
92 struct ipsec_sadb ipsec_sadb;
93
94 #if IPSEC_SA_REF_CODE
95
96 /* the sub table must be narrower (or equal) in bits than the variable type
97 in the main table to count the number of unused entries in it. */
98 typedef struct {
99 int testSizeOf_refSubTable :
100 ((sizeof(IPsecRefTableUnusedCount) * 8) < IPSEC_SA_REF_SUBTABLE_IDX_WIDTH ? -1 : 1);
101 } dummy;
102
103
104 /* The field where the saref will be hosted in the skb must be wide enough to
105 accomodate the information it needs to store. */
106 typedef struct {
107 int testSizeOf_refField :
108 (IPSEC_SA_REF_HOST_FIELD_WIDTH < IPSEC_SA_REF_TABLE_IDX_WIDTH ? -1 : 1 );
109 } dummy2;
110
111
112 void
113 ipsec_SAtest(void)
114 {
115 IPsecSAref_t SAref = 258;
116 struct ipsec_sa ips;
117 ips.ips_ref = 772;
118
119 printk("klips_debug:ipsec_SAtest: "
120 "IPSEC_SA_REF_SUBTABLE_IDX_WIDTH=%u\n"
121 "IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES=%u\n"
122 "IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES=%u\n"
123 "IPSEC_SA_REF_HOST_FIELD_WIDTH=%lu\n"
124 "IPSEC_SA_REF_TABLE_MASK=%x\n"
125 "IPSEC_SA_REF_ENTRY_MASK=%x\n"
126 "IPsecSAref2table(%d)=%u\n"
127 "IPsecSAref2entry(%d)=%u\n"
128 "IPsecSAref2NFmark(%d)=%u\n"
129 "IPsecSAref2SA(%d)=%p\n"
130 "IPsecSA2SAref(%p)=%d\n"
131 ,
132 IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
133 IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
134 IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
135 (unsigned long) IPSEC_SA_REF_HOST_FIELD_WIDTH,
136 IPSEC_SA_REF_TABLE_MASK,
137 IPSEC_SA_REF_ENTRY_MASK,
138 SAref, IPsecSAref2table(SAref),
139 SAref, IPsecSAref2entry(SAref),
140 SAref, IPsecSAref2NFmark(SAref),
141 SAref, IPsecSAref2SA(SAref),
142 (&ips), IPsecSA2SAref((&ips))
143 );
144 return;
145 }
146
147 int
148 ipsec_SAref_recycle(void)
149 {
150 int table;
151 int entry;
152 int error = 0;
153
154 ipsec_sadb.refFreeListHead = -1;
155 ipsec_sadb.refFreeListTail = -1;
156
157 if(ipsec_sadb.refFreeListCont == IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
158 KLIPS_PRINT(debug_xform,
159 "klips_debug:ipsec_SAref_recycle: "
160 "end of table reached, continuing at start..\n");
161 ipsec_sadb.refFreeListCont = 0;
162 }
163
164 KLIPS_PRINT(debug_xform,
165 "klips_debug:ipsec_SAref_recycle: "
166 "recycling, continuing from SAref=%d (0p%p), table=%d, entry=%d.\n",
167 ipsec_sadb.refFreeListCont,
168 (ipsec_sadb.refTable[IPsecSAref2table(ipsec_sadb.refFreeListCont)] != NULL) ? IPsecSAref2SA(ipsec_sadb.refFreeListCont) : NULL,
169 IPsecSAref2table(ipsec_sadb.refFreeListCont),
170 IPsecSAref2entry(ipsec_sadb.refFreeListCont));
171
172 for(table = IPsecSAref2table(ipsec_sadb.refFreeListCont);
173 table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES;
174 table++) {
175 if(ipsec_sadb.refTable[table] == NULL) {
176 error = ipsec_SArefSubTable_alloc(table);
177 if(error) {
178 return error;
179 }
180 }
181 for(entry = IPsecSAref2entry(ipsec_sadb.refFreeListCont);
182 entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES;
183 entry++) {
184 if(ipsec_sadb.refTable[table]->entry[entry] == NULL) {
185 ipsec_sadb.refFreeList[++ipsec_sadb.refFreeListTail] = IPsecSArefBuild(table, entry);
186 if(ipsec_sadb.refFreeListTail == (IPSEC_SA_REF_FREELIST_NUM_ENTRIES - 1)) {
187 ipsec_sadb.refFreeListHead = 0;
188 ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
189 KLIPS_PRINT(debug_xform,
190 "klips_debug:ipsec_SAref_recycle: "
191 "SArefFreeList refilled.\n");
192 return 0;
193 }
194 }
195 }
196 }
197
198 if(ipsec_sadb.refFreeListTail == -1) {
199 KLIPS_PRINT(debug_xform,
200 "klips_debug:ipsec_SAref_recycle: "
201 "out of room in the SArefTable.\n");
202
203 return(-ENOSPC);
204 }
205
206 ipsec_sadb.refFreeListHead = 0;
207 ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
208 KLIPS_PRINT(debug_xform,
209 "klips_debug:ipsec_SAref_recycle: "
210 "SArefFreeList partly refilled to %d of %d.\n",
211 ipsec_sadb.refFreeListTail,
212 IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
213 return 0;
214 }
215
216 int
217 ipsec_SArefSubTable_alloc(unsigned table)
218 {
219 unsigned entry;
220 struct IPsecSArefSubTable* SArefsub;
221
222 KLIPS_PRINT(debug_xform,
223 "klips_debug:ipsec_SArefSubTable_alloc: "
224 "allocating %lu bytes for table %u of %u.\n",
225 (unsigned long) (IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *)),
226 table,
227 IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
228
229 /* allocate another sub-table */
230 SArefsub = vmalloc(IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *));
231 if(SArefsub == NULL) {
232 KLIPS_PRINT(debug_xform,
233 "klips_debug:ipsec_SArefSubTable_alloc: "
234 "error allocating memory for table %u of %u!\n",
235 table,
236 IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
237 return -ENOMEM;
238 }
239
240 /* add this sub-table to the main table */
241 ipsec_sadb.refTable[table] = SArefsub;
242
243 /* initialise each element to NULL */
244 KLIPS_PRINT(debug_xform,
245 "klips_debug:ipsec_SArefSubTable_alloc: "
246 "initialising %u elements (2 ^ %u) of table %u.\n",
247 IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
248 IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
249 table);
250 for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
251 SArefsub->entry[entry] = NULL;
252 }
253
254 return 0;
255 }
256 #endif /* IPSEC_SA_REF_CODE */
257
258 int
259 ipsec_saref_freelist_init(void)
260 {
261 int i;
262
263 KLIPS_PRINT(debug_xform,
264 "klips_debug:ipsec_saref_freelist_init: "
265 "initialising %u elements of FreeList.\n",
266 IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
267
268 for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
269 ipsec_sadb.refFreeList[i] = IPSEC_SAREF_NULL;
270 }
271 ipsec_sadb.refFreeListHead = -1;
272 ipsec_sadb.refFreeListCont = 0;
273 ipsec_sadb.refFreeListTail = -1;
274
275 return 0;
276 }
277
278 int
279 ipsec_sadb_init(void)
280 {
281 int error = 0;
282 unsigned i;
283
284 for(i = 0; i < SADB_HASHMOD; i++) {
285 ipsec_sadb_hash[i] = NULL;
286 }
287 /* parts above are for the old style SADB hash table */
288
289
290 #if IPSEC_SA_REF_CODE
291 /* initialise SA reference table */
292
293 /* initialise the main table */
294 KLIPS_PRINT(debug_xform,
295 "klips_debug:ipsec_sadb_init: "
296 "initialising main table of size %u (2 ^ %u).\n",
297 IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
298 IPSEC_SA_REF_MAINTABLE_IDX_WIDTH);
299 {
300 unsigned table;
301 for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
302 ipsec_sadb.refTable[table] = NULL;
303 }
304 }
305
306 /* allocate the first sub-table */
307 error = ipsec_SArefSubTable_alloc(0);
308 if(error) {
309 return error;
310 }
311
312 error = ipsec_saref_freelist_init();
313 #endif /* IPSEC_SA_REF_CODE */
314 return error;
315 }
316
317 #if IPSEC_SA_REF_CODE
318 IPsecSAref_t
319 ipsec_SAref_alloc(int*error) /* pass in error var by pointer */
320 {
321 IPsecSAref_t SAref;
322
323 KLIPS_PRINT(debug_xform,
324 "klips_debug:ipsec_SAref_alloc: "
325 "SAref requested... head=%d, cont=%d, tail=%d, listsize=%d.\n",
326 ipsec_sadb.refFreeListHead,
327 ipsec_sadb.refFreeListCont,
328 ipsec_sadb.refFreeListTail,
329 IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
330
331 if(ipsec_sadb.refFreeListHead == -1) {
332 KLIPS_PRINT(debug_xform,
333 "klips_debug:ipsec_SAref_alloc: "
334 "FreeList empty, recycling...\n");
335 *error = ipsec_SAref_recycle();
336 if(*error) {
337 return IPSEC_SAREF_NULL;
338 }
339 }
340
341 SAref = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead];
342 if(SAref == IPSEC_SAREF_NULL) {
343 KLIPS_PRINT(debug_xform,
344 "klips_debug:ipsec_SAref_alloc: "
345 "unexpected error, refFreeListHead = %d points to invalid entry.\n",
346 ipsec_sadb.refFreeListHead);
347 *error = -ESPIPE;
348 return IPSEC_SAREF_NULL;
349 }
350
351 KLIPS_PRINT(debug_xform,
352 "klips_debug:ipsec_SAref_alloc: "
353 "allocating SAref=%d, table=%u, entry=%u of %u.\n",
354 SAref,
355 IPsecSAref2table(SAref),
356 IPsecSAref2entry(SAref),
357 IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES);
358
359 ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead] = IPSEC_SAREF_NULL;
360 ipsec_sadb.refFreeListHead++;
361 if(ipsec_sadb.refFreeListHead > ipsec_sadb.refFreeListTail) {
362 KLIPS_PRINT(debug_xform,
363 "klips_debug:ipsec_SAref_alloc: "
364 "last FreeList entry allocated, resetting list head to empty.\n");
365 ipsec_sadb.refFreeListHead = -1;
366 }
367
368 return SAref;
369 }
370 #endif /* IPSEC_SA_REF_CODE */
371
372 int
373 ipsec_sa_print(struct ipsec_sa *ips)
374 {
375 char sa[SATOA_BUF];
376 size_t sa_len;
377
378 printk(KERN_INFO "klips_debug: SA:");
379 if(ips == NULL) {
380 printk("NULL\n");
381 return -ENOENT;
382 }
383 printk(" ref=%d", ips->ips_ref);
384 printk(" refcount=%d", atomic_read(&ips->ips_refcount));
385 if(ips->ips_hnext != NULL) {
386 printk(" hnext=0p%p", ips->ips_hnext);
387 }
388 if(ips->ips_inext != NULL) {
389 printk(" inext=0p%p", ips->ips_inext);
390 }
391 if(ips->ips_onext != NULL) {
392 printk(" onext=0p%p", ips->ips_onext);
393 }
394 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
395 printk(" said=%s", sa_len ? sa : " (error)");
396 if(ips->ips_seq) {
397 printk(" seq=%u", ips->ips_seq);
398 }
399 if(ips->ips_pid) {
400 printk(" pid=%u", ips->ips_pid);
401 }
402 if(ips->ips_authalg) {
403 printk(" authalg=%u", ips->ips_authalg);
404 }
405 if(ips->ips_encalg) {
406 printk(" encalg=%u", ips->ips_encalg);
407 }
408 printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
409 if(ips->ips_replaywin) {
410 printk(" ooowin=%u", ips->ips_replaywin);
411 }
412 if(ips->ips_flags) {
413 printk(" flags=%u", ips->ips_flags);
414 }
415 if(ips->ips_addr_s) {
416 char buf[SUBNETTOA_BUF];
417 addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
418 0, buf, sizeof(buf));
419 printk(" src=%s", buf);
420 }
421 if(ips->ips_addr_d) {
422 char buf[SUBNETTOA_BUF];
423 addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
424 0, buf, sizeof(buf));
425 printk(" dst=%s", buf);
426 }
427 if(ips->ips_addr_p) {
428 char buf[SUBNETTOA_BUF];
429 addrtoa(((struct sockaddr_in*)(ips->ips_addr_p))->sin_addr,
430 0, buf, sizeof(buf));
431 printk(" proxy=%s", buf);
432 }
433 if(ips->ips_key_bits_a) {
434 printk(" key_bits_a=%u", ips->ips_key_bits_a);
435 }
436 if(ips->ips_key_bits_e) {
437 printk(" key_bits_e=%u", ips->ips_key_bits_e);
438 }
439
440 printk("\n");
441 return 0;
442 }
443
444 struct ipsec_sa*
445 ipsec_sa_alloc(int*error) /* pass in error var by pointer */
446 {
447 struct ipsec_sa* ips;
448
449 if((ips = kmalloc(sizeof(*ips), GFP_ATOMIC) ) == NULL) {
450 KLIPS_PRINT(debug_xform,
451 "klips_debug:ipsec_sa_alloc: "
452 "memory allocation error\n");
453 *error = -ENOMEM;
454 return NULL;
455 }
456 memset((caddr_t)ips, 0, sizeof(*ips));
457 #if IPSEC_SA_REF_CODE
458 ips->ips_ref = ipsec_SAref_alloc(error); /* pass in error return by pointer */
459 KLIPS_PRINT(debug_xform,
460 "klips_debug:ipsec_sa_alloc: "
461 "allocated %lu bytes for ipsec_sa struct=0p%p ref=%d.\n",
462 (unsigned long) sizeof(*ips),
463 ips,
464 ips->ips_ref);
465 if(ips->ips_ref == IPSEC_SAREF_NULL) {
466 kfree(ips);
467 KLIPS_PRINT(debug_xform,
468 "klips_debug:ipsec_sa_alloc: "
469 "SAref allocation error\n");
470 return NULL;
471 }
472
473 atomic_inc(&ips->ips_refcount);
474 IPsecSAref2SA(ips->ips_ref) = ips;
475 #endif /* IPSEC_SA_REF_CODE */
476
477 *error = 0;
478 return(ips);
479 }
480
481 int
482 ipsec_sa_free(struct ipsec_sa* ips)
483 {
484 return ipsec_sa_wipe(ips);
485 }
486
487 struct ipsec_sa *
488 ipsec_sa_getbyid(struct sa_id *said)
489 {
490 int hashval;
491 struct ipsec_sa *ips;
492 char sa[SATOA_BUF];
493 size_t sa_len;
494
495 if(said == NULL) {
496 KLIPS_PRINT(debug_xform,
497 "klips_error:ipsec_sa_getbyid: "
498 "null pointer passed in!\n");
499 return NULL;
500 }
501
502 sa_len = satoa(*said, 0, sa, SATOA_BUF);
503
504 hashval = (said->spi+said->dst.s_addr+said->proto) % SADB_HASHMOD;
505
506 KLIPS_PRINT(debug_xform,
507 "klips_debug:ipsec_sa_getbyid: "
508 "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
509 hashval,
510 sa_len ? sa : " (error)");
511
512 if((ips = ipsec_sadb_hash[hashval]) == NULL) {
513 KLIPS_PRINT(debug_xform,
514 "klips_debug:ipsec_sa_getbyid: "
515 "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
516 hashval,
517 sa_len ? sa : " (error)");
518 return NULL;
519 }
520
521 for (; ips; ips = ips->ips_hnext) {
522 if ((ips->ips_said.spi == said->spi) &&
523 (ips->ips_said.dst.s_addr == said->dst.s_addr) &&
524 (ips->ips_said.proto == said->proto)) {
525 atomic_inc(&ips->ips_refcount);
526 return ips;
527 }
528 }
529
530 KLIPS_PRINT(debug_xform,
531 "klips_debug:ipsec_sa_getbyid: "
532 "no entry in linked list for hash=%d of SA:%s.\n",
533 hashval,
534 sa_len ? sa : " (error)");
535 return NULL;
536 }
537
538 int
539 ipsec_sa_put(struct ipsec_sa *ips)
540 {
541 char sa[SATOA_BUF];
542 size_t sa_len;
543
544 if(ips == NULL) {
545 KLIPS_PRINT(debug_xform,
546 "klips_error:ipsec_sa_put: "
547 "null pointer passed in!\n");
548 return -1;
549 }
550
551 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
552
553 KLIPS_PRINT(debug_xform,
554 "klips_debug:ipsec_sa_put: "
555 "ipsec_sa SA:%s, ref:%d reference count decremented.\n",
556 sa_len ? sa : " (error)",
557 ips->ips_ref);
558
559 atomic_dec(&ips->ips_refcount);
560
561 return 0;
562 }
563
564 /*
565 The ipsec_sa table better *NOT* be locked before it is handed in, or SMP locks will happen
566 */
567 int
568 ipsec_sa_add(struct ipsec_sa *ips)
569 {
570 int error = 0;
571 unsigned int hashval;
572
573 if(ips == NULL) {
574 KLIPS_PRINT(debug_xform,
575 "klips_error:ipsec_sa_add: "
576 "null pointer passed in!\n");
577 return -ENODATA;
578 }
579 hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
580
581 atomic_inc(&ips->ips_refcount);
582 spin_lock_bh(&tdb_lock);
583
584 ips->ips_hnext = ipsec_sadb_hash[hashval];
585 ipsec_sadb_hash[hashval] = ips;
586
587 spin_unlock_bh(&tdb_lock);
588
589 return error;
590 }
591
592 /*
593 The ipsec_sa table better be locked before it is handed in, or races might happen
594 */
595 int
596 ipsec_sa_del(struct ipsec_sa *ips)
597 {
598 unsigned int hashval;
599 struct ipsec_sa *ipstp;
600 char sa[SATOA_BUF];
601 size_t sa_len;
602
603 if(ips == NULL) {
604 KLIPS_PRINT(debug_xform,
605 "klips_error:ipsec_sa_del: "
606 "null pointer passed in!\n");
607 return -ENODATA;
608 }
609
610 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
611 if(ips->ips_inext || ips->ips_onext) {
612 KLIPS_PRINT(debug_xform,
613 "klips_error:ipsec_sa_del: "
614 "SA:%s still linked!\n",
615 sa_len ? sa : " (error)");
616 return -EMLINK;
617 }
618
619 hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
620
621 KLIPS_PRINT(debug_xform,
622 "klips_debug:ipsec_sa_del: "
623 "deleting SA:%s, hashval=%d.\n",
624 sa_len ? sa : " (error)",
625 hashval);
626 if(ipsec_sadb_hash[hashval] == NULL) {
627 KLIPS_PRINT(debug_xform,
628 "klips_debug:ipsec_sa_del: "
629 "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
630 hashval,
631 sa_len ? sa : " (error)");
632 return -ENOENT;
633 }
634
635 if (ips == ipsec_sadb_hash[hashval]) {
636 ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
637 ips->ips_hnext = NULL;
638 atomic_dec(&ips->ips_refcount);
639 KLIPS_PRINT(debug_xform,
640 "klips_debug:ipsec_sa_del: "
641 "successfully deleted first ipsec_sa in chain.\n");
642 return 0;
643 } else {
644 for (ipstp = ipsec_sadb_hash[hashval];
645 ipstp;
646 ipstp = ipstp->ips_hnext) {
647 if (ipstp->ips_hnext == ips) {
648 ipstp->ips_hnext = ips->ips_hnext;
649 ips->ips_hnext = NULL;
650 atomic_dec(&ips->ips_refcount);
651 KLIPS_PRINT(debug_xform,
652 "klips_debug:ipsec_sa_del: "
653 "successfully deleted link in ipsec_sa chain.\n");
654 return 0;
655 }
656 }
657 }
658
659 KLIPS_PRINT(debug_xform,
660 "klips_debug:ipsec_sa_del: "
661 "no entries in linked list for hash=%d of SA:%s.\n",
662 hashval,
663 sa_len ? sa : " (error)");
664 return -ENOENT;
665 }
666
667 /*
668 The ipsec_sa table better be locked before it is handed in, or races
669 might happen
670 */
671 int
672 ipsec_sa_delchain(struct ipsec_sa *ips)
673 {
674 struct ipsec_sa *ipsdel;
675 int error = 0;
676 char sa[SATOA_BUF];
677 size_t sa_len;
678
679 if(ips == NULL) {
680 KLIPS_PRINT(debug_xform,
681 "klips_error:ipsec_sa_delchain: "
682 "null pointer passed in!\n");
683 return -ENODATA;
684 }
685
686 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
687 KLIPS_PRINT(debug_xform,
688 "klips_debug:ipsec_sa_delchain: "
689 "passed SA:%s\n",
690 sa_len ? sa : " (error)");
691 while(ips->ips_onext != NULL) {
692 ips = ips->ips_onext;
693 }
694
695 while(ips) {
696 /* XXX send a pfkey message up to advise of deleted ipsec_sa */
697 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
698 KLIPS_PRINT(debug_xform,
699 "klips_debug:ipsec_sa_delchain: "
700 "unlinking and delting SA:%s",
701 sa_len ? sa : " (error)");
702 ipsdel = ips;
703 ips = ips->ips_inext;
704 if(ips != NULL) {
705 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
706 KLIPS_PRINT(debug_xform,
707 ", inext=%s",
708 sa_len ? sa : " (error)");
709 atomic_dec(&ipsdel->ips_refcount);
710 ipsdel->ips_inext = NULL;
711 atomic_dec(&ips->ips_refcount);
712 ips->ips_onext = NULL;
713 }
714 KLIPS_PRINT(debug_xform,
715 ".\n");
716 if((error = ipsec_sa_del(ipsdel))) {
717 KLIPS_PRINT(debug_xform,
718 "klips_debug:ipsec_sa_delchain: "
719 "ipsec_sa_del returned error %d.\n", -error);
720 return error;
721 }
722 if((error = ipsec_sa_wipe(ipsdel))) {
723 KLIPS_PRINT(debug_xform,
724 "klips_debug:ipsec_sa_delchain: "
725 "ipsec_sa_wipe returned error %d.\n", -error);
726 return error;
727 }
728 }
729 return error;
730 }
731
732 int
733 ipsec_sadb_cleanup(__u8 proto)
734 {
735 unsigned i;
736 int error = 0;
737 struct ipsec_sa *ips, **ipsprev, *ipsdel;
738 char sa[SATOA_BUF];
739 size_t sa_len;
740
741 KLIPS_PRINT(debug_xform,
742 "klips_debug:ipsec_sadb_cleanup: "
743 "cleaning up proto=%d.\n",
744 proto);
745
746 spin_lock_bh(&tdb_lock);
747
748 for (i = 0; i < SADB_HASHMOD; i++) {
749 ipsprev = &(ipsec_sadb_hash[i]);
750 ips = ipsec_sadb_hash[i];
751 if(ips != NULL) {
752 atomic_inc(&ips->ips_refcount);
753 }
754 for(; ips != NULL;) {
755 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
756 KLIPS_PRINT(debug_xform,
757 "klips_debug:ipsec_sadb_cleanup: "
758 "checking SA:%s, hash=%d, ref=%d",
759 sa_len ? sa : " (error)",
760 i,
761 ips->ips_ref);
762 ipsdel = ips;
763 ips = ipsdel->ips_hnext;
764 if(ips != NULL) {
765 atomic_inc(&ips->ips_refcount);
766 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
767 KLIPS_PRINT(debug_xform,
768 ", hnext=%s",
769 sa_len ? sa : " (error)");
770 }
771 if(*ipsprev != NULL) {
772 sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
773 KLIPS_PRINT(debug_xform,
774 ", *ipsprev=%s",
775 sa_len ? sa : " (error)");
776 if((*ipsprev)->ips_hnext) {
777 sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
778 KLIPS_PRINT(debug_xform,
779 ", *ipsprev->ips_hnext=%s",
780 sa_len ? sa : " (error)");
781 }
782 }
783 KLIPS_PRINT(debug_xform,
784 ".\n");
785 if(proto == 0 || (proto == ipsdel->ips_said.proto)) {
786 sa_len = satoa(ipsdel->ips_said, 0, sa, SATOA_BUF);
787 KLIPS_PRINT(debug_xform,
788 "klips_debug:ipsec_sadb_cleanup: "
789 "deleting SA chain:%s.\n",
790 sa_len ? sa : " (error)");
791 if((error = ipsec_sa_delchain(ipsdel))) {
792 SENDERR(-error);
793 }
794 ipsprev = &(ipsec_sadb_hash[i]);
795 ips = ipsec_sadb_hash[i];
796
797 KLIPS_PRINT(debug_xform,
798 "klips_debug:ipsec_sadb_cleanup: "
799 "deleted SA chain:%s",
800 sa_len ? sa : " (error)");
801 if(ips != NULL) {
802 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
803 KLIPS_PRINT(debug_xform,
804 ", ipsec_sadb_hash[%d]=%s",
805 i,
806 sa_len ? sa : " (error)");
807 }
808 if(*ipsprev != NULL) {
809 sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
810 KLIPS_PRINT(debug_xform,
811 ", *ipsprev=%s",
812 sa_len ? sa : " (error)");
813 if((*ipsprev)->ips_hnext != NULL) {
814 sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
815 KLIPS_PRINT(debug_xform,
816 ", *ipsprev->ips_hnext=%s",
817 sa_len ? sa : " (error)");
818 }
819 }
820 KLIPS_PRINT(debug_xform,
821 ".\n");
822 } else {
823 ipsprev = &ipsdel;
824 }
825 if(ipsdel != NULL) {
826 ipsec_sa_put(ipsdel);
827 }
828 }
829 }
830 errlab:
831
832 spin_unlock_bh(&tdb_lock);
833
834
835 #if IPSEC_SA_REF_CODE
836 /* clean up SA reference table */
837
838 /* go through the ref table and clean out all the SAs */
839 KLIPS_PRINT(debug_xform,
840 "klips_debug:ipsec_sadb_cleanup: "
841 "removing SAref entries and tables.");
842 {
843 unsigned table, entry;
844 for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
845 KLIPS_PRINT(debug_xform,
846 "klips_debug:ipsec_sadb_cleanup: "
847 "cleaning SAref table=%u.\n",
848 table);
849 if(ipsec_sadb.refTable[table] == NULL) {
850 printk("\n");
851 KLIPS_PRINT(debug_xform,
852 "klips_debug:ipsec_sadb_cleanup: "
853 "cleaned %u used refTables.\n",
854 table);
855 break;
856 }
857 for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
858 if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
859 ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
860 ipsec_sadb.refTable[table]->entry[entry] = NULL;
861 }
862 }
863 }
864 }
865 #endif /* IPSEC_SA_REF_CODE */
866
867 return(error);
868 }
869
870 int
871 ipsec_sadb_free(void)
872 {
873 int error = 0;
874
875 KLIPS_PRINT(debug_xform,
876 "klips_debug:ipsec_sadb_free: "
877 "freeing SArefTable memory.\n");
878
879 /* clean up SA reference table */
880
881 /* go through the ref table and clean out all the SAs if any are
882 left and free table memory */
883 KLIPS_PRINT(debug_xform,
884 "klips_debug:ipsec_sadb_free: "
885 "removing SAref entries and tables.\n");
886 {
887 unsigned table, entry;
888 for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
889 KLIPS_PRINT(debug_xform,
890 "klips_debug:ipsec_sadb_free: "
891 "removing SAref table=%u.\n",
892 table);
893 if(ipsec_sadb.refTable[table] == NULL) {
894 KLIPS_PRINT(debug_xform,
895 "klips_debug:ipsec_sadb_free: "
896 "removed %u used refTables.\n",
897 table);
898 break;
899 }
900 for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
901 if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
902 ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
903 ipsec_sadb.refTable[table]->entry[entry] = NULL;
904 }
905 }
906 vfree(ipsec_sadb.refTable[table]);
907 ipsec_sadb.refTable[table] = NULL;
908 }
909 }
910
911 return(error);
912 }
913
914 int
915 ipsec_sa_wipe(struct ipsec_sa *ips)
916 {
917 if(ips == NULL) {
918 return -ENODATA;
919 }
920
921 /* if(atomic_dec_and_test(ips)) {
922 }; */
923
924 #if IPSEC_SA_REF_CODE
925 /* remove me from the SArefTable */
926 {
927 char sa[SATOA_BUF];
928 size_t sa_len;
929 sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
930 KLIPS_PRINT(debug_xform,
931 "klips_debug:ipsec_sa_wipe: "
932 "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
933 sa_len ? sa : " (error)",
934 ips,
935 ips->ips_ref,
936 IPsecSAref2table(IPsecSA2SAref(ips)),
937 ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))],
938 IPsecSAref2entry(IPsecSA2SAref(ips)));
939 }
940 if(ips->ips_ref == IPSEC_SAREF_NULL) {
941 KLIPS_PRINT(debug_xform,
942 "klips_debug:ipsec_sa_wipe: "
943 "why does this SA not have a valid SAref?.\n");
944 }
945 ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))]->entry[IPsecSAref2entry(IPsecSA2SAref(ips))] = NULL;
946 ips->ips_ref = IPSEC_SAREF_NULL;
947 ipsec_sa_put(ips);
948 #endif /* IPSEC_SA_REF_CODE */
949
950 /* paranoid clean up */
951 if(ips->ips_addr_s != NULL) {
952 memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
953 kfree(ips->ips_addr_s);
954 }
955 ips->ips_addr_s = NULL;
956
957 if(ips->ips_addr_d != NULL) {
958 memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
959 kfree(ips->ips_addr_d);
960 }
961 ips->ips_addr_d = NULL;
962
963 if(ips->ips_addr_p != NULL) {
964 memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
965 kfree(ips->ips_addr_p);
966 }
967 ips->ips_addr_p = NULL;
968
969 #ifdef CONFIG_IPSEC_NAT_TRAVERSAL
970 if(ips->ips_natt_oa) {
971 memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
972 kfree(ips->ips_natt_oa);
973 }
974 ips->ips_natt_oa = NULL;
975 #endif
976
977 if(ips->ips_key_a != NULL) {
978 memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
979 kfree(ips->ips_key_a);
980 }
981 ips->ips_key_a = NULL;
982
983 if(ips->ips_key_e != NULL) {
984 #ifdef CONFIG_IPSEC_ALG
985 if (ips->ips_alg_enc&&ips->ips_alg_enc->ixt_e_destroy_key) {
986 ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc,
987 ips->ips_key_e);
988 } else {
989 #endif /* CONFIG_IPSEC_ALG */
990 memset((caddr_t)(ips->ips_key_e), 0, ips->ips_key_e_size);
991 kfree(ips->ips_key_e);
992 #ifdef CONFIG_IPSEC_ALG
993 }
994 #endif /* CONFIG_IPSEC_ALG */
995 }
996 ips->ips_key_e = NULL;
997
998 if(ips->ips_iv != NULL) {
999 memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
1000 kfree(ips->ips_iv);
1001 }
1002 ips->ips_iv = NULL;
1003
1004 if(ips->ips_ident_s.data != NULL) {
1005 memset((caddr_t)(ips->ips_ident_s.data),
1006 0,
1007 ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
1008 kfree(ips->ips_ident_s.data);
1009 }
1010 ips->ips_ident_s.data = NULL;
1011
1012 if(ips->ips_ident_d.data != NULL) {
1013 memset((caddr_t)(ips->ips_ident_d.data),
1014 0,
1015 ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
1016 kfree(ips->ips_ident_d.data);
1017 }
1018 ips->ips_ident_d.data = NULL;
1019
1020 #ifdef CONFIG_IPSEC_ALG
1021 if (ips->ips_alg_enc||ips->ips_alg_auth) {
1022 ipsec_alg_sa_wipe(ips);
1023 }
1024 #endif /* CONFIG_IPSEC_ALG */
1025
1026 memset((caddr_t)ips, 0, sizeof(*ips));
1027 kfree(ips);
1028 ips = NULL;
1029
1030 return 0;
1031 }