ef728bfbf1c6fa935c796699df397f7f8e410431
[strongswan.git] / src / charon / processing / jobs / initiate_mediation_job.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "initiate_mediation_job.h"
19
20 #include <sa/ike_sa.h>
21 #include <daemon.h>
22
23
24 typedef struct private_initiate_mediation_job_t private_initiate_mediation_job_t;
25
26 /**
27 * Private data of an initiate_mediation_job_t Object
28 */
29 struct private_initiate_mediation_job_t {
30 /**
31 * public initiate_mediation_job_t interface
32 */
33 initiate_mediation_job_t public;
34
35 /**
36 * ID of the IKE_SA of the mediated connection.
37 */
38 ike_sa_id_t *mediated_sa_id;
39
40 /**
41 * ID of the IKE_SA of the mediation connection.
42 */
43 ike_sa_id_t *mediation_sa_id;
44 };
45
46 /**
47 * Implements job_t.destroy.
48 */
49 static void destroy(private_initiate_mediation_job_t *this)
50 {
51 DESTROY_IF(this->mediation_sa_id);
52 DESTROY_IF(this->mediated_sa_id);
53 free(this);
54 }
55
56 /**
57 * Callback to handle initiation of mediation connection
58 */
59 static bool initiate_callback(private_initiate_mediation_job_t *this,
60 signal_t signal, level_t level, ike_sa_t *ike_sa,
61 void *data, char *format, va_list args)
62 {
63 if (signal == CHD_UP_SUCCESS)
64 {
65 /* mediation connection is up */
66 this->mediation_sa_id = ike_sa->get_id(ike_sa);
67 this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id);
68 return FALSE;
69 }
70 return TRUE;
71 }
72
73 /**
74 * Implementation of job_t.execute.
75 */
76 static void initiate(private_initiate_mediation_job_t *this)
77 { /* FIXME: check the logging */
78 ike_sa_t *mediated_sa, *mediation_sa;
79 peer_cfg_t *mediated_cfg, *mediation_cfg;
80
81 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
82 this->mediated_sa_id);
83 if (mediated_sa)
84 {
85 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
86 /* get_peer_cfg returns an internal object */
87 mediated_cfg->get_ref(mediated_cfg);
88
89 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
90
91 mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
92 mediation_cfg->get_ref(mediation_cfg);
93
94 if (charon->connect_manager->check_and_register(charon->connect_manager,
95 mediation_cfg->get_my_id(mediation_cfg),
96 mediated_cfg->get_peer_id(mediated_cfg),
97 this->mediated_sa_id))
98 {
99 mediated_cfg->destroy(mediated_cfg);
100 mediation_cfg->destroy(mediation_cfg);
101 /* this pointer should still be valid */
102 charon->bus->set_sa(charon->bus, mediated_sa);
103 DBG1(DBG_IKE, "mediation with the same peer is already in progress, queued");
104 destroy(this);
105 return;
106 }
107 /* we need an additional reference because initiate consumes one */
108 mediation_cfg->get_ref(mediation_cfg);
109
110 /* this function call blocks until the connection is up or failed
111 * we do not check the status, but NEED_MORE would be returned on success
112 * because the registered callback returns FALSE then
113 * this->mediation_sa_id is set in the callback */
114 charon->controller->initiate(charon->controller,
115 mediation_cfg, NULL, (controller_cb_t)initiate_callback, this);
116 if (!this->mediation_sa_id)
117 {
118 DBG1(DBG_JOB, "initiating mediation connection '%s' failed",
119 mediation_cfg->get_name(mediation_cfg));
120 mediation_cfg->destroy(mediation_cfg);
121 mediated_cfg->destroy(mediated_cfg);
122 charon->bus->set_sa(charon->bus, mediated_sa);
123 SIG_IKE(UP_FAILED, "mediation failed");
124 destroy(this);
125 return;
126 }
127 mediation_cfg->destroy(mediation_cfg);
128
129 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
130 this->mediation_sa_id);
131
132 if (mediation_sa)
133 {
134 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
135 {
136 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
137 mediated_cfg->get_name(mediated_cfg));
138 mediated_cfg->destroy(mediated_cfg);
139 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
140
141 charon->bus->set_sa(charon->bus, mediated_sa);
142 SIG_IKE(UP_FAILED, "mediation failed");
143 destroy(this);
144 return;
145 }
146
147 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
148 }
149
150 mediated_cfg->destroy(mediated_cfg);
151 }
152 destroy(this);
153 }
154
155 /**
156 * Implementation of job_t.execute.
157 */
158 static void reinitiate(private_initiate_mediation_job_t *this)
159 { /* FIXME: check the logging */
160 ike_sa_t *mediated_sa, *mediation_sa;
161 peer_cfg_t *mediated_cfg;
162
163 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
164 this->mediated_sa_id);
165 if (mediated_sa)
166 {
167 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
168 mediated_cfg->get_ref(mediated_cfg);
169 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
170
171 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
172 this->mediation_sa_id);
173 if (mediation_sa)
174 {
175 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
176 {
177 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
178 mediated_cfg->get_name(mediated_cfg));
179 mediated_cfg->destroy(mediated_cfg);
180 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
181
182 charon->bus->set_sa(charon->bus, mediated_sa);
183 SIG_IKE(UP_FAILED, "mediation failed");
184 destroy(this);
185 return;
186 }
187
188 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
189 }
190
191 mediated_cfg->destroy(mediated_cfg);
192 }
193 destroy(this);
194 }
195
196 /**
197 * Creates an empty job
198 */
199 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
200 {
201 private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t);
202
203 /* interface functions */
204 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
205
206 /* private variables */
207 this->mediation_sa_id = NULL;
208 this->mediated_sa_id = NULL;
209
210 return this;
211 }
212
213 /*
214 * Described in header
215 */
216 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id)
217 {
218 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
219
220 this->public.job_interface.execute = (void (*) (job_t *)) initiate;
221
222 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
223
224 return &this->public;
225 }
226
227 /*
228 * Described in header
229 */
230 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
231 ike_sa_id_t *mediated_sa_id)
232 {
233 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
234
235 this->public.job_interface.execute = (void (*) (job_t *)) reinitiate;
236
237 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
238 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
239
240 return &this->public;
241 }