02b6ddc7c1d4053253f472146f5533f1b80c9519
[strongswan.git] / src / charon-tkm / src / tkm / tkm_kernel_sad.c
1 /*
2 * Copyright (C) 2012 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
4 * Hochschule fuer Technik Rapperswil
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 #include <collections/linked_list.h>
18 #include <threading/mutex.h>
19 #include <utils/debug.h>
20
21 #include "tkm_kernel_sad.h"
22
23 typedef struct private_tkm_kernel_sad_t private_tkm_kernel_sad_t;
24
25 /**
26 * Private data of tkm_kernel_sad.
27 */
28 struct private_tkm_kernel_sad_t {
29
30 /**
31 * Public functions.
32 */
33 tkm_kernel_sad_t public;
34
35 /**
36 * Linked list of SAD entries.
37 */
38 linked_list_t *data;
39
40 /**
41 * Lock used to protect SA data.
42 */
43 mutex_t *mutex;
44
45 };
46
47 typedef struct sad_entry_t sad_entry_t;
48
49 /**
50 * Data structure holding all information of an SAD entry.
51 */
52 struct sad_entry_t {
53
54 /**
55 * ESA identifier.
56 */
57 esa_id_type esa_id;
58
59 /**
60 * Source address of CHILD SA.
61 */
62 host_t *src;
63
64 /**
65 * Destination address of CHILD SA.
66 */
67 host_t *dst;
68
69 /**
70 * SPI of CHILD SA.
71 */
72 u_int32_t spi;
73
74 /**
75 * Protocol of CHILD SA (ESP/AH).
76 */
77 u_int8_t proto;
78
79 };
80
81 /**
82 * Destroy an sad_entry_t object.
83 */
84 static void sad_entry_destroy(sad_entry_t *entry)
85 {
86 if (entry)
87 {
88 DESTROY_IF(entry->src);
89 DESTROY_IF(entry->dst);
90 free(entry);
91 }
92 }
93
94 /**
95 * Find a list entry with given src, dst, spi and proto values.
96 */
97 static bool sad_entry_match(sad_entry_t * const entry, const host_t * const src,
98 const host_t * const dst, const u_int32_t * const spi,
99 const u_int8_t * const proto)
100 {
101 if (entry->src == NULL || entry->dst == NULL)
102 {
103 return FALSE;
104 }
105
106 return src->ip_equals(entry->src, (host_t *)src) &&
107 dst->ip_equals(entry->dst, (host_t *)dst) &&
108 entry->spi == *spi && entry->proto == *proto;
109 }
110
111 /**
112 * Compare two SAD entries for equality.
113 */
114 static bool sad_entry_equal(sad_entry_t * const left, sad_entry_t * const right)
115 {
116 if (left->src == NULL || left->dst == NULL || right->src == NULL ||
117 right->dst == NULL)
118 {
119 return FALSE;
120 }
121 return left->esa_id == right->esa_id &&
122 left->src->ip_equals(left->src, right->src) &&
123 left->dst->ip_equals(left->dst, right->dst) &&
124 left->spi == right->spi && left->proto == right->proto;
125 }
126
127 METHOD(tkm_kernel_sad_t, insert, bool,
128 private_tkm_kernel_sad_t * const this, const esa_id_type esa_id,
129 const host_t * const src, const host_t * const dst, const u_int32_t spi,
130 const u_int8_t proto)
131 {
132
133 sad_entry_t *new_entry;
134 INIT(new_entry,
135 .esa_id = esa_id,
136 .src = (host_t *)src,
137 .dst = (host_t *)dst,
138 .spi = spi,
139 .proto = proto,
140 );
141
142 this->mutex->lock(this->mutex);
143 const status_t result = this->data->find_first(this->data,
144 (linked_list_match_t)sad_entry_equal,
145 NULL, new_entry);
146 if (result == NOT_FOUND)
147 {
148 DBG3(DBG_KNL, "inserting SAD entry (esa: %llu, src: %H, dst: %H, "
149 "spi: %x, proto: %u)", esa_id, src, dst, ntohl(spi), proto);
150 new_entry->src = src->clone((host_t *)src);
151 new_entry->dst = dst->clone((host_t *)dst);
152 this->data->insert_last(this->data, new_entry);
153 }
154 else
155 {
156 DBG1(DBG_KNL, "SAD entry with esa id %llu already exists!", esa_id);
157 free(new_entry);
158 }
159 this->mutex->unlock(this->mutex);
160 return result == NOT_FOUND;
161 }
162
163 METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type,
164 private_tkm_kernel_sad_t * const this, const host_t * const src,
165 const host_t * const dst, const u_int32_t spi, const u_int8_t proto)
166 {
167 esa_id_type id = 0;
168 sad_entry_t *entry = NULL;
169
170 this->mutex->lock(this->mutex);
171 const status_t res = this->data->find_first(this->data,
172 (linked_list_match_t)sad_entry_match,
173 (void**)&entry, src, dst, &spi,
174 &proto);
175 if (res == SUCCESS && entry)
176 {
177 id = entry->esa_id;
178 DBG3(DBG_KNL, "getting ESA id of SAD entry (esa: %llu, src: %H, "
179 "dst: %H, spi: %x, proto: %u)", id, src, dst, ntohl(spi),
180 proto);
181 }
182 else
183 {
184 DBG3(DBG_KNL, "no SAD entry found");
185 }
186 this->mutex->unlock(this->mutex);
187 return id;
188 }
189
190 METHOD(tkm_kernel_sad_t, _remove, bool,
191 private_tkm_kernel_sad_t * const this, const esa_id_type esa_id)
192 {
193 sad_entry_t *current;
194 bool removed = FALSE;
195 this->mutex->lock(this->mutex);
196 enumerator_t *enumerator = this->data->create_enumerator(this->data);
197 while (enumerator->enumerate(enumerator, (void **)&current))
198 {
199 if (current->esa_id == esa_id)
200 {
201 this->data->remove_at(this->data, enumerator);
202 sad_entry_destroy(current);
203 removed = TRUE;
204 break;
205 }
206 }
207 enumerator->destroy(enumerator);
208
209 if (removed)
210 {
211 DBG3(DBG_KNL, "removed SAD entry (esa: %llu)", esa_id);
212 }
213 else
214 {
215 DBG1(DBG_KNL, "no SAD entry with ESA id %llu found!", esa_id);
216 }
217 this->mutex->unlock(this->mutex);
218
219 return removed;
220 }
221
222
223 METHOD(tkm_kernel_sad_t, destroy, void,
224 private_tkm_kernel_sad_t *this)
225 {
226 this->mutex->destroy(this->mutex);
227 this->data->destroy_function(this->data, (void*)sad_entry_destroy);
228 free(this);
229 }
230
231 /*
232 * see header file
233 */
234 tkm_kernel_sad_t *tkm_kernel_sad_create()
235 {
236 private_tkm_kernel_sad_t *this;
237
238 INIT(this,
239 .public = {
240 .insert = _insert,
241 .get_esa_id = _get_esa_id,
242 .remove = __remove,
243 .destroy = _destroy,
244 },
245 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
246 .data = linked_list_create(),
247 );
248
249 return &this->public;
250 }