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 "messages/tcg/pb_pdp_referral_msg.h"
28 #include "state_machine/pb_tnc_state_machine.h"
30 #include <tncif_names.h>
31 #include <tncif_pa_subtypes.h>
34 #include <tnc/tnccs/tnccs_manager.h>
35 #include <tnc/imc/imc_manager.h>
36 #include <tnc/imv/imv_manager.h>
38 #include <threading/mutex.h>
39 #include <utils/debug.h>
40 #include <collections/linked_list.h>
43 typedef struct private_tnccs_20_t private_tnccs_20_t
;
46 * Private data of a tnccs_20_t object.
48 struct private_tnccs_20_t
{
51 * Public tnccs_t interface.
56 * TNCC if TRUE, TNCS if FALSE
63 identification_t
*server
;
68 identification_t
*peer
;
71 * Underlying TNC IF-T transport protocol
73 tnc_ift_type_t transport
;
76 * Type of TNC client authentication
81 * PB-TNC State Machine
83 pb_tnc_state_machine_t
*state_machine
;
86 * Connection ID assigned to this TNCCS connection
88 TNC_ConnectionID connection_id
;
91 * PB-TNC messages to be sent
93 linked_list_t
*messages
;
96 * Type of PB-TNC batch being constructed
98 pb_tnc_batch_type_t batch_type
;
101 * Maximum PB-TNC batch size
103 size_t max_batch_len
;
106 * Maximum PA-TNC message size
111 * Mutex locking the batch in construction
116 * Flag set while processing
121 * Flag set by IMC/IMV RequestHandshakeRetry() function
123 bool request_handshake_retry
;
126 * SendMessage() by IMC/IMV only allowed if flag is set
131 * Set of IMV recommendations (TNC Server only)
133 recommendations_t
*recs
;
136 * Callback function to communicate recommendation (TNC Server only)
141 * Data to pass to callback function (TNC Server only)
148 * If the batch type changes then delete all accumulated PB-TNC messages
150 void change_batch_type(private_tnccs_20_t
*this, pb_tnc_batch_type_t batch_type
)
154 if (batch_type
!= this->batch_type
)
156 if (this->batch_type
!= PB_BATCH_NONE
)
158 DBG1(DBG_TNC
, "cancelling PB-TNC %N batch",
159 pb_tnc_batch_type_names
, this->batch_type
);
161 while (this->messages
->remove_last(this->messages
,
162 (void**)&msg
) == SUCCESS
)
167 this->batch_type
= batch_type
;
171 METHOD(tnccs_t
, send_msg
, TNC_Result
,
172 private_tnccs_20_t
* this, TNC_IMCID imc_id
, TNC_IMVID imv_id
,
173 TNC_UInt32 msg_flags
,
174 TNC_BufferReference msg
,
176 TNC_VendorID msg_vid
,
177 TNC_MessageSubtype msg_subtype
)
179 pb_tnc_msg_t
*pb_tnc_msg
;
180 pb_tnc_batch_type_t batch_type
;
181 enum_name_t
*pa_subtype_names
;
186 DBG1(DBG_TNC
, "%s %u not allowed to call SendMessage()",
187 this->is_server ?
"IMV" : "IMC",
188 this->is_server ? imv_id
: imc_id
);
189 return TNC_RESULT_ILLEGAL_OPERATION
;
191 excl
= (msg_flags
& TNC_MESSAGE_FLAGS_EXCLUSIVE
) != 0;
193 pb_tnc_msg
= pb_pa_msg_create(msg_vid
, msg_subtype
, imc_id
, imv_id
,
194 excl
, chunk_create(msg
, msg_len
));
196 pa_subtype_names
= get_pa_subtype_names(msg_vid
);
197 if (pa_subtype_names
)
199 DBG2(DBG_TNC
, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
200 pen_names
, msg_vid
, pa_subtype_names
, msg_subtype
,
201 msg_vid
, msg_subtype
);
205 DBG2(DBG_TNC
, "creating PB-PA message type '%N' 0x%06x/0x%08x",
206 pen_names
, msg_vid
, msg_vid
, msg_subtype
);
209 /* adding PA message to SDATA or CDATA batch only */
210 batch_type
= this->is_server ? PB_BATCH_SDATA
: PB_BATCH_CDATA
;
211 this->mutex
->lock(this->mutex
);
212 if (this->batch_type
== PB_BATCH_NONE
)
214 this->batch_type
= batch_type
;
216 if (this->batch_type
== batch_type
)
218 this->messages
->insert_last(this->messages
, pb_tnc_msg
);
222 pb_tnc_msg
->destroy(pb_tnc_msg
);
224 this->mutex
->unlock(this->mutex
);
225 return TNC_RESULT_SUCCESS
;
229 * Handle a single PB-TNC IETF standard message according to its type
231 static void handle_ietf_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
233 pen_type_t msg_type
= msg
->get_type(msg
);
235 switch (msg_type
.type
)
237 case PB_MSG_EXPERIMENTAL
:
243 pen_type_t msg_subtype
;
244 u_int16_t imc_id
, imv_id
;
247 enum_name_t
*pa_subtype_names
;
249 pa_msg
= (pb_pa_msg_t
*)msg
;
250 msg_subtype
= pa_msg
->get_subtype(pa_msg
);
251 msg_body
= pa_msg
->get_body(pa_msg
);
252 imc_id
= pa_msg
->get_collector_id(pa_msg
);
253 imv_id
= pa_msg
->get_validator_id(pa_msg
);
254 excl
= pa_msg
->get_exclusive_flag(pa_msg
);
256 pa_subtype_names
= get_pa_subtype_names(msg_subtype
.vendor_id
);
257 if (pa_subtype_names
)
259 DBG2(DBG_TNC
, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
260 pen_names
, msg_subtype
.vendor_id
, pa_subtype_names
,
261 msg_subtype
.type
, msg_subtype
.vendor_id
, msg_subtype
.type
);
265 DBG2(DBG_TNC
, "handling PB-PA message type '%N' 0x%06x/0x%08x",
266 pen_names
, msg_subtype
.vendor_id
, msg_subtype
.vendor_id
,
270 this->send_msg
= TRUE
;
273 tnc
->imvs
->receive_message(tnc
->imvs
, this->connection_id
,
274 excl
, msg_body
.ptr
, msg_body
.len
,
275 msg_subtype
.vendor_id
,
276 msg_subtype
.type
, imc_id
, imv_id
);
280 tnc
->imcs
->receive_message(tnc
->imcs
, this->connection_id
,
281 excl
, msg_body
.ptr
, msg_body
.len
,
282 msg_subtype
.vendor_id
,
283 msg_subtype
.type
, imv_id
, imc_id
);
285 this->send_msg
= FALSE
;
288 case PB_MSG_ASSESSMENT_RESULT
:
290 pb_assessment_result_msg_t
*assess_msg
;
293 assess_msg
= (pb_assessment_result_msg_t
*)msg
;
294 result
= assess_msg
->get_assessment_result(assess_msg
);
295 DBG1(DBG_TNC
, "PB-TNC assessment result is '%N'",
296 TNC_IMV_Evaluation_Result_names
, result
);
299 case PB_MSG_ACCESS_RECOMMENDATION
:
301 pb_access_recommendation_msg_t
*rec_msg
;
302 pb_access_recommendation_code_t rec
;
303 TNC_ConnectionState state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
305 rec_msg
= (pb_access_recommendation_msg_t
*)msg
;
306 rec
= rec_msg
->get_access_recommendation(rec_msg
);
307 DBG1(DBG_TNC
, "PB-TNC access recommendation is '%N'",
308 pb_access_recommendation_code_names
, rec
);
311 case PB_REC_ACCESS_ALLOWED
:
312 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
314 case PB_REC_ACCESS_DENIED
:
315 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
317 case PB_REC_QUARANTINED
:
318 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
320 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
324 case PB_MSG_REMEDIATION_PARAMETERS
:
326 pb_remediation_parameters_msg_t
*rem_msg
;
327 pen_type_t parameters_type
;
328 chunk_t parameters
, string
, lang_code
;
330 rem_msg
= (pb_remediation_parameters_msg_t
*)msg
;
331 parameters_type
= rem_msg
->get_parameters_type(rem_msg
);
332 parameters
= rem_msg
->get_parameters(rem_msg
);
334 if (parameters_type
.vendor_id
== PEN_IETF
)
336 switch (parameters_type
.type
)
338 case PB_REMEDIATION_URI
:
339 DBG1(DBG_TNC
, "remediation uri: %.*s",
340 parameters
.len
, parameters
.ptr
);
342 case PB_REMEDIATION_STRING
:
343 string
= rem_msg
->get_string(rem_msg
, &lang_code
);
344 DBG1(DBG_TNC
, "remediation string: [%.*s]\n%.*s",
345 lang_code
.len
, lang_code
.ptr
,
346 string
.len
, string
.ptr
);
349 DBG1(DBG_TNC
, "remediation parameters: %B", ¶meters
);
354 DBG1(DBG_TNC
, "remediation parameters: %B", ¶meters
);
360 pb_error_msg_t
*err_msg
;
363 u_int16_t error_code
;
365 err_msg
= (pb_error_msg_t
*)msg
;
366 fatal
= err_msg
->get_fatal_flag(err_msg
);
367 vendor_id
= err_msg
->get_vendor_id(err_msg
);
368 error_code
= err_msg
->get_error_code(err_msg
);
372 this->fatal_error
= TRUE
;
375 if (vendor_id
== PEN_IETF
)
379 case PB_ERROR_INVALID_PARAMETER
:
380 case PB_ERROR_UNSUPPORTED_MANDATORY_MSG
:
381 DBG1(DBG_TNC
, "received %s PB-TNC error '%N' "
383 fatal ?
"fatal" : "non-fatal",
384 pb_tnc_error_code_names
, error_code
,
385 err_msg
->get_offset(err_msg
));
387 case PB_ERROR_VERSION_NOT_SUPPORTED
:
388 DBG1(DBG_TNC
, "received %s PB-TNC error '%N' "
389 "caused by bad version 0x%02x",
390 fatal ?
"fatal" : "non-fatal",
391 pb_tnc_error_code_names
, error_code
,
392 err_msg
->get_bad_version(err_msg
));
394 case PB_ERROR_UNEXPECTED_BATCH_TYPE
:
395 case PB_ERROR_LOCAL_ERROR
:
397 DBG1(DBG_TNC
, "received %s PB-TNC error '%N'",
398 fatal ?
"fatal" : "non-fatal",
399 pb_tnc_error_code_names
, error_code
);
405 DBG1(DBG_TNC
, "received %s PB-TNC error (%u) "
406 "with Vendor ID 0x%06x",
407 fatal ?
"fatal" : "non-fatal",
408 error_code
, vendor_id
);
412 case PB_MSG_LANGUAGE_PREFERENCE
:
414 pb_language_preference_msg_t
*lang_msg
;
417 lang_msg
= (pb_language_preference_msg_t
*)msg
;
418 lang
= lang_msg
->get_language_preference(lang_msg
);
422 DBG2(DBG_TNC
, "setting language preference to '%.*s'",
423 (int)lang
.len
, lang
.ptr
);
424 this->recs
->set_preferred_language(this->recs
, lang
);
428 case PB_MSG_REASON_STRING
:
430 pb_reason_string_msg_t
*reason_msg
;
431 chunk_t reason_string
, language_code
;
433 reason_msg
= (pb_reason_string_msg_t
*)msg
;
434 reason_string
= reason_msg
->get_reason_string(reason_msg
);
435 language_code
= reason_msg
->get_language_code(reason_msg
);
436 DBG1(DBG_TNC
, "reason string is '%.*s' [%.*s]",
437 (int)reason_string
.len
, reason_string
.ptr
,
438 (int)language_code
.len
, language_code
.ptr
);
447 * Handle a single PB-TNC TCG standard message according to its type
449 static void handle_tcg_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
451 pen_type_t msg_type
= msg
->get_type(msg
);
453 switch (msg_type
.type
)
455 case PB_TCG_MSG_PDP_REFERRAL
:
457 pb_pdp_referral_msg_t
*pdp_msg
;
458 pen_type_t pdp_id_type
;
460 u_int8_t pdp_protocol
;
463 pdp_msg
= (pb_pdp_referral_msg_t
*)msg
;
464 pdp_id_type
= pdp_msg
->get_identifier_type(pdp_msg
);
466 if (pdp_id_type
.vendor_id
== PEN_TCG
&&
467 pdp_id_type
.type
== PB_PDP_ID_FQDN
)
469 pdp_server
= pdp_msg
->get_fqdn(pdp_msg
, &pdp_protocol
,
471 if (pdp_protocol
!= 0)
473 DBG1(DBG_TNC
, "unsupported PDP transport protocol");
476 DBG1(DBG_TNC
, "PDP server '%.*s' is listening on port %u",
477 pdp_server
.len
, pdp_server
.ptr
, pdp_port
);
487 * Handle a single PB-TNC message according to its type
489 static void handle_message(private_tnccs_20_t
*this, pb_tnc_msg_t
*msg
)
491 pen_type_t msg_type
= msg
->get_type(msg
);
493 switch (msg_type
.vendor_id
)
496 handle_ietf_message(this, msg
);
499 handle_tcg_message(this, msg
);
507 * Build a CRETRY or SRETRY batch
509 static void build_retry_batch(private_tnccs_20_t
*this)
511 pb_tnc_batch_type_t batch_retry_type
;
513 batch_retry_type
= this->is_server ? PB_BATCH_SRETRY
: PB_BATCH_CRETRY
;
514 if (this->batch_type
== batch_retry_type
)
516 /* retry batch has already been selected */
520 change_batch_type(this, batch_retry_type
);
524 this->recs
->clear_recommendation(this->recs
);
525 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
526 TNC_CONNECTION_STATE_HANDSHAKE
);
530 METHOD(tls_t
, process
, status_t
,
531 private_tnccs_20_t
*this, void *buf
, size_t buflen
)
534 pb_tnc_batch_t
*batch
;
536 enumerator_t
*enumerator
;
537 identification_t
*pdp_server
;
541 if (this->is_server
&& !this->connection_id
)
543 this->connection_id
= tnc
->tnccs
->create_connection(tnc
->tnccs
,
544 TNCCS_2_0
, (tnccs_t
*)this, _send_msg
,
545 &this->request_handshake_retry
,
546 this->max_msg_len
, &this->recs
);
547 if (!this->connection_id
)
551 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
552 TNC_CONNECTION_STATE_CREATE
);
553 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
554 TNC_CONNECTION_STATE_HANDSHAKE
);
556 /* Send a PB-TNC TCG PDP Referral message if PDP is known */
557 pdp_server
= (identification_t
*)lib
->get(lib
, "pt-tls-server");
558 pdp_port
= (u_int16_t
*)lib
->get(lib
, "pt-tls-port");
560 if ((this->transport
== TNC_IFT_EAP_1_1
||
561 this->transport
== TNC_IFT_EAP_2_0
) && pdp_server
&& pdp_port
)
563 msg
= pb_pdp_referral_msg_create_from_fqdn(
564 pdp_server
->get_encoding(pdp_server
), *pdp_port
);
565 this->messages
->insert_last(this->messages
, msg
);
570 data
= chunk_create(buf
, buflen
);
571 DBG1(DBG_TNC
, "received TNCCS batch (%u bytes) for Connection ID %u",
572 data
.len
, this->connection_id
);
573 DBG3(DBG_TNC
, "%B", &data
);
574 batch
= pb_tnc_batch_create_from_data(this->is_server
, data
);
575 status
= batch
->process(batch
, this->state_machine
);
577 if (status
!= FAILED
)
579 enumerator_t
*enumerator
;
581 pb_tnc_batch_type_t batch_type
;
584 batch_type
= batch
->get_type(batch
);
586 if (batch_type
== PB_BATCH_CRETRY
)
588 /* Send an SRETRY batch in response */
589 this->mutex
->lock(this->mutex
);
590 build_retry_batch(this);
591 this->mutex
->unlock(this->mutex
);
593 else if (batch_type
== PB_BATCH_SRETRY
)
595 /* Restart the measurements */
596 tnc
->imcs
->notify_connection_change(tnc
->imcs
,
597 this->connection_id
, TNC_CONNECTION_STATE_HANDSHAKE
);
598 this->send_msg
= TRUE
;
599 tnc
->imcs
->begin_handshake(tnc
->imcs
, this->connection_id
);
600 this->send_msg
= FALSE
;
603 enumerator
= batch
->create_msg_enumerator(batch
);
604 while (enumerator
->enumerate(enumerator
, &msg
))
606 handle_message(this, msg
);
609 enumerator
->destroy(enumerator
);
611 /* received an empty CLOSE batch from PB-TNC client */
612 if (this->is_server
&& batch_type
== PB_BATCH_CLOSE
&& empty
)
614 batch
->destroy(batch
);
615 if (this->fatal_error
)
617 DBG1(DBG_TNC
, "a fatal PB-TNC error occurred, "
618 "terminating connection");
627 this->send_msg
= TRUE
;
630 tnc
->imvs
->batch_ending(tnc
->imvs
, this->connection_id
);
634 tnc
->imcs
->batch_ending(tnc
->imcs
, this->connection_id
);
636 this->send_msg
= FALSE
;
642 this->fatal_error
= TRUE
;
643 this->mutex
->lock(this->mutex
);
644 change_batch_type(this, PB_BATCH_CLOSE
);
645 this->mutex
->unlock(this->mutex
);
646 /* fall through to add error messages to outbound batch */
648 enumerator
= batch
->create_error_enumerator(batch
);
649 while (enumerator
->enumerate(enumerator
, &msg
))
651 this->mutex
->lock(this->mutex
);
652 this->messages
->insert_last(this->messages
, msg
->get_ref(msg
));
653 this->mutex
->unlock(this->mutex
);
655 enumerator
->destroy(enumerator
);
661 batch
->destroy(batch
);
667 * Build a RESULT batch if a final recommendation is available
669 static void check_and_build_recommendation(private_tnccs_20_t
*this)
671 TNC_IMV_Action_Recommendation rec
;
672 TNC_IMV_Evaluation_Result eval
;
673 TNC_ConnectionState state
;
675 chunk_t reason
, language
;
676 enumerator_t
*enumerator
;
678 pb_access_recommendation_code_t pb_rec
;
680 if (!this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
682 tnc
->imvs
->solicit_recommendation(tnc
->imvs
, this->connection_id
);
684 if (this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
686 this->batch_type
= PB_BATCH_RESULT
;
688 msg
= pb_assessment_result_msg_create(eval
);
689 this->messages
->insert_last(this->messages
, msg
);
692 * Map IMV Action Recommendation codes to PB Access Recommendation codes
693 * and communicate Access Recommendation to IMVs
697 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW
:
698 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
699 pb_rec
= PB_REC_ACCESS_ALLOWED
;
701 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
:
702 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
703 pb_rec
= PB_REC_QUARANTINED
;
705 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
:
706 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
:
708 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
709 pb_rec
= PB_REC_ACCESS_DENIED
;
711 tnc
->imvs
->notify_connection_change(tnc
->imvs
, this->connection_id
,
714 msg
= pb_access_recommendation_msg_create(pb_rec
);
715 this->messages
->insert_last(this->messages
, msg
);
717 enumerator
= this->recs
->create_reason_enumerator(this->recs
);
718 while (enumerator
->enumerate(enumerator
, &id
, &reason
, &language
))
720 msg
= pb_reason_string_msg_create(reason
, language
);
721 this->messages
->insert_last(this->messages
, msg
);
723 enumerator
->destroy(enumerator
);
727 METHOD(tls_t
, build
, status_t
,
728 private_tnccs_20_t
*this, void *buf
, size_t *buflen
, size_t *msglen
)
731 pb_tnc_state_t state
;
733 /* Initialize the connection */
734 if (!this->is_server
&& !this->connection_id
)
739 this->connection_id
= tnc
->tnccs
->create_connection(tnc
->tnccs
,
740 TNCCS_2_0
, (tnccs_t
*)this, _send_msg
,
741 &this->request_handshake_retry
,
742 this->max_msg_len
, NULL
);
743 if (!this->connection_id
)
748 /* Create PB-TNC Language Preference message */
749 pref_lang
= tnc
->imcs
->get_preferred_language(tnc
->imcs
);
750 msg
= pb_language_preference_msg_create(chunk_create(pref_lang
,
752 this->mutex
->lock(this->mutex
);
753 this->batch_type
= PB_BATCH_CDATA
;
754 this->messages
->insert_last(this->messages
, msg
);
755 this->mutex
->unlock(this->mutex
);
757 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
758 TNC_CONNECTION_STATE_CREATE
);
759 tnc
->imcs
->notify_connection_change(tnc
->imcs
, this->connection_id
,
760 TNC_CONNECTION_STATE_HANDSHAKE
);
761 this->send_msg
= TRUE
;
762 tnc
->imcs
->begin_handshake(tnc
->imcs
, this->connection_id
);
763 this->send_msg
= FALSE
;
766 state
= this->state_machine
->get_state(this->state_machine
);
768 if (this->fatal_error
&& state
== PB_STATE_END
)
770 DBG1(DBG_TNC
, "a fatal PB-TNC error occurred, terminating connection");
774 /* Do not allow any asynchronous IMCs or IMVs to add additional messages */
775 this->mutex
->lock(this->mutex
);
777 if (this->request_handshake_retry
)
779 if (state
!= PB_STATE_INIT
)
781 build_retry_batch(this);
784 /* Reset the flag for the next handshake retry request */
785 this->request_handshake_retry
= FALSE
;
788 if (this->is_server
&& state
== PB_STATE_SERVER_WORKING
&&
789 this->recs
->have_recommendation(this->recs
, NULL
, NULL
))
791 check_and_build_recommendation(this);
794 if (this->batch_type
== PB_BATCH_NONE
)
798 if (state
== PB_STATE_SERVER_WORKING
)
800 if (this->state_machine
->get_empty_cdata(this->state_machine
))
802 check_and_build_recommendation(this);
806 DBG2(DBG_TNC
, "no recommendation available yet, "
807 "sending empty PB-TNC SDATA batch");
808 this->batch_type
= PB_BATCH_SDATA
;
816 case PB_STATE_CLIENT_WORKING
:
817 DBG2(DBG_TNC
, "no client data to send, "
818 "sending empty PB-TNC CDATA batch");
819 this->batch_type
= PB_BATCH_CDATA
;
821 case PB_STATE_DECIDED
:
823 * In the DECIDED state and if no CRETRY is under way,
824 * a PB-TNC client replies with an empty CLOSE batch.
826 this->batch_type
= PB_BATCH_CLOSE
;
834 if (this->batch_type
!= PB_BATCH_NONE
)
836 pb_tnc_batch_t
*batch
;
840 enumerator_t
*enumerator
;
842 if (this->state_machine
->send_batch(this->state_machine
, this->batch_type
))
844 batch
= pb_tnc_batch_create(this->is_server
, this->batch_type
,
845 min(this->max_batch_len
, *buflen
));
847 enumerator
= this->messages
->create_enumerator(this->messages
);
848 while (enumerator
->enumerate(enumerator
, &msg
))
850 if (batch
->add_msg(batch
, msg
))
852 this->messages
->remove_at(this->messages
, enumerator
);
859 enumerator
->destroy(enumerator
);
862 data
= batch
->get_encoding(batch
);
863 DBG1(DBG_TNC
, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
864 pb_tnc_batch_type_names
, this->batch_type
, data
.len
,
865 this->connection_id
);
866 DBG3(DBG_TNC
, "%B", &data
);
870 memcpy(buf
, data
.ptr
, *buflen
);
871 batch
->destroy(batch
);
873 msg_count
= this->messages
->get_count(this->messages
);
876 DBG2(DBG_TNC
, "queued %d PB-TNC message%s for next %N batch",
877 msg_count
, (msg_count
== 1) ?
"" : "s",
878 pb_tnc_batch_type_names
, this->batch_type
);
882 this->batch_type
= PB_BATCH_NONE
;
885 status
= ALREADY_DONE
;
889 change_batch_type(this, PB_BATCH_NONE
);
890 status
= INVALID_STATE
;
895 DBG1(DBG_TNC
, "no PB-TNC batch to send");
896 status
= INVALID_STATE
;
898 this->mutex
->unlock(this->mutex
);
903 METHOD(tls_t
, is_server
, bool,
904 private_tnccs_20_t
*this)
906 return this->is_server
;
909 METHOD(tls_t
, get_server_id
, identification_t
*,
910 private_tnccs_20_t
*this)
915 METHOD(tls_t
, set_peer_id
, void,
916 private_tnccs_20_t
*this, identification_t
*id
)
918 DESTROY_IF(this->peer
);
919 this->peer
= id
->clone(id
);
922 METHOD(tls_t
, get_peer_id
, identification_t
*,
923 private_tnccs_20_t
*this)
928 METHOD(tls_t
, get_purpose
, tls_purpose_t
,
929 private_tnccs_20_t
*this)
931 return TLS_PURPOSE_EAP_TNC
;
934 METHOD(tls_t
, is_complete
, bool,
935 private_tnccs_20_t
*this)
937 TNC_IMV_Action_Recommendation rec
;
938 TNC_IMV_Evaluation_Result eval
;
940 if (this->recs
&& this->recs
->have_recommendation(this->recs
, &rec
, &eval
))
942 return this->callback ?
this->callback(rec
, eval
) : TRUE
;
950 METHOD(tls_t
, get_eap_msk
, chunk_t
,
951 private_tnccs_20_t
*this)
956 METHOD(tls_t
, destroy
, void,
957 private_tnccs_20_t
*this)
959 tnc
->tnccs
->remove_connection(tnc
->tnccs
, this->connection_id
,
961 this->server
->destroy(this->server
);
962 this->peer
->destroy(this->peer
);
963 this->state_machine
->destroy(this->state_machine
);
964 this->mutex
->destroy(this->mutex
);
965 this->messages
->destroy_offset(this->messages
,
966 offsetof(pb_tnc_msg_t
, destroy
));
970 METHOD(tnccs_t
, get_transport
, tnc_ift_type_t
,
971 private_tnccs_20_t
*this)
973 return this->transport
;
976 METHOD(tnccs_t
, set_transport
, void,
977 private_tnccs_20_t
*this, tnc_ift_type_t transport
)
979 this->transport
= transport
;
982 METHOD(tnccs_t
, get_auth_type
, u_int32_t
,
983 private_tnccs_20_t
*this)
985 return this->auth_type
;
988 METHOD(tnccs_t
, set_auth_type
, void,
989 private_tnccs_20_t
*this, u_int32_t auth_type
)
991 this->auth_type
= auth_type
;
997 tnccs_t
* tnccs_20_create(bool is_server
,
998 identification_t
*server
, identification_t
*peer
,
999 tnc_ift_type_t transport
, tnccs_cb_t cb
)
1001 private_tnccs_20_t
*this;
1006 .process
= _process
,
1008 .is_server
= _is_server
,
1009 .get_server_id
= _get_server_id
,
1010 .set_peer_id
= _set_peer_id
,
1011 .get_peer_id
= _get_peer_id
,
1012 .get_purpose
= _get_purpose
,
1013 .is_complete
= _is_complete
,
1014 .get_eap_msk
= _get_eap_msk
,
1015 .destroy
= _destroy
,
1017 .get_transport
= _get_transport
,
1018 .set_transport
= _set_transport
,
1019 .get_auth_type
= _get_auth_type
,
1020 .set_auth_type
= _set_auth_type
,
1022 .is_server
= is_server
,
1023 .server
= server
->clone(server
),
1024 .peer
= peer
->clone(peer
),
1025 .transport
= transport
,
1027 .state_machine
= pb_tnc_state_machine_create(is_server
),
1028 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
1029 .messages
= linked_list_create(),
1030 .max_batch_len
= lib
->settings
->get_int(lib
->settings
,
1031 "libtnccs.plugins.tnccs-20.max_batch_size", 65522),
1032 .max_msg_len
= lib
->settings
->get_int(lib
->settings
,
1033 "libtnccs.plugins.tnccs-20.max_message_size", 65490),
1036 return &this->public;