implemented mutex locking the recommendations list
[strongswan.git] / src / libcharon / plugins / tnccs_20 / tnccs_20.c
1 /*
2 * Copyright (C) 2010 Sansar Choinyanbuu
3 * HSR 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
16 #include "tnccs_20.h"
17
18 #include <debug.h>
19 #include <daemon.h>
20 #include <threading/mutex.h>
21 #include <tnc/tncif.h>
22 #include <tnc/tncifimv_names.h>
23 #include <tnc/tnccs/tnccs.h>
24
25 typedef struct recommendation_entry_t recommendation_entry_t;
26 typedef struct private_tnccs_20_t private_tnccs_20_t;
27
28 /**
29 * Recommendation entry
30 */
31 struct recommendation_entry_t {
32
33 /**
34 * IMV ID
35 */
36 TNC_IMVID id;
37
38 /**
39 * Action Recommendation provided by IMV instance
40 */
41 TNC_IMV_Action_Recommendation rec;
42
43 /**
44 * Evaluation Result provided by IMV instance
45 */
46 TNC_IMV_Evaluation_Result eval;
47 };
48
49 /**
50 * Private data of a tnccs_20_t object.
51 */
52 struct private_tnccs_20_t {
53
54 /**
55 * Public tls_t interface.
56 */
57 tls_t public;
58
59 /**
60 * TNCC if TRUE, TNCS if FALSE
61 */
62 bool is_server;
63
64 /**
65 * Connection ID assigned to this TNCCS connection
66 */
67 TNC_ConnectionID connection_id;
68
69 /**
70 * Batch being constructed
71 */
72 chunk_t batch;
73
74 /**
75 * Action Recommendations and Evaluations Results provided by IMVs
76 */
77 linked_list_t *recommendations;
78
79 /**
80 * Mutex locking the recommendations list
81 */
82 mutex_t *recommendation_mutex;
83 };
84
85 METHOD(tnccs_t, send_message, void,
86 private_tnccs_20_t* this, TNC_BufferReference message,
87 TNC_UInt32 message_len,
88 TNC_MessageType message_type)
89 {
90 chunk_t msg = { message, message_len },
91 batch = this->batch;
92
93 DBG1(DBG_TNC, "TNCCS 2.0 send message");
94 this->batch = chunk_cat("mc", batch, msg);
95 }
96
97 METHOD(tnccs_t, provide_recommendation, void,
98 private_tnccs_20_t* this, TNC_IMVID id,
99 TNC_IMV_Action_Recommendation rec,
100 TNC_IMV_Evaluation_Result eval)
101 {
102 enumerator_t *enumerator;
103 recommendation_entry_t *entry;
104 bool found = FALSE;
105
106 DBG2(DBG_TNC, "IMV %u provides recommendation '%N' and evaluation '%N'",
107 id, action_recommendation_names, rec, evaluation_result_names, eval);
108
109 this->recommendation_mutex->lock(this->recommendation_mutex);
110 enumerator = this->recommendations->create_enumerator(this->recommendations);
111 while (enumerator->enumerate(enumerator, &entry))
112 {
113 if (entry->id == id)
114 {
115 found = TRUE;
116 break;
117 }
118 }
119 enumerator->destroy(enumerator);
120
121 if (!found)
122 {
123 entry = malloc_thing(recommendation_entry_t);
124 entry->id = id;
125 this->recommendations->insert_last(this->recommendations, entry);
126 }
127
128 /* Assign provided action recommendation and evaluation result */
129 entry->rec = rec;
130 entry->eval = eval;
131 this->recommendation_mutex->unlock(this->recommendation_mutex);
132 }
133
134 METHOD(tls_t, process, status_t,
135 private_tnccs_20_t *this, void *buf, size_t buflen)
136 {
137 char *pos;
138 size_t len;
139
140 if (this->is_server && !this->connection_id)
141 {
142 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
143 (tnccs_t*)this,
144 _send_message, _provide_recommendation);
145 charon->imvs->notify_connection_change(charon->imvs,
146 this->connection_id, TNC_CONNECTION_STATE_CREATE);
147 }
148 DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u",
149 buflen, this->connection_id);
150 DBG3(DBG_TNC, "%.*s", buflen, buf);
151 pos = strchr(buf, '|');
152 if (pos)
153 {
154 pos++;
155 len = buflen - ((char*)buf - pos);
156 }
157 else
158 {
159 pos = buf;
160 len = buflen;
161 }
162 if (this->is_server)
163 {
164 charon->imvs->receive_message(charon->imvs, this->connection_id,
165 pos, len, 0x0080ab31);
166 charon->imvs->batch_ending(charon->imvs, this->connection_id);
167 }
168 else
169 {
170 charon->imcs->receive_message(charon->imcs, this->connection_id,
171 pos, len, 0x0080ab31);
172 charon->imcs->batch_ending(charon->imcs, this->connection_id);
173 }
174 return NEED_MORE;
175 }
176
177 METHOD(tls_t, build, status_t,
178 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
179 {
180 char *msg = this->is_server ? "tncs->tncc 2.0|" : "tncc->tncs 2.0|";
181 size_t len;
182
183 this->batch = chunk_cat("cm", chunk_create(msg, strlen(msg)), this->batch);
184
185 if (!this->is_server && !this->connection_id)
186 {
187 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
188 (tnccs_t*)this, _send_message, NULL);
189 charon->imcs->notify_connection_change(charon->imcs,
190 this->connection_id, TNC_CONNECTION_STATE_CREATE);
191 charon->imcs->notify_connection_change(charon->imcs,
192 this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
193 charon->imcs->begin_handshake(charon->imcs, this->connection_id);
194 }
195
196 len = this->batch.len;
197 *msglen = len;
198 *buflen = len;
199 memcpy(buf, this->batch.ptr, len);
200
201 DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u",
202 len, this->connection_id);
203 DBG3(DBG_TNC, "%.*s", len, buf);
204 chunk_free(&this->batch);
205
206 return ALREADY_DONE;
207 }
208
209 METHOD(tls_t, is_server, bool,
210 private_tnccs_20_t *this)
211 {
212 return this->is_server;
213 }
214
215 METHOD(tls_t, get_purpose, tls_purpose_t,
216 private_tnccs_20_t *this)
217 {
218 return TLS_PURPOSE_EAP_TNC;
219 }
220
221 METHOD(tls_t, is_complete, bool,
222 private_tnccs_20_t *this)
223 {
224 return FALSE;
225 }
226
227 METHOD(tls_t, get_eap_msk, chunk_t,
228 private_tnccs_20_t *this)
229 {
230 return chunk_empty;
231 }
232
233 METHOD(tls_t, destroy, void,
234 private_tnccs_20_t *this)
235 {
236 charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
237 this->recommendations->destroy_function(this->recommendations, free);
238 this->recommendation_mutex->destroy(this->recommendation_mutex);
239 free(this->batch.ptr);
240 free(this);
241 }
242
243 /**
244 * See header
245 */
246 tls_t *tnccs_20_create(bool is_server)
247 {
248 private_tnccs_20_t *this;
249
250 INIT(this,
251 .public = {
252 .process = _process,
253 .build = _build,
254 .is_server = _is_server,
255 .get_purpose = _get_purpose,
256 .is_complete = _is_complete,
257 .get_eap_msk = _get_eap_msk,
258 .destroy = _destroy,
259 },
260 .is_server = is_server,
261 .recommendations = linked_list_create(),
262 .recommendation_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
263 );
264
265 return &this->public;
266 }