make maximum PB-TNC batch size configurable
[strongswan.git] / src / libcharon / plugins / tnccs_20 / tnccs_20.c
1 /*
2 * Copyright (C) 2010 Sansar Choinyanbuu
3 * Copyright (C) 2010-2012 Andreas Steffen
4 * HSR 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 "tnccs_20.h"
18 #include "batch/pb_tnc_batch.h"
19 #include "messages/pb_tnc_msg.h"
20 #include "messages/pb_pa_msg.h"
21 #include "messages/pb_error_msg.h"
22 #include "messages/pb_assessment_result_msg.h"
23 #include "messages/pb_access_recommendation_msg.h"
24 #include "messages/pb_remediation_parameters_msg.h"
25 #include "messages/pb_reason_string_msg.h"
26 #include "messages/pb_language_preference_msg.h"
27 #include "state_machine/pb_tnc_state_machine.h"
28
29 #include <tncif_names.h>
30 #include <tncif_pa_subtypes.h>
31
32 #include <tnc/tnc.h>
33 #include <tnc/tnccs/tnccs_manager.h>
34 #include <tnc/imc/imc_manager.h>
35 #include <tnc/imv/imv_manager.h>
36
37 #include <debug.h>
38 #include <daemon.h>
39 #include <threading/mutex.h>
40 #include <utils/linked_list.h>
41 #include <pen/pen.h>
42
43 typedef struct private_tnccs_20_t private_tnccs_20_t;
44
45 /**
46 * Private data of a tnccs_20_t object.
47 */
48 struct private_tnccs_20_t {
49
50 /**
51 * Public tls_t interface.
52 */
53 tls_t public;
54
55 /**
56 * TNCC if TRUE, TNCS if FALSE
57 */
58 bool is_server;
59
60 /**
61 * PB-TNC State Machine
62 */
63 pb_tnc_state_machine_t *state_machine;
64
65 /**
66 * Connection ID assigned to this TNCCS connection
67 */
68 TNC_ConnectionID connection_id;
69
70 /**
71 * PB-TNC messages to be sent
72 */
73 linked_list_t *messages;
74
75 /**
76 * Type of PB-TNC batch being constructed
77 */
78 pb_tnc_batch_type_t batch_type;
79
80 /**
81 * Maximum PA-TNC batch size
82 */
83 size_t max_batch_len;
84
85 /**
86 * Mutex locking the batch in construction
87 */
88 mutex_t *mutex;
89
90 /**
91 * Flag set while processing
92 */
93 bool fatal_error;
94
95 /**
96 * Flag set by IMC/IMV RequestHandshakeRetry() function
97 */
98 bool request_handshake_retry;
99
100 /**
101 * SendMessage() by IMC/IMV only allowed if flag is set
102 */
103 bool send_msg;
104
105 /**
106 * Set of IMV recommendations (TNC Server only)
107 */
108 recommendations_t *recs;
109
110 };
111
112 /**
113 * If the batch type changes then delete all accumulated PB-TNC messages
114 */
115 void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type)
116 {
117 pb_tnc_msg_t *msg;
118
119 if (batch_type != this->batch_type)
120 {
121 if (this->batch_type != PB_BATCH_NONE)
122 {
123 DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
124 pb_tnc_batch_type_names, this->batch_type);
125
126 while (this->messages->remove_last(this->messages,
127 (void**)&msg) == SUCCESS)
128 {
129 msg->destroy(msg);
130 }
131 }
132 this->batch_type = batch_type;
133 }
134 }
135
136 METHOD(tnccs_t, send_msg, TNC_Result,
137 private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
138 TNC_UInt32 msg_flags,
139 TNC_BufferReference msg,
140 TNC_UInt32 msg_len,
141 TNC_VendorID msg_vid,
142 TNC_MessageSubtype msg_subtype)
143 {
144 pb_tnc_msg_t *pb_tnc_msg;
145 pb_tnc_batch_type_t batch_type;
146 enum_name_t *pa_subtype_names;
147 bool excl;
148
149 if (!this->send_msg)
150 {
151 DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
152 this->is_server ? "IMV" : "IMC",
153 this->is_server ? imv_id : imc_id);
154 return TNC_RESULT_ILLEGAL_OPERATION;
155 }
156 excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
157
158 pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
159 excl, chunk_create(msg, msg_len));
160
161 pa_subtype_names = get_pa_subtype_names(msg_vid);
162 if (pa_subtype_names)
163 {
164 DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
165 pen_names, msg_vid, pa_subtype_names, msg_subtype,
166 msg_vid, msg_subtype);
167 }
168 else
169 {
170 DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
171 pen_names, msg_vid, msg_vid, msg_subtype);
172 }
173
174 /* adding PA message to SDATA or CDATA batch only */
175 batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA;
176 this->mutex->lock(this->mutex);
177 if (this->batch_type == PB_BATCH_NONE)
178 {
179 this->batch_type = batch_type;
180 }
181 if (this->batch_type == batch_type)
182 {
183 this->messages->insert_last(this->messages, pb_tnc_msg);
184 }
185 else
186 {
187 pb_tnc_msg->destroy(pb_tnc_msg);
188 }
189 this->mutex->unlock(this->mutex);
190 return TNC_RESULT_SUCCESS;
191 }
192
193 /**
194 * Handle a single PB-TNC message according to its type
195 */
196 static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
197 {
198 switch (msg->get_type(msg))
199 {
200 case PB_MSG_EXPERIMENTAL:
201 /* nothing to do */
202 break;
203 case PB_MSG_PA:
204 {
205 pb_pa_msg_t *pa_msg;
206 u_int32_t msg_vid, msg_subtype;
207 u_int16_t imc_id, imv_id;
208 chunk_t msg_body;
209 bool excl;
210 enum_name_t *pa_subtype_names;
211
212 pa_msg = (pb_pa_msg_t*)msg;
213 msg_vid = pa_msg->get_vendor_id(pa_msg, &msg_subtype);
214 msg_body = pa_msg->get_body(pa_msg);
215 imc_id = pa_msg->get_collector_id(pa_msg);
216 imv_id = pa_msg->get_validator_id(pa_msg);
217 excl = pa_msg->get_exclusive_flag(pa_msg);
218
219 pa_subtype_names = get_pa_subtype_names(msg_vid);
220 if (pa_subtype_names)
221 {
222 DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
223 pen_names, msg_vid, pa_subtype_names, msg_subtype,
224 msg_vid, msg_subtype);
225 }
226 else
227 {
228 DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x",
229 pen_names, msg_vid, msg_vid, msg_subtype);
230 }
231
232 this->send_msg = TRUE;
233 if (this->is_server)
234 {
235 tnc->imvs->receive_message(tnc->imvs, this->connection_id,
236 excl, msg_body.ptr, msg_body.len,
237 msg_vid, msg_subtype, imc_id, imv_id);
238 }
239 else
240 {
241 tnc->imcs->receive_message(tnc->imcs, this->connection_id,
242 excl, msg_body.ptr, msg_body.len,
243 msg_vid, msg_subtype, imv_id, imc_id);
244 }
245 this->send_msg = FALSE;
246 break;
247 }
248 case PB_MSG_ASSESSMENT_RESULT:
249 {
250 pb_assessment_result_msg_t *assess_msg;
251 u_int32_t result;
252
253 assess_msg = (pb_assessment_result_msg_t*)msg;
254 result = assess_msg->get_assessment_result(assess_msg);
255 DBG1(DBG_TNC, "PB-TNC assessment result is '%N'",
256 TNC_IMV_Evaluation_Result_names, result);
257 break;
258 }
259 case PB_MSG_ACCESS_RECOMMENDATION:
260 {
261 pb_access_recommendation_msg_t *rec_msg;
262 pb_access_recommendation_code_t rec;
263 TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE;
264
265 rec_msg = (pb_access_recommendation_msg_t*)msg;
266 rec = rec_msg->get_access_recommendation(rec_msg);
267 DBG1(DBG_TNC, "PB-TNC access recommendation is '%N'",
268 pb_access_recommendation_code_names, rec);
269 switch (rec)
270 {
271 case PB_REC_ACCESS_ALLOWED:
272 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
273 break;
274 case PB_REC_ACCESS_DENIED:
275 state = TNC_CONNECTION_STATE_ACCESS_NONE;
276 break;
277 case PB_REC_QUARANTINED:
278 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
279 }
280 tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
281 state);
282 break;
283 }
284 case PB_MSG_REMEDIATION_PARAMETERS:
285 {
286 /* TODO : Remediation parameters message processing */
287 break;
288 }
289 case PB_MSG_ERROR:
290 {
291 pb_error_msg_t *err_msg;
292 bool fatal;
293 u_int32_t vendor_id;
294 u_int16_t error_code;
295
296 err_msg = (pb_error_msg_t*)msg;
297 fatal = err_msg->get_fatal_flag(err_msg);
298 vendor_id = err_msg->get_vendor_id(err_msg);
299 error_code = err_msg->get_error_code(err_msg);
300
301 if (fatal)
302 {
303 this->fatal_error = TRUE;
304 }
305
306 if (vendor_id == PEN_IETF)
307 {
308 switch (error_code)
309 {
310 case PB_ERROR_INVALID_PARAMETER:
311 case PB_ERROR_UNSUPPORTED_MANDATORY_MSG:
312 DBG1(DBG_TNC, "received %s PB-TNC error '%N' "
313 "(offset %u bytes)",
314 fatal ? "fatal" : "non-fatal",
315 pb_tnc_error_code_names, error_code,
316 err_msg->get_offset(err_msg));
317 break;
318 case PB_ERROR_VERSION_NOT_SUPPORTED:
319 DBG1(DBG_TNC, "received %s PB-TNC error '%N' "
320 "caused by bad version 0x%02x",
321 fatal ? "fatal" : "non-fatal",
322 pb_tnc_error_code_names, error_code,
323 err_msg->get_bad_version(err_msg));
324 break;
325 case PB_ERROR_UNEXPECTED_BATCH_TYPE:
326 case PB_ERROR_LOCAL_ERROR:
327 default:
328 DBG1(DBG_TNC, "received %s PB-TNC error '%N'",
329 fatal ? "fatal" : "non-fatal",
330 pb_tnc_error_code_names, error_code);
331 break;
332 }
333 }
334 else
335 {
336 DBG1(DBG_TNC, "received %s PB-TNC error (%u) "
337 "with Vendor ID 0x%06x",
338 fatal ? "fatal" : "non-fatal",
339 error_code, vendor_id);
340 }
341 break;
342 }
343 case PB_MSG_LANGUAGE_PREFERENCE:
344 {
345 pb_language_preference_msg_t *lang_msg;
346 chunk_t lang;
347
348 lang_msg = (pb_language_preference_msg_t*)msg;
349 lang = lang_msg->get_language_preference(lang_msg);
350
351 DBG2(DBG_TNC, "setting language preference to '%.*s'",
352 lang.len, lang.ptr);
353 this->recs->set_preferred_language(this->recs, lang);
354 break;
355 }
356 case PB_MSG_REASON_STRING:
357 {
358 pb_reason_string_msg_t *reason_msg;
359 chunk_t reason_string, language_code;
360
361 reason_msg = (pb_reason_string_msg_t*)msg;
362 reason_string = reason_msg->get_reason_string(reason_msg);
363 language_code = reason_msg->get_language_code(reason_msg);
364 DBG2(DBG_TNC, "reason string is '%.*s'", reason_string.len,
365 reason_string.ptr);
366 DBG2(DBG_TNC, "language code is '%.*s'", language_code.len,
367 language_code.ptr);
368 break;
369 }
370 default:
371 break;
372 }
373 }
374
375 /**
376 * Build a CRETRY or SRETRY batch
377 */
378 static void build_retry_batch(private_tnccs_20_t *this)
379 {
380 pb_tnc_batch_type_t batch_retry_type;
381
382 batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY;
383 if (this->batch_type == batch_retry_type)
384 {
385 /* retry batch has already been selected */
386 return;
387 }
388
389 change_batch_type(this, batch_retry_type);
390
391 if (this->is_server)
392 {
393 tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
394 TNC_CONNECTION_STATE_HANDSHAKE);
395 }
396 }
397
398 METHOD(tls_t, process, status_t,
399 private_tnccs_20_t *this, void *buf, size_t buflen)
400 {
401 chunk_t data;
402 pb_tnc_batch_t *batch;
403 pb_tnc_msg_t *msg;
404 enumerator_t *enumerator;
405 status_t status;
406
407 if (this->is_server && !this->connection_id)
408 {
409 this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
410 TNCCS_2_0, (tnccs_t*)this, _send_msg,
411 &this->request_handshake_retry, &this->recs);
412 if (!this->connection_id)
413 {
414 return FAILED;
415 }
416 tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
417 TNC_CONNECTION_STATE_CREATE);
418 tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
419 TNC_CONNECTION_STATE_HANDSHAKE);
420 }
421
422 data = chunk_create(buf, buflen);
423 DBG1(DBG_TNC, "received TNCCS batch (%u bytes) for Connection ID %u",
424 data.len, this->connection_id);
425 DBG3(DBG_TNC, "%B", &data);
426 batch = pb_tnc_batch_create_from_data(this->is_server, data);
427 status = batch->process(batch, this->state_machine);
428
429 if (status != FAILED)
430 {
431 enumerator_t *enumerator;
432 pb_tnc_msg_t *msg;
433 pb_tnc_batch_type_t batch_type;
434 bool empty = TRUE;
435
436 batch_type = batch->get_type(batch);
437
438 if (batch_type == PB_BATCH_CRETRY)
439 {
440 /* Send an SRETRY batch in response */
441 this->mutex->lock(this->mutex);
442 build_retry_batch(this);
443 this->mutex->unlock(this->mutex);
444 }
445 else if (batch_type == PB_BATCH_SRETRY)
446 {
447 /* Restart the measurements */
448 tnc->imcs->notify_connection_change(tnc->imcs,
449 this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
450 this->send_msg = TRUE;
451 tnc->imcs->begin_handshake(tnc->imcs, this->connection_id);
452 this->send_msg = FALSE;
453 }
454
455 enumerator = batch->create_msg_enumerator(batch);
456 while (enumerator->enumerate(enumerator, &msg))
457 {
458 handle_message(this, msg);
459 empty = FALSE;
460 }
461 enumerator->destroy(enumerator);
462
463 /* received an empty CLOSE batch from PB-TNC client */
464 if (this->is_server && batch_type == PB_BATCH_CLOSE && empty)
465 {
466 batch->destroy(batch);
467 if (this->fatal_error)
468 {
469 DBG1(DBG_TNC, "a fatal PB-TNC error occurred, "
470 "terminating connection");
471 return FAILED;
472 }
473 else
474 {
475 return SUCCESS;
476 }
477 }
478
479 this->send_msg = TRUE;
480 if (this->is_server)
481 {
482 tnc->imvs->batch_ending(tnc->imvs, this->connection_id);
483 }
484 else
485 {
486 tnc->imcs->batch_ending(tnc->imcs, this->connection_id);
487 }
488 this->send_msg = FALSE;
489 }
490
491 switch (status)
492 {
493 case FAILED:
494 this->fatal_error = TRUE;
495 this->mutex->lock(this->mutex);
496 change_batch_type(this, PB_BATCH_CLOSE);
497 this->mutex->unlock(this->mutex);
498 /* fall through to add error messages to outbound batch */
499 case VERIFY_ERROR:
500 enumerator = batch->create_error_enumerator(batch);
501 while (enumerator->enumerate(enumerator, &msg))
502 {
503 this->mutex->lock(this->mutex);
504 this->messages->insert_last(this->messages, msg->get_ref(msg));
505 this->mutex->unlock(this->mutex);
506 }
507 enumerator->destroy(enumerator);
508 break;
509 case SUCCESS:
510 default:
511 break;
512 }
513 batch->destroy(batch);
514
515 return NEED_MORE;
516 }
517
518 /**
519 * Build a RESULT batch if a final recommendation is available
520 */
521 static void check_and_build_recommendation(private_tnccs_20_t *this)
522 {
523 TNC_IMV_Action_Recommendation rec;
524 TNC_IMV_Evaluation_Result eval;
525 TNC_IMVID id;
526 chunk_t reason, language;
527 enumerator_t *enumerator;
528 pb_tnc_msg_t *msg;
529 pb_access_recommendation_code_t pb_rec;
530
531 if (!this->recs->have_recommendation(this->recs, &rec, &eval))
532 {
533 tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id);
534 }
535 if (this->recs->have_recommendation(this->recs, &rec, &eval))
536 {
537 this->batch_type = PB_BATCH_RESULT;
538
539 msg = pb_assessment_result_msg_create(eval);
540 this->messages->insert_last(this->messages, msg);
541
542 /**
543 * Map IMV Action Recommendation codes to PB Access Recommendation codes
544 */
545 switch (rec)
546 {
547 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
548 pb_rec = PB_REC_ACCESS_ALLOWED;
549 break;
550 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
551 pb_rec = PB_REC_QUARANTINED;
552 break;
553 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
554 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
555 default:
556 pb_rec = PB_REC_ACCESS_DENIED;
557 }
558 msg = pb_access_recommendation_msg_create(pb_rec);
559 this->messages->insert_last(this->messages, msg);
560
561 enumerator = this->recs->create_reason_enumerator(this->recs);
562 while (enumerator->enumerate(enumerator, &id, &reason, &language))
563 {
564 msg = pb_reason_string_msg_create(reason, language);
565 this->messages->insert_last(this->messages, msg);
566 }
567 enumerator->destroy(enumerator);
568 this->recs->clear_reasons(this->recs);
569 }
570 }
571
572 METHOD(tls_t, build, status_t,
573 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
574 {
575 status_t status;
576 pb_tnc_state_t state;
577
578 /* Initialize the connection */
579 if (!this->is_server && !this->connection_id)
580 {
581 pb_tnc_msg_t *msg;
582 char *pref_lang;
583
584 this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
585 TNCCS_2_0, (tnccs_t*)this, _send_msg,
586 &this->request_handshake_retry, NULL);
587 if (!this->connection_id)
588 {
589 return FAILED;
590 }
591
592 /* Create PB-TNC Language Preference message */
593 pref_lang = tnc->imcs->get_preferred_language(tnc->imcs);
594 msg = pb_language_preference_msg_create(chunk_create(pref_lang,
595 strlen(pref_lang)));
596 this->mutex->lock(this->mutex);
597 this->batch_type = PB_BATCH_CDATA;
598 this->messages->insert_last(this->messages, msg);
599 this->mutex->unlock(this->mutex);
600
601 tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
602 TNC_CONNECTION_STATE_CREATE);
603 tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
604 TNC_CONNECTION_STATE_HANDSHAKE);
605 this->send_msg = TRUE;
606 tnc->imcs->begin_handshake(tnc->imcs, this->connection_id);
607 this->send_msg = FALSE;
608 }
609
610 state = this->state_machine->get_state(this->state_machine);
611
612 if (this->is_server && this->fatal_error && state == PB_STATE_END)
613 {
614 DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection");
615 return FAILED;
616 }
617
618 /* Do not allow any asynchronous IMCs or IMVs to add additional messages */
619 this->mutex->lock(this->mutex);
620
621 if (this->request_handshake_retry)
622 {
623 if (state != PB_STATE_INIT)
624 {
625 build_retry_batch(this);
626 }
627
628 /* Reset the flag for the next handshake retry request */
629 this->request_handshake_retry = FALSE;
630 }
631
632 if (this->batch_type == PB_BATCH_NONE && this->is_server &&
633 state == PB_STATE_SERVER_WORKING)
634 {
635 check_and_build_recommendation(this);
636 }
637
638 if (this->batch_type != PB_BATCH_NONE)
639 {
640 pb_tnc_batch_t *batch;
641 pb_tnc_msg_t *msg;
642 chunk_t msg_value, data;
643 int msg_count;
644 size_t batch_len;
645 enumerator_t *enumerator;
646
647 if (this->state_machine->send_batch(this->state_machine, this->batch_type))
648 {
649 batch = pb_tnc_batch_create(this->is_server, this->batch_type);
650 batch_len = PB_TNC_BATCH_HEADER_SIZE;
651
652 enumerator = this->messages->create_enumerator(this->messages);
653 while (enumerator->enumerate(enumerator, &msg))
654 {
655 msg->build(msg);
656 msg_value = msg->get_encoding(msg);
657 batch_len += PB_TNC_HEADER_SIZE + msg_value.len;
658 if (batch_len > min(this->max_batch_len, *buflen))
659 {
660 /* message does not fit into batch of maximum size */
661 break;
662 }
663 batch->add_msg(batch, msg);
664 this->messages->remove_at(this->messages, enumerator);
665 }
666 enumerator->destroy(enumerator);
667
668 batch->build(batch);
669 data = batch->get_encoding(batch);
670 DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
671 pb_tnc_batch_type_names, this->batch_type, data.len,
672 this->connection_id);
673 DBG3(DBG_TNC, "%B", &data);
674
675 *buflen = data.len;
676 *msglen = 0;
677 memcpy(buf, data.ptr, *buflen);
678 batch->destroy(batch);
679
680 msg_count = this->messages->get_count(this->messages);
681 if (msg_count)
682 {
683 DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch",
684 msg_count, (msg_count == 1) ? "" : "s",
685 pb_tnc_batch_type_names, this->batch_type);
686 }
687 else
688 {
689 this->batch_type = PB_BATCH_NONE;
690 }
691
692 status = ALREADY_DONE;
693 }
694 else
695 {
696 change_batch_type(this, PB_BATCH_NONE);
697 status = INVALID_STATE;
698 }
699 }
700 else
701 {
702 DBG1(DBG_TNC, "no PB-TNC batch to send");
703 status = INVALID_STATE;
704 }
705 this->mutex->unlock(this->mutex);
706
707 return status;
708 }
709
710 METHOD(tls_t, is_server, bool,
711 private_tnccs_20_t *this)
712 {
713 return this->is_server;
714 }
715
716 METHOD(tls_t, get_purpose, tls_purpose_t,
717 private_tnccs_20_t *this)
718 {
719 return TLS_PURPOSE_EAP_TNC;
720 }
721
722 METHOD(tls_t, is_complete, bool,
723 private_tnccs_20_t *this)
724 {
725 TNC_IMV_Action_Recommendation rec;
726 TNC_IMV_Evaluation_Result eval;
727
728 if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval))
729 {
730 return tnc->imvs->enforce_recommendation(tnc->imvs, rec, eval);
731 }
732 else
733 {
734 return FALSE;
735 }
736 }
737
738 METHOD(tls_t, get_eap_msk, chunk_t,
739 private_tnccs_20_t *this)
740 {
741 return chunk_empty;
742 }
743
744 METHOD(tls_t, destroy, void,
745 private_tnccs_20_t *this)
746 {
747 tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id,
748 this->is_server);
749 this->state_machine->destroy(this->state_machine);
750 this->mutex->destroy(this->mutex);
751 this->messages->destroy_offset(this->messages,
752 offsetof(pb_tnc_msg_t, destroy));
753 free(this);
754 }
755
756 /**
757 * See header
758 */
759 tls_t *tnccs_20_create(bool is_server)
760 {
761 private_tnccs_20_t *this;
762
763 INIT(this,
764 .public = {
765 .process = _process,
766 .build = _build,
767 .is_server = _is_server,
768 .get_purpose = _get_purpose,
769 .is_complete = _is_complete,
770 .get_eap_msk = _get_eap_msk,
771 .destroy = _destroy,
772 },
773 .is_server = is_server,
774 .state_machine = pb_tnc_state_machine_create(is_server),
775 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
776 .messages = linked_list_create(),
777 .max_batch_len = lib->settings->get_int(lib->settings,
778 "%s.plugins.tnccs-20.max_batch_size", 65522,
779 charon->name),
780 );
781
782 return &this->public;
783 }