define pb_tnc_state_machine_t object
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 10 Dec 2010 13:56:40 +0000 (14:56 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 10 Dec 2010 13:56:40 +0000 (14:56 +0100)
src/libcharon/plugins/tnccs_20/Makefile.am
src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c
src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h
src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c [new file with mode: 0644]
src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h [new file with mode: 0644]
src/libcharon/plugins/tnccs_20/tnccs_20.c

index f5dd6ba..4b335a0 100644 (file)
@@ -21,6 +21,7 @@ libstrongswan_tnccs_20_la_SOURCES = \
        messages/pb_access_recommendation_message.h messages/pb_access_recommendation_message.c \
        messages/pb_error_message.h messages/pb_error_message.c \
        messages/pb_language_preference_message.h messages/pb_language_preference_message.c \
        messages/pb_access_recommendation_message.h messages/pb_access_recommendation_message.c \
        messages/pb_error_message.h messages/pb_error_message.c \
        messages/pb_language_preference_message.h messages/pb_language_preference_message.c \
-       messages/pb_reason_string_message.h messages/pb_reason_string_message.c
+       messages/pb_reason_string_message.h messages/pb_reason_string_message.c \
+       state_machine/pb_tnc_state_machine.h state_machine/pb_tnc_state_machine.c
 
 libstrongswan_tnccs_20_la_LDFLAGS = -module -avoid-version
 
 libstrongswan_tnccs_20_la_LDFLAGS = -module -avoid-version
index edada34..8e4c54e 100644 (file)
@@ -17,6 +17,7 @@
 #include "tnccs_20_types.h"
 #include "pb_tnc_batch.h"
 #include "messages/pb_error_message.h"
 #include "tnccs_20_types.h"
 #include "pb_tnc_batch.h"
 #include "messages/pb_error_message.h"
+#include "state_machine/pb_tnc_state_machine.h"
 
 #include <debug.h>
 #include <utils/linked_list.h>
 
 #include <debug.h>
 #include <utils/linked_list.h>
 #include <tls_reader.h>
 #include <tnc/tnccs/tnccs.h>
 
 #include <tls_reader.h>
 #include <tnc/tnccs/tnccs.h>
 
-ENUM(pb_tnc_state_names, PB_STATE_INIT, PB_STATE_END,
-       "Init",
-       "Server Working",
-       "Client Working",
-       "Decided",
-       "End"
-);
-
 ENUM(pb_tnc_batch_type_names, PB_BATCH_CDATA, PB_BATCH_CLOSE,
        "CDATA",
        "SDATA",
 ENUM(pb_tnc_batch_type_names, PB_BATCH_CDATA, PB_BATCH_CLOSE,
        "CDATA",
        "SDATA",
@@ -206,95 +199,8 @@ METHOD(pb_tnc_batch_t, build, void,
        writer->destroy(writer);
 }
 
        writer->destroy(writer);
 }
 
-/*
- * Implements the PB-TNC state machine in receive direction
- */
-static bool state_transition_upon_receive(pb_tnc_state_t *state,
-                                                                                 pb_tnc_batch_type_t batch_type,
-                                                                                 bool is_server)
-{
-       switch (*state)
-       {
-               case PB_STATE_INIT:
-                       if (is_server && batch_type == PB_BATCH_CDATA)
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (!is_server && batch_type == PB_BATCH_SDATA)
-                       {
-                               *state = PB_STATE_CLIENT_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_SERVER_WORKING:
-                       if (!is_server && batch_type == PB_BATCH_SDATA)
-                       {
-                               *state = PB_STATE_CLIENT_WORKING;
-                               break;
-                       }
-                       if (!is_server && batch_type == PB_BATCH_RESULT)
-                       {
-                               *state = PB_STATE_DECIDED;
-                               break;
-                       }
-                       if ((is_server && batch_type == PB_BATCH_CRETRY) ||
-                          (!is_server && batch_type == PB_BATCH_SRETRY))
-                       {
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_CLIENT_WORKING:
-                       if (is_server && batch_type == PB_BATCH_CDATA)
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (is_server && batch_type == PB_BATCH_CRETRY)
-                       {
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_DECIDED:
-                       if ((is_server && batch_type == PB_BATCH_CRETRY) ||
-                          (!is_server && batch_type == PB_BATCH_SRETRY))
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_END:
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               break;
-                       }
-                       return FALSE;
-       }
-       return TRUE;
-}
-
 static status_t process_batch_header(private_pb_tnc_batch_t *this,
 static status_t process_batch_header(private_pb_tnc_batch_t *this,
-                                                                        pb_tnc_state_t *state)
+                                                                        pb_tnc_state_machine_t *state_machine)
 {
        tls_reader_t *reader;
        pb_tnc_message_t *msg;
 {
        tls_reader_t *reader;
        pb_tnc_message_t *msg;
@@ -358,7 +264,7 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this,
                goto fatal;
        }
 
                goto fatal;
        }
 
-       if (!state_transition_upon_receive(state, this->type, this->is_server))
+       if (!state_machine->receive_batch(state_machine, this->type))
        {
                DBG1(DBG_TNC, "unexpected PB-TNC Batch Type: %N",
                                           pb_tnc_batch_type_names, this->type);
        {
                DBG1(DBG_TNC, "unexpected PB-TNC Batch Type: %N",
                                           pb_tnc_batch_type_names, this->type);
@@ -514,11 +420,11 @@ fatal:
 }
 
 METHOD(pb_tnc_batch_t, process, status_t,
 }
 
 METHOD(pb_tnc_batch_t, process, status_t,
-       private_pb_tnc_batch_t *this, pb_tnc_state_t *state)
+       private_pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine)
 {
        status_t status;
 
 {
        status_t status;
 
-       status = process_batch_header(this, state);
+       status = process_batch_header(this, state_machine);
        if (status == FAILED)
        {
                return FAILED;
        if (status == FAILED)
        {
                return FAILED;
index 7bc4639..a437799 100644 (file)
 #ifndef PB_TNC_BATCH_H_
 #define PB_TNC_BATCH_H_
 
 #ifndef PB_TNC_BATCH_H_
 #define PB_TNC_BATCH_H_
 
+typedef enum pb_tnc_batch_type_t pb_tnc_batch_type_t;
+typedef struct pb_tnc_batch_t pb_tnc_batch_t;
+
 #include "messages/pb_tnc_message.h"
 #include "messages/pb_tnc_message.h"
+#include "state_machine/pb_tnc_state_machine.h"
 
 #include <library.h>
 
 
 #include <library.h>
 
-typedef enum pb_tnc_state_t pb_tnc_state_t;
-
-/**
- * PB-TNC States (State machine) as defined in section 3.2 of RFC 5793
- */
-enum pb_tnc_state_t {
-       PB_STATE_INIT,
-       PB_STATE_SERVER_WORKING,
-       PB_STATE_CLIENT_WORKING,
-       PB_STATE_DECIDED,
-       PB_STATE_END,
-};
-
-/**
- * enum name for pb_tnc_state_t.
- */
-extern enum_name_t *pb_tnc_state_names;
-
-typedef enum pb_tnc_batch_type_t pb_tnc_batch_type_t;
-
 /**
   * PB-TNC Batch Types as defined in section 4.1 of RFC 5793
  */
 /**
   * PB-TNC Batch Types as defined in section 4.1 of RFC 5793
  */
@@ -58,8 +42,6 @@ enum pb_tnc_batch_type_t {
        PB_BATCH_ROOF =         6
 };
 
        PB_BATCH_ROOF =         6
 };
 
-typedef struct pb_tnc_batch_t pb_tnc_batch_t;
-
 /**
  * enum name for pb_tnc_batch_type_t.
  */
 /**
  * enum name for pb_tnc_batch_type_t.
  */
@@ -99,10 +81,11 @@ struct pb_tnc_batch_t {
        /**
         * Process the PB-TNC Batch
         *
        /**
         * Process the PB-TNC Batch
         *
-        * @param                               in: current state, out: new state
+        * @param                               PB-TNC state machine
         * @return                              return processing status
         */
         * @return                              return processing status
         */
-       status_t (*process)(pb_tnc_batch_t *this, pb_tnc_state_t *state);
+       status_t (*process)(pb_tnc_batch_t *this,
+                                               pb_tnc_state_machine_t *state_machine);
 
        /**
         * Enumerates over all PB-TNC Messages
 
        /**
         * Enumerates over all PB-TNC Messages
diff --git a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c
new file mode 100644 (file)
index 0000000..4cca60f
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "pb_tnc_state_machine.h"
+#include "messages/pb_error_message.h"
+
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <tls_writer.h>
+#include <tls_reader.h>
+#include <tnc/tnccs/tnccs.h>
+
+ENUM(pb_tnc_state_names, PB_STATE_INIT, PB_STATE_END,
+       "Init",
+       "Server Working",
+       "Client Working",
+       "Decided",
+       "End"
+);
+
+/**
+ *   PB-TNC State Machine (see section 3.2 of RFC 5793)
+ *
+ *              Receive CRETRY        SRETRY
+ *                   or SRETRY   +----------------+
+ *                        +--+   |                |
+ *                        v  |   v                |
+ *                       +---------+  CRETRY  +---------+
+ *             CDATA     | Server  |<---------| Decided | CLOSE
+ *          +----------->| Working |--------->|         |-------+
+ *          |            +---------+  RESULT  +---------+       |
+ *          |                ^ |  |                             v
+ *          |                | |  +---------------------->=======
+ *        ========           | |              CLOSE       " End "
+ *        " Init "      CDATA| |SDATA                     =======
+ *        ========           | |                          ^    ^
+ *          |  |             | v                          |    |
+ *          |  | SDATA   +---------+          CLOSE       |    |
+ *          |  +-------->| Client  |----------------------+    |
+ *          |            | Working |                           |
+ *          |            +---------+                           |
+ *          |                |  ^                              |
+ *          |                +--+                              |
+ *          |            Receive CRETRY                        |
+ *          |   CLOSE                                          |
+ *          +--------------------------------------------------+
+ */
+
+typedef struct private_pb_tnc_state_machine_t private_pb_tnc_state_machine_t;
+
+/**
+ * Private data of a pb_tnc_state_machine_t object.
+ *
+ */
+struct private_pb_tnc_state_machine_t {
+       /**
+        * Public pb_pa_message_t interface.
+        */
+       pb_tnc_state_machine_t public;
+
+       /**
+        * PB-TNC Server if TRUE, PB-TNC Client if FALSE
+        */
+       bool is_server;
+
+       /**
+        * Current PB-TNC state
+        */
+       pb_tnc_state_t state;
+};
+
+METHOD(pb_tnc_state_machine_t, get_state, pb_tnc_state_t,
+       private_pb_tnc_state_machine_t *this)
+{
+       return this->state;
+}
+
+METHOD(pb_tnc_state_machine_t, receive_batch, bool,
+       private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
+{
+       pb_tnc_state_t old_state = this->state;
+
+       switch (this->state)
+       {
+               case PB_STATE_INIT:
+                       if (this->is_server && type == PB_BATCH_CDATA)
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (!this->is_server && type == PB_BATCH_SDATA)
+                       {
+                               this->state = PB_STATE_CLIENT_WORKING;
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_SERVER_WORKING:
+                       if (!this->is_server && type == PB_BATCH_SDATA)
+                       {
+                               this->state = PB_STATE_CLIENT_WORKING;
+                               break;
+                       }
+                       if (!this->is_server && type == PB_BATCH_RESULT)
+                       {
+                               this->state = PB_STATE_DECIDED;
+                               break;
+                       }
+                       if ((this->is_server && type == PB_BATCH_CRETRY) ||
+                          (!this->is_server && type == PB_BATCH_SRETRY))
+                       {
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_CLIENT_WORKING:
+                       if (this->is_server && type == PB_BATCH_CDATA)
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (this->is_server && type == PB_BATCH_CRETRY)
+                       {
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_DECIDED:
+                       if ((this->is_server && type == PB_BATCH_CRETRY) ||
+                          (!this->is_server && type == PB_BATCH_SRETRY))
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_END:
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               break;
+                       }
+                       return FALSE;
+       }
+
+       if (this->state != old_state)
+       {
+               DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
+                        pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
+       }
+       return TRUE;
+}
+
+METHOD(pb_tnc_state_machine_t, send_batch, bool,
+       private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
+{
+       pb_tnc_state_t old_state = this->state;
+
+       switch (this->state)
+       {
+               case PB_STATE_INIT:
+                       if (!this->is_server && type == PB_BATCH_CDATA)
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (this->is_server && type == PB_BATCH_SDATA)
+                       {
+                               this->state = PB_STATE_CLIENT_WORKING;
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_SERVER_WORKING:
+                       if (this->is_server && type == PB_BATCH_SDATA)
+                       {
+                               this->state = PB_STATE_CLIENT_WORKING;
+                               break;
+                       }
+                       if (this->is_server && type == PB_BATCH_RESULT)
+                       {
+                               this->state = PB_STATE_DECIDED;
+                               break;
+                       }
+                       if (this->is_server && type == PB_BATCH_SRETRY)
+                       {
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_CLIENT_WORKING:
+                       if (!this->is_server && type == PB_BATCH_CDATA)
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_DECIDED:
+                       if ((this->is_server && type == PB_BATCH_SRETRY) ||
+                          (!this->is_server && type == PB_BATCH_CRETRY))
+                       {
+                               this->state = PB_STATE_SERVER_WORKING;
+                               break;
+                       }
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               this->state = PB_STATE_END;
+                               break;
+                       }
+                       return FALSE;
+               case PB_STATE_END:
+                       if (type == PB_BATCH_CLOSE)
+                       {
+                               break;
+                       }
+                       return FALSE;
+       }
+
+       if (this->state != old_state)
+       {
+               DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
+                        pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
+       }
+       return TRUE;
+}
+
+METHOD(pb_tnc_state_machine_t, destroy, void,
+       private_pb_tnc_state_machine_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server)
+{
+       private_pb_tnc_state_machine_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_state = _get_state,
+                       .receive_batch = _receive_batch,
+                       .send_batch = _send_batch,
+                       .destroy = _destroy,
+               },
+               .is_server = is_server,
+               .state = PB_STATE_INIT,
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h
new file mode 100644 (file)
index 0000000..8076b6d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pb_tnc_state_machine pb_tnc_state_machine
+ * @{ @ingroup tnccs_20
+ */
+
+#ifndef PB_TNC_STATE_MACHINE_H_
+#define PB_TNC_STATE_MACHINE_H_
+
+typedef struct pb_tnc_state_machine_t pb_tnc_state_machine_t;
+typedef enum pb_tnc_state_t pb_tnc_state_t;
+
+#include "batch/pb_tnc_batch.h"
+
+#include <library.h>
+
+/**
+ * PB-TNC States (state machine) as defined in section 3.2 of RFC 5793
+ */
+enum pb_tnc_state_t {
+       PB_STATE_INIT,
+       PB_STATE_SERVER_WORKING,
+       PB_STATE_CLIENT_WORKING,
+       PB_STATE_DECIDED,
+       PB_STATE_END,
+};
+
+/**
+ * enum name for pb_tnc_state_t.
+ */
+extern enum_name_t *pb_tnc_state_names;
+
+/**
+ * Interface for the PB-TNC state machine.
+ */
+struct pb_tnc_state_machine_t {
+
+       /**
+        * Get the current PB-TNC STATE
+        *
+        * @return                              current state
+        */
+       pb_tnc_state_t (*get_state)(pb_tnc_state_machine_t *this);
+
+       /**
+        * Compute state transition due to received PB-TNC Batch
+        *
+        * @param type                  type of received batch
+        * @result                              TRUE if a valid transition was found, FALSE otherwise
+        */
+       bool (*receive_batch)(pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type);
+
+       /**
+        * Compute state transition due to sent PB-TNC Batch
+        *
+        * @param type                  type of sent batch
+        * @result                              TRUE if a valid transition was found, FALSE otherwise
+        */
+       bool (*send_batch)(pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type);
+
+       /**
+        * Destroys a pb_tnc_state_machine_t object.
+        */
+       void (*destroy)(pb_tnc_state_machine_t *this);
+};
+
+/**
+ * Create and initialize a PB-TNC state machine
+ *
+ * @param is_server            TRUE if PB-TNC server, FALSE if PB-TNC client
+ */
+pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server);
+
+#endif /** PB_TNC_STATE_MACHINE_H_ @}*/
index 8bf88a2..fcabc55 100644 (file)
@@ -24,6 +24,7 @@
 #include "messages/pb_access_recommendation_message.h"
 #include "messages/pb_reason_string_message.h"
 #include "messages/pb_language_preference_message.h"
 #include "messages/pb_access_recommendation_message.h"
 #include "messages/pb_reason_string_message.h"
 #include "messages/pb_language_preference_message.h"
+#include "state_machine/pb_tnc_state_machine.h"
 
 #include <debug.h>
 #include <daemon.h>
 
 #include <debug.h>
 #include <daemon.h>
@@ -52,7 +53,7 @@ struct private_tnccs_20_t {
        /**
         * PB-TNC State Machine
         */
        /**
         * PB-TNC State Machine
         */
-       pb_tnc_state_t state;
+       pb_tnc_state_machine_t *state_machine;
 
        /**
         * Connection ID assigned to this TNCCS connection
 
        /**
         * Connection ID assigned to this TNCCS connection
@@ -272,7 +273,6 @@ METHOD(tls_t, process, status_t,
        chunk_t data;
        pb_tnc_batch_t *batch;
        pb_tnc_message_t *msg;
        chunk_t data;
        pb_tnc_batch_t *batch;
        pb_tnc_message_t *msg;
-       pb_tnc_state_t old_state = this->state;
        enumerator_t *enumerator;
        status_t status;
 
        enumerator_t *enumerator;
        status_t status;
 
@@ -294,13 +294,7 @@ METHOD(tls_t, process, status_t,
                                   data.len, this->connection_id);
        DBG3(DBG_TNC, "%B", &data);  
        batch = pb_tnc_batch_create_from_data(this->is_server, data);
                                   data.len, this->connection_id);
        DBG3(DBG_TNC, "%B", &data);  
        batch = pb_tnc_batch_create_from_data(this->is_server, data);
-       status = batch->process(batch, &this->state);
-
-       if (this->state != old_state)
-       {
-               DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
-                        pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
-       }
+       status = batch->process(batch, this->state_machine);
 
        switch (status)
        {
 
        switch (status)
        {
@@ -343,92 +337,6 @@ METHOD(tls_t, process, status_t,
        return NEED_MORE;
 }
 
        return NEED_MORE;
 }
 
-/*
- * Implements the PB-TNC state machine in send direction
- */
-static bool state_transition_upon_send(pb_tnc_state_t *state,
-                                                                          pb_tnc_batch_type_t batch_type)
-{
-       switch (*state)
-       {
-               case PB_STATE_INIT:
-                       if (batch_type == PB_BATCH_CDATA)
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_SDATA)
-                       {
-                               *state = PB_STATE_CLIENT_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_SERVER_WORKING:
-                       if (batch_type == PB_BATCH_SDATA)
-                       {
-                               *state = PB_STATE_CLIENT_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_RESULT)
-                       {
-                               *state = PB_STATE_DECIDED;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CRETRY ||
-                               batch_type == PB_BATCH_SRETRY)
-                       {
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_CLIENT_WORKING:
-                       if (batch_type == PB_BATCH_CDATA)
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CRETRY)
-                       {
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_DECIDED:
-                       if (batch_type == PB_BATCH_CRETRY ||
-                               batch_type == PB_BATCH_SRETRY)
-                       {
-                               *state = PB_STATE_SERVER_WORKING;
-                               break;
-                       }
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               *state = PB_STATE_END;
-                               break;
-                       }
-                       return FALSE;
-               case PB_STATE_END:
-                       if (batch_type == PB_BATCH_CLOSE)
-                       {
-                               break;
-                       }
-                       return FALSE;
-       }
-       return TRUE;
-}
-
 METHOD(tls_t, build, status_t,
        private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
 {
 METHOD(tls_t, build, status_t,
        private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
 {
@@ -464,15 +372,13 @@ METHOD(tls_t, build, status_t,
        if (this->batch)
        {
                pb_tnc_batch_type_t batch_type;
        if (this->batch)
        {
                pb_tnc_batch_type_t batch_type;
-               pb_tnc_state_t old_state;
                status_t status;
                chunk_t data;
 
                status_t status;
                chunk_t data;
 
-               batch_type = this->batch->get_type(this->batch);
-               old_state = this->state;
                this->mutex->lock(this->mutex);
                this->mutex->lock(this->mutex);
+               batch_type = this->batch->get_type(this->batch);
 
 
-               if (state_transition_upon_send(&this->state, batch_type))
+               if (this->state_machine->send_batch(this->state_machine, batch_type))
                {
                        this->batch->build(this->batch);
                        data = this->batch->get_encoding(this->batch);
                {
                        this->batch->build(this->batch);
                        data = this->batch->get_encoding(this->batch);
@@ -497,11 +403,6 @@ METHOD(tls_t, build, status_t,
                this->batch = NULL;
                this->mutex->unlock(this->mutex);
 
                this->batch = NULL;
                this->mutex->unlock(this->mutex);
 
-               if (this->state != old_state)
-               {
-                       DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
-                                pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
-               }
                return status;
        }
        else
                return status;
        }
        else
@@ -552,6 +453,7 @@ METHOD(tls_t, destroy, void,
        private_tnccs_20_t *this)
 {
        charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
        private_tnccs_20_t *this)
 {
        charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
+       this->state_machine->destroy(this->state_machine);
        this->mutex->destroy(this->mutex);
        DESTROY_IF(this->batch);
        free(this);
        this->mutex->destroy(this->mutex);
        DESTROY_IF(this->batch);
        free(this);
@@ -575,7 +477,7 @@ tls_t *tnccs_20_create(bool is_server)
                        .destroy = _destroy,
                },
                .is_server = is_server,
                        .destroy = _destroy,
                },
                .is_server = is_server,
-               .state = PB_STATE_INIT,
+               .state_machine = pb_tnc_state_machine_create(is_server),
                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        );
 
                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        );