define pb_tnc_state_machine_t object

This commit is contained in:
Andreas Steffen 2010-12-10 14:56:40 +01:00
parent 755f2419a5
commit 5988fc0dfd
6 changed files with 401 additions and 229 deletions

View 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_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

View File

@ -17,6 +17,7 @@
#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>
@ -24,14 +25,6 @@
#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",
@ -206,95 +199,8 @@ METHOD(pb_tnc_batch_t, build, void,
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,
pb_tnc_state_t *state)
pb_tnc_state_machine_t *state_machine)
{
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;
}
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);
@ -514,11 +420,11 @@ fatal:
}
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 = process_batch_header(this, state);
status = process_batch_header(this, state_machine);
if (status == FAILED)
{
return FAILED;

View File

@ -21,30 +21,14 @@
#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 "state_machine/pb_tnc_state_machine.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
*/
@ -58,8 +42,6 @@ enum pb_tnc_batch_type_t {
PB_BATCH_ROOF = 6
};
typedef struct pb_tnc_batch_t pb_tnc_batch_t;
/**
* enum name for pb_tnc_batch_type_t.
*/
@ -99,10 +81,11 @@ struct pb_tnc_batch_t {
/**
* Process the PB-TNC Batch
*
* @param in: current state, out: new state
* @param PB-TNC state machine
* @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

View File

@ -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;
}

View File

@ -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_ @}*/

View 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 "state_machine/pb_tnc_state_machine.h"
#include <debug.h>
#include <daemon.h>
@ -52,7 +53,7 @@ struct private_tnccs_20_t {
/**
* PB-TNC State Machine
*/
pb_tnc_state_t state;
pb_tnc_state_machine_t *state_machine;
/**
* 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;
pb_tnc_state_t old_state = this->state;
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);
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)
{
@ -343,92 +337,6 @@ METHOD(tls_t, process, status_t,
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)
{
@ -464,15 +372,13 @@ METHOD(tls_t, build, status_t,
if (this->batch)
{
pb_tnc_batch_type_t batch_type;
pb_tnc_state_t old_state;
status_t status;
chunk_t data;
batch_type = this->batch->get_type(this->batch);
old_state = this->state;
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);
@ -497,11 +403,6 @@ METHOD(tls_t, build, status_t,
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
@ -552,6 +453,7 @@ METHOD(tls_t, destroy, void,
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);
@ -575,7 +477,7 @@ tls_t *tnccs_20_create(bool 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),
);