charon-tkm: Also store local SPI in SAD
[strongswan.git] / src / charon-tkm / src / tkm / tkm_kernel_sad.c
1 /*
2 * Copyright (C) 2012-2014 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 * Reqid.
61 */
62 u_int32_t reqid;
63
64 /**
65 * Source address of CHILD SA.
66 */
67 host_t *src;
68
69 /**
70 * Destination address of CHILD SA.
71 */
72 host_t *dst;
73
74 /**
75 * Local SPI of CHILD SA.
76 */
77 u_int32_t spi_loc;
78
79 /**
80 * Remote SPI of CHILD SA.
81 */
82 u_int32_t spi_rem;
83
84 /**
85 * Protocol of CHILD SA (ESP/AH).
86 */
87 u_int8_t proto;
88
89 };
90
91 /**
92 * Destroy an sad_entry_t object.
93 */
94 static void sad_entry_destroy(sad_entry_t *entry)
95 {
96 if (entry)
97 {
98 DESTROY_IF(entry->src);
99 DESTROY_IF(entry->dst);
100 free(entry);
101 }
102 }
103
104 /**
105 * Find a list entry with given src, dst, (remote) spi and proto values.
106 */
107 static bool sad_entry_match(sad_entry_t * const entry, const host_t * const src,
108 const host_t * const dst, const u_int32_t * const spi,
109 const u_int8_t * const proto)
110 {
111 if (entry->src == NULL || entry->dst == NULL)
112 {
113 return FALSE;
114 }
115
116 return src->ip_equals(entry->src, (host_t *)src) &&
117 dst->ip_equals(entry->dst, (host_t *)dst) &&
118 entry->spi_rem == *spi && entry->proto == *proto;
119 }
120
121 /**
122 * Find a list entry with given reqid, spi and proto values.
123 */
124 static bool sad_entry_match_dst(sad_entry_t * const entry,
125 const u_int32_t * const reqid,
126 const u_int32_t * const spi,
127 const u_int8_t * const proto)
128 {
129 return entry->reqid == *reqid &&
130 entry->spi_rem == *spi &&
131 entry->proto == *proto;
132 }
133
134 /**
135 * Find a list entry with given esa id.
136 */
137 static bool sad_entry_match_esa_id(sad_entry_t * const entry,
138 const esa_id_type * const esa_id)
139 {
140 return entry->esa_id == *esa_id;
141 }
142
143 /**
144 * Find a list entry with given reqid and different esa id.
145 */
146 static bool sad_entry_match_other_esa(sad_entry_t * const entry,
147 const esa_id_type * const esa_id,
148 const u_int32_t * const reqid)
149 {
150 return entry->reqid == *reqid &&
151 entry->esa_id != *esa_id;
152 }
153
154 /**
155 * Compare two SAD entries for equality.
156 */
157 static bool sad_entry_equal(sad_entry_t * const left, sad_entry_t * const right)
158 {
159 if (left->src == NULL || left->dst == NULL || right->src == NULL ||
160 right->dst == NULL)
161 {
162 return FALSE;
163 }
164 return left->esa_id == right->esa_id &&
165 left->reqid == right->reqid &&
166 left->src->ip_equals(left->src, right->src) &&
167 left->dst->ip_equals(left->dst, right->dst) &&
168 left->spi_loc == right->spi_loc &&
169 left->spi_rem == right->spi_rem &&
170 left->proto == right->proto;
171 }
172
173 METHOD(tkm_kernel_sad_t, insert, bool,
174 private_tkm_kernel_sad_t * const this, const esa_id_type esa_id,
175 const u_int32_t reqid, const host_t * const src, const host_t * const dst,
176 const u_int32_t spi_loc, const u_int32_t spi_rem, const u_int8_t proto)
177 {
178 status_t result;
179 sad_entry_t *new_entry;
180
181 INIT(new_entry,
182 .esa_id = esa_id,
183 .reqid = reqid,
184 .src = (host_t *)src,
185 .dst = (host_t *)dst,
186 .spi_loc = spi_loc,
187 .spi_rem = spi_rem,
188 .proto = proto,
189 );
190
191 this->mutex->lock(this->mutex);
192 result = this->data->find_first(this->data,
193 (linked_list_match_t)sad_entry_equal, NULL,
194 new_entry);
195 if (result == NOT_FOUND)
196 {
197 DBG3(DBG_KNL, "inserting SAD entry (esa: %llu, reqid: %u, src: %H, "
198 "dst: %H, spi_loc: %x, spi_rem: %x,proto: %u)", esa_id, reqid, src,
199 dst, ntohl(spi_loc), ntohl(spi_rem), proto);
200 new_entry->src = src->clone((host_t *)src);
201 new_entry->dst = dst->clone((host_t *)dst);
202 this->data->insert_last(this->data, new_entry);
203 }
204 else
205 {
206 DBG1(DBG_KNL, "SAD entry with esa id %llu already exists!", esa_id);
207 free(new_entry);
208 }
209 this->mutex->unlock(this->mutex);
210 return result == NOT_FOUND;
211 }
212
213 METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type,
214 private_tkm_kernel_sad_t * const this, const host_t * const src,
215 const host_t * const dst, const u_int32_t spi, const u_int8_t proto)
216 {
217 esa_id_type id = 0;
218 sad_entry_t *entry = NULL;
219
220 this->mutex->lock(this->mutex);
221 const status_t res = this->data->find_first(this->data,
222 (linked_list_match_t)sad_entry_match,
223 (void**)&entry, src, dst, &spi,
224 &proto);
225 if (res == SUCCESS && entry)
226 {
227 id = entry->esa_id;
228 DBG3(DBG_KNL, "returning ESA id %llu of SAD entry (src: %H, dst: %H, "
229 "spi: %x, proto: %u)", id, src, dst, ntohl(spi), proto);
230 }
231 else
232 {
233 DBG3(DBG_KNL, "no SAD entry found for src %H, dst %H, spi %x, proto %u",
234 src, dst, ntohl(spi), proto);
235 }
236 this->mutex->unlock(this->mutex);
237 return id;
238 }
239
240 METHOD(tkm_kernel_sad_t, get_other_esa_id, esa_id_type,
241 private_tkm_kernel_sad_t * const this, const esa_id_type esa_id)
242 {
243 esa_id_type id = 0;
244 sad_entry_t *entry = NULL;
245 u_int32_t reqid;
246 status_t res;
247
248 this->mutex->lock(this->mutex);
249 res = this->data->find_first(this->data,
250 (linked_list_match_t)sad_entry_match_esa_id,
251 (void**)&entry, &esa_id);
252 if (res == SUCCESS && entry)
253 {
254 reqid = entry->reqid;
255 }
256 else
257 {
258 DBG3(DBG_KNL, "no SAD entry found for ESA id %llu", esa_id);
259 this->mutex->unlock(this->mutex);
260 return id;
261 }
262
263 res = this->data->find_first(this->data,
264 (linked_list_match_t)sad_entry_match_other_esa,
265 (void**)&entry, &esa_id, &reqid);
266 if (res == SUCCESS && entry)
267 {
268 id = entry->esa_id;
269 DBG3(DBG_KNL, "returning ESA id %llu of other SAD entry with reqid %u",
270 id, reqid);
271 }
272 this->mutex->unlock(this->mutex);
273 return id;
274 }
275
276 METHOD(tkm_kernel_sad_t, get_dst_host, host_t *,
277 private_tkm_kernel_sad_t * const this, const u_int32_t reqid,
278 const u_int32_t spi, const u_int8_t proto)
279 {
280 host_t *dst = NULL;
281 sad_entry_t *entry = NULL;
282
283 this->mutex->lock(this->mutex);
284 const status_t res = this->data->find_first(this->data,
285 (linked_list_match_t)sad_entry_match_dst,
286 (void**)&entry, &reqid, &spi, &proto);
287 if (res == SUCCESS && entry)
288 {
289 dst = entry->dst;
290 DBG3(DBG_KNL, "returning destination host %H of SAD entry (reqid: %u,"
291 " spi: %x, proto: %u)", dst, reqid, ntohl(spi), proto);
292 }
293 else
294 {
295 DBG3(DBG_KNL, "no SAD entry found for reqid %u, spi %x, proto: %u",
296 reqid, ntohl(spi), proto);
297 }
298 this->mutex->unlock(this->mutex);
299 return dst;
300 }
301
302 METHOD(tkm_kernel_sad_t, _remove, bool,
303 private_tkm_kernel_sad_t * const this, const esa_id_type esa_id)
304 {
305 sad_entry_t *current;
306 bool removed = FALSE;
307 enumerator_t *enumerator;
308
309 this->mutex->lock(this->mutex);
310 enumerator = this->data->create_enumerator(this->data);
311 while (enumerator->enumerate(enumerator, (void **)&current))
312 {
313 if (current->esa_id == esa_id)
314 {
315 this->data->remove_at(this->data, enumerator);
316 sad_entry_destroy(current);
317 removed = TRUE;
318 break;
319 }
320 }
321 enumerator->destroy(enumerator);
322
323 if (removed)
324 {
325 DBG3(DBG_KNL, "removed SAD entry (esa: %llu)", esa_id);
326 }
327 else
328 {
329 DBG1(DBG_KNL, "no SAD entry with ESA id %llu found!", esa_id);
330 }
331 this->mutex->unlock(this->mutex);
332
333 return removed;
334 }
335
336
337 METHOD(tkm_kernel_sad_t, destroy, void,
338 private_tkm_kernel_sad_t *this)
339 {
340 this->mutex->destroy(this->mutex);
341 this->data->destroy_function(this->data, (void*)sad_entry_destroy);
342 free(this);
343 }
344
345 /*
346 * see header file
347 */
348 tkm_kernel_sad_t *tkm_kernel_sad_create()
349 {
350 private_tkm_kernel_sad_t *this;
351
352 INIT(this,
353 .public = {
354 .insert = _insert,
355 .get_esa_id = _get_esa_id,
356 .get_other_esa_id = _get_other_esa_id,
357 .get_dst_host = _get_dst_host,
358 .remove = __remove,
359 .destroy = _destroy,
360 },
361 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
362 .data = linked_list_create(),
363 );
364
365 return &this->public;
366 }