2 * Copyright (C) 2010 Sansar Choinyanbuu
3 * Copyright (C) 2010-2013 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
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>.
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
18 #include "batch/pb_tnc_batch.h"
19 #include "messages/pb_tnc_msg.h"
20 #include "messages/ietf/pb_pa_msg.h"
21 #include "messages/ietf/pb_error_msg.h"
22 #include "messages/ietf/pb_assessment_result_msg.h"
23 #include "messages/ietf/pb_access_recommendation_msg.h"
24 #include "messages/ietf/pb_remediation_parameters_msg.h"
25 #include "messages/ietf/pb_reason_string_msg.h"
26 #include "messages/ietf/pb_language_preference_msg.h"
27 #include "state_machine/pb_tnc_state_machine.h"
29 #include <tncif_names.h>
30 #include <tncif_pa_subtypes.h>
33 #include <tnc/tnccs/tnccs_manager.h>
34 #include <tnc/imc/imc_manager.h>
35 #include <tnc/imv/imv_manager.h>
37 #include <threading/mutex.h>
38 #include <utils/debug.h>
39 #include <collections/linked_list.h>
42 typedef struct private_tnccs_20_t private_tnccs_20_t
;
45 * Private data of a tnccs_20_t object.
47 struct private_tnccs_20_t
{
50 * Public tnccs_t interface.
55 * TNCC if TRUE, TNCS if FALSE
62 identification_t
*server
;
67 identification_t
*peer
;
70 * Underlying TNC IF-T transport protocol
72 tnc_ift_type_t transport
;
75 * Type of TNC client authentication
80 * PB-TNC State Machine
82 pb_tnc_state_machine_t
*state_machine
;
85 * Connection ID assigned to this TNCCS connection
87 TNC_ConnectionID connection_id
;
90 * PB-TNC messages to be sent
92 linked_list_t
*messages
;
95 * Type of PB-TNC batch being constructed
97 pb_tnc_batch_type_t batch_type
;
100 * Maximum PB-TNC batch size
102 size_t max_batch_len
;
105 * Maximum PA-TNC message size
110 * Mutex locking the batch in construction
115 * Flag set while processing
120 * Flag set by IMC/IMV RequestHandshakeRetry() function
122 bool request_handshake_retry
;
125 * SendMessage() by IMC/IMV only allowed if flag is set
130 * Set of IMV recommendations (TNC Server only)
132 recommendations_t
*recs
;
135 * Callback function to communicate recommendation (TNC Server only)
140 * Data to pass to callback function (TNC Server only)
147 * If the batch type changes then delete all accumulated PB-TNC messages
149 void change_batch_type(private_tnccs_20_t
*this, pb_tnc_batch_type_t batch_type
)
153 if (batch_type
!= this->batch_type
)
155 if (this->batch_type
!= PB_BATCH_NONE
)
157 DBG1(DBG_TNC
, "cancelling PB-TNC %N batch",
158 pb_tnc_batch_type_names
, this->batch_type
);
160 while (this->messages
->remove_last(this->messages
,
161 (void**)&msg
) == SUCCESS
)
166 this->batch_type
= batch_type
;
170 METHOD(tnccs_t
, send_msg
, TNC_Result
,
171 private_tnccs_20_t
* this, TNC_IMCID imc_id
, TNC_IMVID imv_id
,
172 TNC_UInt32 msg_flags
,
173 TNC_BufferReference msg
,
175 TNC_VendorID msg_vid
,
176 TNC_MessageSubtype msg_subtype
)
178 pb_tnc_msg_t
*pb_tnc_msg
;
179 pb_tnc_batch_type_t batch_type
;
180 enum_name_t
*pa_subtype_names
;
185 DBG1(DBG_TNC
, "%s %u not allowed to call SendMessage()",
186 this->is_server ?
"IMV" : "IMC",
187 this->is_server ? imv_id
: imc_id
);
188 return TNC_RESULT_ILLEGAL_OPERATION
;
190 excl
= (msg_flags
& TNC_MESSAGE_FLAGS_EXCLUSIVE
) != 0;
192 pb_tnc_msg
= pb_pa_msg_create(msg_vid
, msg_subtype
, imc_id
, imv_id
,
193 excl
, chunk_create(msg
, msg_len
));
195 pa_subtype_names
= get_pa_subtype_names(msg_vid
);
196 if (pa_subtype_names
)
198 DBG2(DBG_TNC
, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
199 pen_names
, msg_vid
, pa_subtype_names
, msg_subtype
,
200 msg_vid
, msg_subtype
);
204 DBG2(DBG_TNC
, "creating PB-PA message type '%N' 0x%06x/0x%08x",
205 pen_names
, msg_vid
, msg_vid
, msg_subtype
);
208 /* adding PA message to SDATA or CDATA batch only */
209 batch_type
= this->is_server ? PB_BATCH_SDATA
: PB_BATCH_CDATA
;
210 this->mutex
->lock(this->mutex
);
211 if (this->batch_type
== PB_BATCH_NONE
)
213 this->batch_type
= batch_type
;
215 if (this->batch_type
== batch_type
)
217 this->messages
->insert_last(this->messages
, pb_tnc_msg
);
221 pb_tnc_msg
->destroy(pb_tnc_msg
);
223 this->mutex
->unlock(this->mutex
);
224 return TNC_RESULT_SUCCESS
;
228 * Handle a single PB-TNC IETF standard message according to its type
230 static void handle_ietf_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
232 pen_type_t msg_type
= msg
->get_type(msg
);
234 switch (msg_type
.type
)
236 case PB_MSG_EXPERIMENTAL
:
242 pen_type_t msg_subtype
;
243 u_int16_t imc_id
, imv_id
;
246 enum_name_t
*pa_subtype_names
;
248 pa_msg
= (pb_pa_msg_t
*)msg
;
249 msg_subtype
= pa_msg
->get_subtype(pa_msg
);
250 msg_body
= pa_msg
->get_body(pa_msg
);
251 imc_id
= pa_msg
->get_collector_id(pa_msg
);
252 imv_id
= pa_msg
->get_validator_id(pa_msg
);
253 excl
= pa_msg
->get_exclusive_flag(pa_msg
);
255 pa_subtype_names
= get_pa_subtype_names(msg_subtype
.vendor_id
);
256 if (pa_subtype_names
)
258 DBG2(DBG_TNC
, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
259 pen_names
, msg_subtype
.vendor_id
, pa_subtype_names
,
260 msg_subtype
.type
, msg_subtype
.vendor_id
, msg_subtype
.type
);
264 DBG2(DBG_TNC
, "handling PB-PA message type '%N' 0x%06x/0x%08x",
265 pen_names
, msg_subtype
.vendor_id
, msg_subtype
.vendor_id
,
269 this->send_msg
= TRUE
;
272 tnc
->imvs
->receive_message(tnc
->imvs
, this->connection_id
,
273 excl
, msg_body
.ptr
, msg_body
.len
,
274 msg_subtype
.vendor_id
,
275 msg_subtype
.type
, imc_id
, imv_id
);
279 tnc
->imcs
->receive_message(tnc
->imcs
, this->connection_id
,
280 excl
, msg_body
.ptr
, msg_body
.len
,
281 msg_subtype
.vendor_id
,
282 msg_subtype
.type
, imv_id
, imc_id
);
284 this->send_msg
= FALSE
;
287 case PB_MSG_ASSESSMENT_RESULT
:
289 pb_assessment_result_msg_t
*assess_msg
;
292 assess_msg
= (pb_assessment_result_msg_t
*)msg
;
293 result
= assess_msg
->get_assessment_result(assess_msg
);
294 DBG1(DBG_TNC
, "PB-TNC assessment result is '%N'",
295 TNC_IMV_Evaluation_Result_names
, result
);
298 case PB_MSG_ACCESS_RECOMMENDATION
:
300 pb_access_recommendation_msg_t
*rec_msg
;
301 pb_access_recommendation_code_t rec
;
302 TNC_ConnectionState state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
304 rec_msg
= (pb_access_recommendation_msg_t
*)msg
;
305 rec
= rec_msg
->get_access_recommendation(rec_msg
);
306 DBG1(DBG_TNC
, "PB-TNC access recommendation is '%N'",
307 pb_access_recommendation_code_names
, rec
);
310 case PB_REC_ACCESS_ALLOWED
:
311 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
313 case PB_REC_ACCESS_DENIED
:
314 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
316 case PB_REC_QUARANTINED
:
317 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
319 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
323 case PB_MSG_REMEDIATION_PARAMETERS
:
325 pb_remediation_parameters_msg_t
*rem_msg
;
326 pen_type_t parameters_type
;
327 chunk_t parameters
, string
, lang_code
;
329 rem_msg
= (pb_remediation_parameters_msg_t
*)msg
;
330 parameters_type
= rem_msg
->get_parameters_type(rem_msg
);
331 parameters
= rem_msg
->get_parameters(rem_msg
);
333 if (parameters_type
.vendor_id
== PEN_IETF
)
335 switch (parameters_type
.type
)
337 case PB_REMEDIATION_URI
:
338 DBG1(DBG_TNC
, "remediation uri: %.*s",
339 parameters
.len
, parameters
.ptr
);
341 case PB_REMEDIATION_STRING
:
342 string
= rem_msg
->get_string(rem_msg
, &lang_code
);
343 DBG1(DBG_TNC
, "remediation string: [%.*s]\n%.*s",
344 lang_code
.len
, lang_code
.ptr
,
345 string
.len
, string
.ptr
);
348 DBG1(DBG_TNC
, "remediation parameters: %B", ¶meters
);
353 DBG1(DBG_TNC
, "remediation parameters: %B", ¶meters
);
359 pb_error_msg_t
*err_msg
;
362 u_int16_t error_code
;
364 err_msg
= (pb_error_msg_t
*)msg
;
365 fatal
= err_msg
->get_fatal_flag(err_msg
);
366 vendor_id
= err_msg
->get_vendor_id(err_msg
);
367 error_code
= err_msg
->get_error_code(err_msg
);
371 this->fatal_error
= TRUE
;
374 if (vendor_id
== PEN_IETF
)
378 case PB_ERROR_INVALID_PARAMETER
:
379 case PB_ERROR_UNSUPPORTED_MANDATORY_MSG
:
380 DBG1(DBG_TNC
, "received %s PB-TNC error '%N' "
382 fatal ?
"fatal" : "non-fatal",
383 pb_tnc_error_code_names
, error_code
,
384 err_msg
->get_offset(err_msg
));
386 case PB_ERROR_VERSION_NOT_SUPPORTED
:
387 DBG1(DBG_TNC
, "received %s PB-TNC error '%N' "
388 "caused by bad version 0x%02x",
389 fatal ?
"fatal" : "non-fatal",
390 pb_tnc_error_code_names
, error_code
,
391 err_msg
->get_bad_version(err_msg
));
393 case PB_ERROR_UNEXPECTED_BATCH_TYPE
:
394 case PB_ERROR_LOCAL_ERROR
:
396 DBG1(DBG_TNC
, "received %s PB-TNC error '%N'",
397 fatal ?
"fatal" : "non-fatal",
398 pb_tnc_error_code_names
, error_code
);
404 DBG1(DBG_TNC
, "received %s PB-TNC error (%u) "
405 "with Vendor ID 0x%06x",
406 fatal ?
"fatal" : "non-fatal",
407 error_code
, vendor_id
);
411 case PB_MSG_LANGUAGE_PREFERENCE
:
413 pb_language_preference_msg_t
*lang_msg
;
416 lang_msg
= (pb_language_preference_msg_t
*)msg
;
417 lang
= lang_msg
->get_language_preference(lang_msg
);
421 DBG2(DBG_TNC
, "setting language preference to '%.*s'",
422 (int)lang
.len
, lang
.ptr
);
423 this->recs
->set_preferred_language(this->recs
, lang
);
427 case PB_MSG_REASON_STRING
:
429 pb_reason_string_msg_t
*reason_msg
;
430 chunk_t reason_string
, language_code
;
432 reason_msg
= (pb_reason_string_msg_t
*)msg
;
433 reason_string
= reason_msg
->get_reason_string(reason_msg
);
434 language_code
= reason_msg
->get_language_code(reason_msg
);
435 DBG1(DBG_TNC
, "reason string is '%.*s' [%.*s]",
436 (int)reason_string
.len
, reason_string
.ptr
,
437 (int)language_code
.len
, language_code
.ptr
);
446 * Handle a single PB-TNC TCG standard message according to its type
448 static void handle_tcg_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
450 pen_type_t msg_type
= msg
->get_type(msg
);
452 switch (msg_type
.type
)
454 case PB_TCG_MSG_PDP_REFERRAL
:
455 /* TODO handle PDP Referral */
463 * Handle a single PB-TNC message according to its type
465 static void handle_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
467 pen_type_t msg_type
= msg
->get_type(msg
);
469 switch (msg_type
.vendor_id
)
472 handle_ietf_message(this, msg
);
475 handle_tcg_message(this, msg
);
483 * Build a CRETRY or SRETRY batch
485 static void build_retry_batch(private_tnccs_20_t
*this)
487 pb_tnc_batch_type_t batch_retry_type
;
489 batch_retry_type
= this->is_server ? PB_BATCH_SRETRY
: PB_BATCH_CRETRY
;
490 if (this->batch_type
== batch_retry_type
)
492 /* retry batch has already been selected */
496 change_batch_type(this, batch_retry_type
);
500 this->recs
->clear_recommendation(this->recs
);
501 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
502 TNC_CONNECTION_STATE_HANDSHAKE
);
506 METHOD(tls_t
, process
, status_t
,
507 private_tnccs_20_t
*this, void *buf
, size_t buflen
)
510 pb_tnc_batch_t
*batch
;
512 enumerator_t
*enumerator
;
515 if (this->is_server
&& !this->connection_id
)
517 this->connection_id
= tnc
->tnccs
->create_connection(tnc
->tnccs
,
518 TNCCS_2_0
, (tnccs_t
*)this, _send_msg
,
519 &this->request_handshake_retry
,
520 this->max_msg_len
, &this->recs
);
521 if (!this->connection_id
)
525 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
526 TNC_CONNECTION_STATE_CREATE
);
527 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
528 TNC_CONNECTION_STATE_HANDSHAKE
);
531 data
= chunk_create(buf
, buflen
);
532 DBG1(DBG_TNC
, "received TNCCS batch (%u bytes) for Connection ID %u",
533 data
.len
, this->connection_id
);
534 DBG3(DBG_TNC
, "%B", &data
);
535 batch
= pb_tnc_batch_create_from_data(this->is_server
, data
);
536 status
= batch
->process(batch
, this->state_machine
);
538 if (status
!= FAILED
)
540 enumerator_t
*enumerator
;
542 pb_tnc_batch_type_t batch_type
;
545 batch_type
= batch
->get_type(batch
);
547 if (batch_type
== PB_BATCH_CRETRY
)
549 /* Send an SRETRY batch in response */
550 this->mutex
->lock(this->mutex
);
551 build_retry_batch(this);
552 this->mutex
->unlock(this->mutex
);
554 else if (batch_type
== PB_BATCH_SRETRY
)
556 /* Restart the measurements */
557 tnc
->imcs
->notify_connection_change(tnc
->imcs
,
558 this->connection_id
, TNC_CONNECTION_STATE_HANDSHAKE
);
559 this->send_msg
= TRUE
;
560 tnc
->imcs
->begin_handshake(tnc
->imcs
, this->connection_id
);
561 this->send_msg
= FALSE
;
564 enumerator
= batch
->create_msg_enumerator(batch
);
565 while (enumerator
->enumerate(enumerator
, &msg
))
567 handle_message(this, msg
);
570 enumerator
->destroy(enumerator
);
572 /* received an empty CLOSE batch from PB-TNC client */
573 if (this->is_server
&& batch_type
== PB_BATCH_CLOSE
&& empty
)
575 batch
->destroy(batch
);
576 if (this->fatal_error
)
578 DBG1(DBG_TNC
, "a fatal PB-TNC error occurred, "
579 "terminating connection");
588 this->send_msg
= TRUE
;
591 tnc
->imvs
->batch_ending(tnc
->imvs
, this->connection_id
);
595 tnc
->imcs
->batch_ending(tnc
->imcs
, this->connection_id
);
597 this->send_msg
= FALSE
;
603 this->fatal_error
= TRUE
;
604 this->mutex
->lock(this->mutex
);
605 change_batch_type(this, PB_BATCH_CLOSE
);
606 this->mutex
->unlock(this->mutex
);
607 /* fall through to add error messages to outbound batch */
609 enumerator
= batch
->create_error_enumerator(batch
);
610 while (enumerator
->enumerate(enumerator
, &msg
))
612 this->mutex
->lock(this->mutex
);
613 this->messages
->insert_last(this->messages
, msg
->get_ref(msg
));
614 this->mutex
->unlock(this->mutex
);
616 enumerator
->destroy(enumerator
);
622 batch
->destroy(batch
);
628 * Build a RESULT batch if a final recommendation is available
630 static void check_and_build_recommendation(private_tnccs_20_t
*this)
632 TNC_IMV_Action_Recommendation rec
;
633 TNC_IMV_Evaluation_Result eval
;
634 TNC_ConnectionState state
;
636 chunk_t reason
, language
;
637 enumerator_t
*enumerator
;
639 pb_access_recommendation_code_t pb_rec
;
641 if (!this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
643 tnc
->imvs
->solicit_recommendation(tnc
->imvs
, this->connection_id
);
645 if (this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
647 this->batch_type
= PB_BATCH_RESULT
;
649 msg
= pb_assessment_result_msg_create(eval
);
650 this->messages
->insert_last(this->messages
, msg
);
653 * Map IMV Action Recommendation codes to PB Access Recommendation codes
654 * and communicate Access Recommendation to IMVs
658 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW
:
659 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
660 pb_rec
= PB_REC_ACCESS_ALLOWED
;
662 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
:
663 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
664 pb_rec
= PB_REC_QUARANTINED
;
666 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
:
667 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
:
669 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
670 pb_rec
= PB_REC_ACCESS_DENIED
;
672 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
675 msg
= pb_access_recommendation_msg_create(pb_rec
);
676 this->messages
->insert_last(this->messages
, msg
);
678 enumerator
= this->recs
->create_reason_enumerator(this->recs
);
679 while (enumerator
->enumerate(enumerator
, &id
, &reason
, &language
))
681 msg
= pb_reason_string_msg_create(reason
, language
);
682 this->messages
->insert_last(this->messages
, msg
);
684 enumerator
->destroy(enumerator
);
688 METHOD(tls_t
, build
, status_t
,
689 private_tnccs_20_t
*this, void *buf
, size_t *buflen
, size_t *msglen
)
692 pb_tnc_state_t state
;
694 /* Initialize the connection */
695 if (!this->is_server
&& !this->connection_id
)
700 this->connection_id
= tnc
->tnccs
->create_connection(tnc
->tnccs
,
701 TNCCS_2_0
, (tnccs_t
*)this, _send_msg
,
702 &this->request_handshake_retry
,
703 this->max_msg_len
, NULL
);
704 if (!this->connection_id
)
709 /* Create PB-TNC Language Preference message */
710 pref_lang
= tnc
->imcs
->get_preferred_language(tnc
->imcs
);
711 msg
= pb_language_preference_msg_create(chunk_create(pref_lang
,
713 this->mutex
->lock(this->mutex
);
714 this->batch_type
= PB_BATCH_CDATA
;
715 this->messages
->insert_last(this->messages
, msg
);
716 this->mutex
->unlock(this->mutex
);
718 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
719 TNC_CONNECTION_STATE_CREATE
);
720 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
721 TNC_CONNECTION_STATE_HANDSHAKE
);
722 this->send_msg
= TRUE
;
723 tnc
->imcs
->begin_handshake(tnc
->imcs
, this->connection_id
);
724 this->send_msg
= FALSE
;
727 state
= this->state_machine
->get_state(this->state_machine
);
729 if (this->fatal_error
&& state
== PB_STATE_END
)
731 DBG1(DBG_TNC
, "a fatal PB-TNC error occurred, terminating connection");
735 /* Do not allow any asynchronous IMCs or IMVs to add additional messages */
736 this->mutex
->lock(this->mutex
);
738 if (this->request_handshake_retry
)
740 if (state
!= PB_STATE_INIT
)
742 build_retry_batch(this);
745 /* Reset the flag for the next handshake retry request */
746 this->request_handshake_retry
= FALSE
;
749 if (this->is_server
&& state
== PB_STATE_SERVER_WORKING
&&
750 this->recs
->have_recommendation(this->recs
, NULL
, NULL
))
752 check_and_build_recommendation(this);
755 if (this->batch_type
== PB_BATCH_NONE
)
759 if (state
== PB_STATE_SERVER_WORKING
)
761 if (this->state_machine
->get_empty_cdata(this->state_machine
))
763 check_and_build_recommendation(this);
767 DBG2(DBG_TNC
, "no recommendation available yet, "
768 "sending empty PB-TNC SDATA batch");
769 this->batch_type
= PB_BATCH_SDATA
;
777 case PB_STATE_CLIENT_WORKING
:
778 DBG2(DBG_TNC
, "no client data to send, "
779 "sending empty PB-TNC CDATA batch");
780 this->batch_type
= PB_BATCH_CDATA
;
782 case PB_STATE_DECIDED
:
784 * In the DECIDED state and if no CRETRY is under way,
785 * a PB-TNC client replies with an empty CLOSE batch.
787 this->batch_type
= PB_BATCH_CLOSE
;
795 if (this->batch_type
!= PB_BATCH_NONE
)
797 pb_tnc_batch_t
*batch
;
801 enumerator_t
*enumerator
;
803 if (this->state_machine
->send_batch(this->state_machine
, this->batch_type
))
805 batch
= pb_tnc_batch_create(this->is_server
, this->batch_type
,
806 min(this->max_batch_len
, *buflen
));
808 enumerator
= this->messages
->create_enumerator(this->messages
);
809 while (enumerator
->enumerate(enumerator
, &msg
))
811 if (batch
->add_msg(batch
, msg
))
813 this->messages
->remove_at(this->messages
, enumerator
);
820 enumerator
->destroy(enumerator
);
823 data
= batch
->get_encoding(batch
);
824 DBG1(DBG_TNC
, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
825 pb_tnc_batch_type_names
, this->batch_type
, data
.len
,
826 this->connection_id
);
827 DBG3(DBG_TNC
, "%B", &data
);
831 memcpy(buf
, data
.ptr
, *buflen
);
832 batch
->destroy(batch
);
834 msg_count
= this->messages
->get_count(this->messages
);
837 DBG2(DBG_TNC
, "queued %d PB-TNC message%s for next %N batch",
838 msg_count
, (msg_count
== 1) ?
"" : "s",
839 pb_tnc_batch_type_names
, this->batch_type
);
843 this->batch_type
= PB_BATCH_NONE
;
846 status
= ALREADY_DONE
;
850 change_batch_type(this, PB_BATCH_NONE
);
851 status
= INVALID_STATE
;
856 DBG1(DBG_TNC
, "no PB-TNC batch to send");
857 status
= INVALID_STATE
;
859 this->mutex
->unlock(this->mutex
);
864 METHOD(tls_t
, is_server
, bool,
865 private_tnccs_20_t
*this)
867 return this->is_server
;
870 METHOD(tls_t
, get_server_id
, identification_t
*,
871 private_tnccs_20_t
*this)
876 METHOD(tls_t
, set_peer_id
, void,
877 private_tnccs_20_t
*this, identification_t
*id
)
879 DESTROY_IF(this->peer
);
880 this->peer
= id
->clone(id
);
883 METHOD(tls_t
, get_peer_id
, identification_t
*,
884 private_tnccs_20_t
*this)
889 METHOD(tls_t
, get_purpose
, tls_purpose_t
,
890 private_tnccs_20_t
*this)
892 return TLS_PURPOSE_EAP_TNC
;
895 METHOD(tls_t
, is_complete
, bool,
896 private_tnccs_20_t
*this)
898 TNC_IMV_Action_Recommendation rec
;
899 TNC_IMV_Evaluation_Result eval
;
901 if (this->recs
&& this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
903 return this->callback ?
this->callback(rec
, eval
) : TRUE
;
911 METHOD(tls_t
, get_eap_msk
, chunk_t
,
912 private_tnccs_20_t
*this)
917 METHOD(tls_t
, destroy
, void,
918 private_tnccs_20_t
*this)
920 tnc
->tnccs
->remove_connection(tnc
->tnccs
, this->connection_id
,
922 this->server
->destroy(this->server
);
923 this->peer
->destroy(this->peer
);
924 this->state_machine
->destroy(this->state_machine
);
925 this->mutex
->destroy(this->mutex
);
926 this->messages
->destroy_offset(this->messages
,
927 offsetof(pb_tnc_msg_t
, destroy
));
931 METHOD(tnccs_t
, get_transport
, tnc_ift_type_t
,
932 private_tnccs_20_t
*this)
934 return this->transport
;
937 METHOD(tnccs_t
, set_transport
, void,
938 private_tnccs_20_t
*this, tnc_ift_type_t transport
)
940 this->transport
= transport
;
943 METHOD(tnccs_t
, get_auth_type
, u_int32_t
,
944 private_tnccs_20_t
*this)
946 return this->auth_type
;
949 METHOD(tnccs_t
, set_auth_type
, void,
950 private_tnccs_20_t
*this, u_int32_t auth_type
)
952 this->auth_type
= auth_type
;
958 tnccs_t
* tnccs_20_create(bool is_server
,
959 identification_t
*server
, identification_t
*peer
,
960 tnc_ift_type_t transport
, tnccs_cb_t cb
)
962 private_tnccs_20_t
*this;
969 .is_server
= _is_server
,
970 .get_server_id
= _get_server_id
,
971 .set_peer_id
= _set_peer_id
,
972 .get_peer_id
= _get_peer_id
,
973 .get_purpose
= _get_purpose
,
974 .is_complete
= _is_complete
,
975 .get_eap_msk
= _get_eap_msk
,
978 .get_transport
= _get_transport
,
979 .set_transport
= _set_transport
,
980 .get_auth_type
= _get_auth_type
,
981 .set_auth_type
= _set_auth_type
,
983 .is_server
= is_server
,
984 .server
= server
->clone(server
),
985 .peer
= peer
->clone(peer
),
986 .transport
= transport
,
988 .state_machine
= pb_tnc_state_machine_create(is_server
),
989 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
990 .messages
= linked_list_create(),
991 .max_batch_len
= lib
->settings
->get_int(lib
->settings
,
992 "libtnccs.plugins.tnccs-20.max_batch_size", 65522),
993 .max_msg_len
= lib
->settings
->get_int(lib
->settings
,
994 "libtnccs.plugins.tnccs-20.max_message_size", 65490),
997 return &this->public;