2 * Copyright (C) 2010 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "pb_tnc_state_machine.h"
18 #include <utils/debug.h>
20 ENUM(pb_tnc_state_names
, PB_STATE_INIT
, PB_STATE_END
,
29 * PB-TNC State Machine (see section 3.2 of RFC 5793)
31 * Receive CRETRY SRETRY
32 * or SRETRY +----------------+
35 * +---------+ CRETRY +---------+
36 * CDATA | Server |<---------| Decided | CLOSE
37 * +----------->| Working |--------->| |-------+
38 * | +---------+ RESULT +---------+ |
40 * | | | +---------------------->=======
41 * ======== | | CLOSE " End "
42 * " Init " CDATA| |SDATA =======
45 * | | SDATA +---------+ CLOSE | |
46 * | +-------->| Client |----------------------+ |
53 * +--------------------------------------------------+
56 typedef struct private_pb_tnc_state_machine_t private_pb_tnc_state_machine_t
;
59 * Private data of a pb_tnc_state_machine_t object.
62 struct private_pb_tnc_state_machine_t
{
64 * Public pb_pa_message_t interface.
66 pb_tnc_state_machine_t
public;
69 * PB-TNC Server if TRUE, PB-TNC Client if FALSE
74 * Informs whether last received PB-TNC CDATA Batch was empty
79 * Current PB-TNC state
84 METHOD(pb_tnc_state_machine_t
, get_state
, pb_tnc_state_t
,
85 private_pb_tnc_state_machine_t
*this)
90 METHOD(pb_tnc_state_machine_t
, receive_batch
, bool,
91 private_pb_tnc_state_machine_t
*this, pb_tnc_batch_type_t type
)
93 pb_tnc_state_t old_state
= this->state
;
98 if (this->is_server
&& type
== PB_BATCH_CDATA
)
100 this->state
= PB_STATE_SERVER_WORKING
;
103 if (!this->is_server
&& type
== PB_BATCH_SDATA
)
105 this->state
= PB_STATE_CLIENT_WORKING
;
108 if (type
== PB_BATCH_CLOSE
)
110 this->state
= PB_STATE_END
;
114 case PB_STATE_SERVER_WORKING
:
115 if (!this->is_server
&& (type
== PB_BATCH_SDATA
||
116 type
== PB_BATCH_SRETRY
))
118 this->state
= PB_STATE_CLIENT_WORKING
;
121 if (!this->is_server
&& type
== PB_BATCH_RESULT
)
123 this->state
= PB_STATE_DECIDED
;
126 if (this->is_server
&& type
== PB_BATCH_CRETRY
)
130 if (type
== PB_BATCH_CLOSE
)
132 this->state
= PB_STATE_END
;
136 case PB_STATE_CLIENT_WORKING
:
137 if (this->is_server
&&
138 (type
== PB_BATCH_CDATA
|| type
== PB_BATCH_CRETRY
))
140 this->state
= PB_STATE_SERVER_WORKING
;
143 if (type
== PB_BATCH_CLOSE
)
145 this->state
= PB_STATE_END
;
149 case PB_STATE_DECIDED
:
150 if ((this->is_server
&& type
== PB_BATCH_CRETRY
) ||
151 (!this->is_server
&& type
== PB_BATCH_SRETRY
))
153 this->state
= PB_STATE_SERVER_WORKING
;
156 if (type
== PB_BATCH_CLOSE
)
158 this->state
= PB_STATE_END
;
163 if (type
== PB_BATCH_CLOSE
)
170 if (this->state
!= old_state
)
172 DBG2(DBG_TNC
, "PB-TNC state transition from '%N' to '%N'",
173 pb_tnc_state_names
, old_state
, pb_tnc_state_names
, this->state
);
178 METHOD(pb_tnc_state_machine_t
, send_batch
, bool,
179 private_pb_tnc_state_machine_t
*this, pb_tnc_batch_type_t type
)
181 pb_tnc_state_t old_state
= this->state
;
186 if (!this->is_server
&& type
== PB_BATCH_CDATA
)
188 this->state
= PB_STATE_SERVER_WORKING
;
191 if (this->is_server
&& type
== PB_BATCH_SDATA
)
193 this->state
= PB_STATE_CLIENT_WORKING
;
196 if (type
== PB_BATCH_CLOSE
)
198 this->state
= PB_STATE_END
;
202 case PB_STATE_SERVER_WORKING
:
203 if (this->is_server
&& (type
== PB_BATCH_SDATA
||
204 type
== PB_BATCH_SRETRY
))
206 this->state
= PB_STATE_CLIENT_WORKING
;
209 if (this->is_server
&& type
== PB_BATCH_RESULT
)
211 this->state
= PB_STATE_DECIDED
;
214 if (!this->is_server
&& type
== PB_BATCH_CRETRY
)
218 if (type
== PB_BATCH_CLOSE
)
220 this->state
= PB_STATE_END
;
224 case PB_STATE_CLIENT_WORKING
:
225 if (!this->is_server
&& (type
== PB_BATCH_CDATA
||
226 type
== PB_BATCH_CRETRY
))
228 this->state
= PB_STATE_SERVER_WORKING
;
231 if (this->is_server
&& type
== PB_BATCH_SRETRY
)
235 if (type
== PB_BATCH_CLOSE
)
237 this->state
= PB_STATE_END
;
241 case PB_STATE_DECIDED
:
242 if ((this->is_server
&& type
== PB_BATCH_SRETRY
) ||
243 (!this->is_server
&& type
== PB_BATCH_CRETRY
))
245 this->state
= PB_STATE_SERVER_WORKING
;
248 if (type
== PB_BATCH_CLOSE
)
250 this->state
= PB_STATE_END
;
255 if (type
== PB_BATCH_CLOSE
)
262 if (this->state
!= old_state
)
264 DBG2(DBG_TNC
, "PB-TNC state transition from '%N' to '%N'",
265 pb_tnc_state_names
, old_state
, pb_tnc_state_names
, this->state
);
270 METHOD(pb_tnc_state_machine_t
, get_empty_cdata
, bool,
271 private_pb_tnc_state_machine_t
*this)
273 return this->empty_cdata
;
276 METHOD(pb_tnc_state_machine_t
, set_empty_cdata
, void,
277 private_pb_tnc_state_machine_t
*this, bool empty
)
281 DBG2(DBG_TNC
, "received empty PB-TNC CDATA batch");
283 this->empty_cdata
= empty
;
286 METHOD(pb_tnc_state_machine_t
, destroy
, void,
287 private_pb_tnc_state_machine_t
*this)
295 pb_tnc_state_machine_t
* pb_tnc_state_machine_create(bool is_server
)
297 private_pb_tnc_state_machine_t
*this;
301 .get_state
= _get_state
,
302 .receive_batch
= _receive_batch
,
303 .send_batch
= _send_batch
,
304 .get_empty_cdata
= _get_empty_cdata
,
305 .set_empty_cdata
= _set_empty_cdata
,
308 .is_server
= is_server
,
309 .state
= PB_STATE_INIT
,
312 return &this->public;