2 * Copyright (C) 2010 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "tnc_tnccs_manager.h"
19 #include <tnc/imv/imv_manager.h>
20 #include <tnc/imc/imc_manager.h>
21 #include <tnc/imv/imv_manager.h>
24 #include <utils/linked_list.h>
25 #include <threading/rwlock.h>
27 typedef struct private_tnc_tnccs_manager_t private_tnc_tnccs_manager_t
;
28 typedef struct tnccs_entry_t tnccs_entry_t
;
29 typedef struct tnccs_connection_entry_t tnccs_connection_entry_t
;
32 * TNCCS constructor entry
34 struct tnccs_entry_t
{
42 * constructor function to create instance
44 tnccs_constructor_t constructor
;
48 * TNCCS connection entry
50 struct tnccs_connection_entry_t
{
63 * TNCCS send message function
65 tnccs_send_message_t send_message
;
68 * TNCCS request handshake retry flag
70 bool *request_handshake_retry
;
73 * collection of IMV recommendations
75 recommendations_t
*recs
;
79 * private data of tnc_tnccs_manager
81 struct private_tnc_tnccs_manager_t
{
86 tnccs_manager_t
public;
89 * list of TNCCS protocol entries
91 linked_list_t
*protocols
;
94 * rwlock to lock the TNCCS protocol entries
96 rwlock_t
*protocol_lock
;
99 * connection ID counter
101 TNC_ConnectionID connection_id
;
104 * list of TNCCS connection entries
106 linked_list_t
*connections
;
109 * rwlock to lock TNCCS connection entries
111 rwlock_t
*connection_lock
;
115 METHOD(tnccs_manager_t
, add_method
, void,
116 private_tnc_tnccs_manager_t
*this, tnccs_type_t type
,
117 tnccs_constructor_t constructor
)
119 tnccs_entry_t
*entry
;
121 entry
= malloc_thing(tnccs_entry_t
);
123 entry
->constructor
= constructor
;
125 this->protocol_lock
->write_lock(this->protocol_lock
);
126 this->protocols
->insert_last(this->protocols
, entry
);
127 this->protocol_lock
->unlock(this->protocol_lock
);
130 METHOD(tnccs_manager_t
, remove_method
, void,
131 private_tnc_tnccs_manager_t
*this, tnccs_constructor_t constructor
)
133 enumerator_t
*enumerator
;
134 tnccs_entry_t
*entry
;
136 this->protocol_lock
->write_lock(this->protocol_lock
);
137 enumerator
= this->protocols
->create_enumerator(this->protocols
);
138 while (enumerator
->enumerate(enumerator
, &entry
))
140 if (constructor
== entry
->constructor
)
142 this->protocols
->remove_at(this->protocols
, enumerator
);
146 enumerator
->destroy(enumerator
);
147 this->protocol_lock
->unlock(this->protocol_lock
);
150 METHOD(tnccs_manager_t
, create_instance
, tnccs_t
*,
151 private_tnc_tnccs_manager_t
*this, tnccs_type_t type
, bool is_server
)
153 enumerator_t
*enumerator
;
154 tnccs_entry_t
*entry
;
155 tnccs_t
*protocol
= NULL
;
157 this->protocol_lock
->read_lock(this->protocol_lock
);
158 enumerator
= this->protocols
->create_enumerator(this->protocols
);
159 while (enumerator
->enumerate(enumerator
, &entry
))
161 if (type
== entry
->type
)
163 protocol
= entry
->constructor(is_server
);
170 enumerator
->destroy(enumerator
);
171 this->protocol_lock
->unlock(this->protocol_lock
);
176 METHOD(tnccs_manager_t
, create_connection
, TNC_ConnectionID
,
177 private_tnc_tnccs_manager_t
*this, tnccs_t
*tnccs
,
178 tnccs_send_message_t send_message
, bool* request_handshake_retry
,
179 recommendations_t
**recs
)
181 tnccs_connection_entry_t
*entry
;
183 entry
= malloc_thing(tnccs_connection_entry_t
);
184 entry
->tnccs
= tnccs
;
185 entry
->send_message
= send_message
;
186 entry
->request_handshake_retry
= request_handshake_retry
;
189 /* we assume a TNC Server needing recommendations from IMVs */
192 DBG1(DBG_TNC
, "no IMV manager available!");
196 entry
->recs
= tnc
->imvs
->create_recommendations(tnc
->imvs
);
201 /* we assume a TNC Client */
204 DBG1(DBG_TNC
, "no IMC manager available!");
210 this->connection_lock
->write_lock(this->connection_lock
);
211 entry
->id
= ++this->connection_id
;
212 this->connections
->insert_last(this->connections
, entry
);
213 this->connection_lock
->unlock(this->connection_lock
);
215 DBG1(DBG_TNC
, "assigned TNCCS Connection ID %u", entry
->id
);
219 METHOD(tnccs_manager_t
, remove_connection
, void,
220 private_tnc_tnccs_manager_t
*this, TNC_ConnectionID id
, bool is_server
)
222 enumerator_t
*enumerator
;
223 tnccs_connection_entry_t
*entry
;
229 tnc
->imvs
->notify_connection_change(tnc
->imvs
, id
,
230 TNC_CONNECTION_STATE_DELETE
);
237 tnc
->imcs
->notify_connection_change(tnc
->imcs
, id
,
238 TNC_CONNECTION_STATE_DELETE
);
242 this->connection_lock
->write_lock(this->connection_lock
);
243 enumerator
= this->connections
->create_enumerator(this->connections
);
244 while (enumerator
->enumerate(enumerator
, &entry
))
248 this->connections
->remove_at(this->connections
, enumerator
);
251 entry
->recs
->destroy(entry
->recs
);
254 DBG1(DBG_TNC
, "removed TNCCS Connection ID %u", id
);
257 enumerator
->destroy(enumerator
);
258 this->connection_lock
->unlock(this->connection_lock
);
261 METHOD(tnccs_manager_t
, request_handshake_retry
, TNC_Result
,
262 private_tnc_tnccs_manager_t
*this, bool is_imc
, TNC_UInt32 imcv_id
,
264 TNC_RetryReason reason
)
266 enumerator_t
*enumerator
;
267 tnccs_connection_entry_t
*entry
;
269 if (id
== TNC_CONNECTIONID_ANY
)
271 DBG2(DBG_TNC
, "%s %u requests handshake retry for all connections "
272 "(reason: %u)", is_imc ?
"IMC":"IMV", reason
);
276 DBG2(DBG_TNC
, "%s %u requests handshake retry for Connection ID %u "
277 "(reason: %u)", is_imc ?
"IMC":"IMV", imcv_id
, id
, reason
);
279 this->connection_lock
->read_lock(this->connection_lock
);
280 enumerator
= this->connections
->create_enumerator(this->connections
);
281 while (enumerator
->enumerate(enumerator
, &entry
))
283 if (id
== TNC_CONNECTIONID_ANY
|| id
== entry
->id
)
285 *entry
->request_handshake_retry
= TRUE
;
289 enumerator
->destroy(enumerator
);
290 this->connection_lock
->unlock(this->connection_lock
);
292 return TNC_RESULT_SUCCESS
;
295 METHOD(tnccs_manager_t
, send_message
, TNC_Result
,
296 private_tnc_tnccs_manager_t
*this, TNC_IMCID imc_id
, TNC_IMVID imv_id
,
298 TNC_UInt32 msg_flags
,
299 TNC_BufferReference msg
,
301 TNC_VendorID msg_vid
,
302 TNC_MessageSubtype msg_subtype
)
305 enumerator_t
*enumerator
;
306 tnccs_connection_entry_t
*entry
;
307 tnccs_send_message_t send_message
= NULL
;
308 tnccs_t
*tnccs
= NULL
;
310 if (msg_vid
== TNC_VENDORID_ANY
|| msg_subtype
== TNC_SUBTYPE_ANY
)
312 DBG1(DBG_TNC
, "not sending message of invalid type 0x%02x/0x%08x",
313 msg_vid
, msg_subtype
);
314 return TNC_RESULT_INVALID_PARAMETER
;
317 this->connection_lock
->read_lock(this->connection_lock
);
318 enumerator
= this->connections
->create_enumerator(this->connections
);
319 while (enumerator
->enumerate(enumerator
, &entry
))
323 tnccs
= entry
->tnccs
;
324 send_message
= entry
->send_message
;
328 enumerator
->destroy(enumerator
);
329 this->connection_lock
->unlock(this->connection_lock
);
331 if (tnccs
&& send_message
)
333 return send_message(tnccs
, imc_id
, imv_id
, msg_flags
, msg
, msg_len
,
334 msg_vid
, msg_subtype
);
336 return TNC_RESULT_FATAL
;
339 METHOD(tnccs_manager_t
, provide_recommendation
, TNC_Result
,
340 private_tnc_tnccs_manager_t
*this, TNC_IMVID imv_id
,
342 TNC_IMV_Action_Recommendation rec
,
343 TNC_IMV_Evaluation_Result eval
)
345 enumerator_t
*enumerator
;
346 tnccs_connection_entry_t
*entry
;
347 recommendations_t
*recs
= NULL
;
349 this->connection_lock
->read_lock(this->connection_lock
);
350 enumerator
= this->connections
->create_enumerator(this->connections
);
351 while (enumerator
->enumerate(enumerator
, &entry
))
359 enumerator
->destroy(enumerator
);
360 this->connection_lock
->unlock(this->connection_lock
);
364 recs
->provide_recommendation(recs
, imv_id
, rec
, eval
);
365 return TNC_RESULT_SUCCESS
;
367 return TNC_RESULT_FATAL
;
370 METHOD(tnccs_manager_t
, get_attribute
, TNC_Result
,
371 private_tnc_tnccs_manager_t
*this, TNC_IMVID imv_id
,
373 TNC_AttributeID attribute_id
,
374 TNC_UInt32 buffer_len
,
375 TNC_BufferReference buffer
,
376 TNC_UInt32
*out_value_len
)
378 enumerator_t
*enumerator
;
379 tnccs_connection_entry_t
*entry
;
380 recommendations_t
*recs
= NULL
;
382 if (id
== TNC_CONNECTIONID_ANY
||
383 attribute_id
!= TNC_ATTRIBUTEID_PREFERRED_LANGUAGE
)
385 return TNC_RESULT_INVALID_PARAMETER
;
388 this->connection_lock
->read_lock(this->connection_lock
);
389 enumerator
= this->connections
->create_enumerator(this->connections
);
390 while (enumerator
->enumerate(enumerator
, &entry
))
398 enumerator
->destroy(enumerator
);
399 this->connection_lock
->unlock(this->connection_lock
);
405 pref_lang
= recs
->get_preferred_language(recs
);
406 if (pref_lang
.len
== 0)
408 return TNC_RESULT_INVALID_PARAMETER
;
410 *out_value_len
= pref_lang
.len
;
411 if (buffer
&& buffer_len
>= pref_lang
.len
)
413 memcpy(buffer
, pref_lang
.ptr
, pref_lang
.len
);
415 return TNC_RESULT_SUCCESS
;
417 return TNC_RESULT_INVALID_PARAMETER
;
420 METHOD(tnccs_manager_t
, set_attribute
, TNC_Result
,
421 private_tnc_tnccs_manager_t
*this, TNC_IMVID imv_id
,
423 TNC_AttributeID attribute_id
,
424 TNC_UInt32 buffer_len
,
425 TNC_BufferReference buffer
)
427 enumerator_t
*enumerator
;
428 tnccs_connection_entry_t
*entry
;
429 recommendations_t
*recs
= NULL
;
431 if (id
== TNC_CONNECTIONID_ANY
||
432 (attribute_id
!= TNC_ATTRIBUTEID_REASON_STRING
&&
433 attribute_id
!= TNC_ATTRIBUTEID_REASON_LANGUAGE
))
435 return TNC_RESULT_INVALID_PARAMETER
;
438 this->connection_lock
->read_lock(this->connection_lock
);
439 enumerator
= this->connections
->create_enumerator(this->connections
);
440 while (enumerator
->enumerate(enumerator
, &entry
))
448 enumerator
->destroy(enumerator
);
449 this->connection_lock
->unlock(this->connection_lock
);
453 chunk_t attribute
= { buffer
, buffer_len
};
455 if (attribute_id
== TNC_ATTRIBUTEID_REASON_STRING
)
457 return recs
->set_reason_string(recs
, imv_id
, attribute
);
461 return recs
->set_reason_language(recs
, imv_id
, attribute
);
464 return TNC_RESULT_INVALID_PARAMETER
;
467 METHOD(tnccs_manager_t
, destroy
, void,
468 private_tnc_tnccs_manager_t
*this)
470 this->protocols
->destroy_function(this->protocols
, free
);
471 this->protocol_lock
->destroy(this->protocol_lock
);
472 this->connections
->destroy_function(this->connections
, free
);
473 this->connection_lock
->destroy(this->connection_lock
);
480 tnccs_manager_t
*tnc_tnccs_manager_create()
482 private_tnc_tnccs_manager_t
*this;
486 .add_method
= _add_method
,
487 .remove_method
= _remove_method
,
488 .create_instance
= _create_instance
,
489 .create_connection
= _create_connection
,
490 .remove_connection
= _remove_connection
,
491 .request_handshake_retry
= _request_handshake_retry
,
492 .send_message
= _send_message
,
493 .provide_recommendation
= _provide_recommendation
,
494 .get_attribute
= _get_attribute
,
495 .set_attribute
= _set_attribute
,
498 .protocols
= linked_list_create(),
499 .connections
= linked_list_create(),
500 .protocol_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
501 .connection_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
504 return &this->public;