define pb_tnc_state_machine_t object
[strongswan.git] / src / libcharon / plugins / tnccs_20 / state_machine / pb_tnc_state_machine.c
1 /*
2 * Copyright (C) 2010 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "pb_tnc_state_machine.h"
17 #include "messages/pb_error_message.h"
18
19 #include <debug.h>
20 #include <utils/linked_list.h>
21 #include <tls_writer.h>
22 #include <tls_reader.h>
23 #include <tnc/tnccs/tnccs.h>
24
25 ENUM(pb_tnc_state_names, PB_STATE_INIT, PB_STATE_END,
26 "Init",
27 "Server Working",
28 "Client Working",
29 "Decided",
30 "End"
31 );
32
33 /**
34 * PB-TNC State Machine (see section 3.2 of RFC 5793)
35 *
36 * Receive CRETRY SRETRY
37 * or SRETRY +----------------+
38 * +--+ | |
39 * v | v |
40 * +---------+ CRETRY +---------+
41 * CDATA | Server |<---------| Decided | CLOSE
42 * +----------->| Working |--------->| |-------+
43 * | +---------+ RESULT +---------+ |
44 * | ^ | | v
45 * | | | +---------------------->=======
46 * ======== | | CLOSE " End "
47 * " Init " CDATA| |SDATA =======
48 * ======== | | ^ ^
49 * | | | v | |
50 * | | SDATA +---------+ CLOSE | |
51 * | +-------->| Client |----------------------+ |
52 * | | Working | |
53 * | +---------+ |
54 * | | ^ |
55 * | +--+ |
56 * | Receive CRETRY |
57 * | CLOSE |
58 * +--------------------------------------------------+
59 */
60
61 typedef struct private_pb_tnc_state_machine_t private_pb_tnc_state_machine_t;
62
63 /**
64 * Private data of a pb_tnc_state_machine_t object.
65 *
66 */
67 struct private_pb_tnc_state_machine_t {
68 /**
69 * Public pb_pa_message_t interface.
70 */
71 pb_tnc_state_machine_t public;
72
73 /**
74 * PB-TNC Server if TRUE, PB-TNC Client if FALSE
75 */
76 bool is_server;
77
78 /**
79 * Current PB-TNC state
80 */
81 pb_tnc_state_t state;
82 };
83
84 METHOD(pb_tnc_state_machine_t, get_state, pb_tnc_state_t,
85 private_pb_tnc_state_machine_t *this)
86 {
87 return this->state;
88 }
89
90 METHOD(pb_tnc_state_machine_t, receive_batch, bool,
91 private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
92 {
93 pb_tnc_state_t old_state = this->state;
94
95 switch (this->state)
96 {
97 case PB_STATE_INIT:
98 if (this->is_server && type == PB_BATCH_CDATA)
99 {
100 this->state = PB_STATE_SERVER_WORKING;
101 break;
102 }
103 if (!this->is_server && type == PB_BATCH_SDATA)
104 {
105 this->state = PB_STATE_CLIENT_WORKING;
106 break;
107 }
108 if (type == PB_BATCH_CLOSE)
109 {
110 this->state = PB_STATE_END;
111 break;
112 }
113 return FALSE;
114 case PB_STATE_SERVER_WORKING:
115 if (!this->is_server && type == PB_BATCH_SDATA)
116 {
117 this->state = PB_STATE_CLIENT_WORKING;
118 break;
119 }
120 if (!this->is_server && type == PB_BATCH_RESULT)
121 {
122 this->state = PB_STATE_DECIDED;
123 break;
124 }
125 if ((this->is_server && type == PB_BATCH_CRETRY) ||
126 (!this->is_server && type == PB_BATCH_SRETRY))
127 {
128 break;
129 }
130 if (type == PB_BATCH_CLOSE)
131 {
132 this->state = PB_STATE_END;
133 break;
134 }
135 return FALSE;
136 case PB_STATE_CLIENT_WORKING:
137 if (this->is_server && type == PB_BATCH_CDATA)
138 {
139 this->state = PB_STATE_SERVER_WORKING;
140 break;
141 }
142 if (this->is_server && type == PB_BATCH_CRETRY)
143 {
144 break;
145 }
146 if (type == PB_BATCH_CLOSE)
147 {
148 this->state = PB_STATE_END;
149 break;
150 }
151 return FALSE;
152 case PB_STATE_DECIDED:
153 if ((this->is_server && type == PB_BATCH_CRETRY) ||
154 (!this->is_server && type == PB_BATCH_SRETRY))
155 {
156 this->state = PB_STATE_SERVER_WORKING;
157 break;
158 }
159 if (type == PB_BATCH_CLOSE)
160 {
161 this->state = PB_STATE_END;
162 break;
163 }
164 return FALSE;
165 case PB_STATE_END:
166 if (type == PB_BATCH_CLOSE)
167 {
168 break;
169 }
170 return FALSE;
171 }
172
173 if (this->state != old_state)
174 {
175 DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
176 pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
177 }
178 return TRUE;
179 }
180
181 METHOD(pb_tnc_state_machine_t, send_batch, bool,
182 private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
183 {
184 pb_tnc_state_t old_state = this->state;
185
186 switch (this->state)
187 {
188 case PB_STATE_INIT:
189 if (!this->is_server && type == PB_BATCH_CDATA)
190 {
191 this->state = PB_STATE_SERVER_WORKING;
192 break;
193 }
194 if (this->is_server && type == PB_BATCH_SDATA)
195 {
196 this->state = PB_STATE_CLIENT_WORKING;
197 break;
198 }
199 if (type == PB_BATCH_CLOSE)
200 {
201 this->state = PB_STATE_END;
202 break;
203 }
204 return FALSE;
205 case PB_STATE_SERVER_WORKING:
206 if (this->is_server && type == PB_BATCH_SDATA)
207 {
208 this->state = PB_STATE_CLIENT_WORKING;
209 break;
210 }
211 if (this->is_server && type == PB_BATCH_RESULT)
212 {
213 this->state = PB_STATE_DECIDED;
214 break;
215 }
216 if (this->is_server && type == PB_BATCH_SRETRY)
217 {
218 break;
219 }
220 if (type == PB_BATCH_CLOSE)
221 {
222 this->state = PB_STATE_END;
223 break;
224 }
225 return FALSE;
226 case PB_STATE_CLIENT_WORKING:
227 if (!this->is_server && type == PB_BATCH_CDATA)
228 {
229 this->state = PB_STATE_SERVER_WORKING;
230 break;
231 }
232 if (type == PB_BATCH_CLOSE)
233 {
234 this->state = PB_STATE_END;
235 break;
236 }
237 return FALSE;
238 case PB_STATE_DECIDED:
239 if ((this->is_server && type == PB_BATCH_SRETRY) ||
240 (!this->is_server && type == PB_BATCH_CRETRY))
241 {
242 this->state = PB_STATE_SERVER_WORKING;
243 break;
244 }
245 if (type == PB_BATCH_CLOSE)
246 {
247 this->state = PB_STATE_END;
248 break;
249 }
250 return FALSE;
251 case PB_STATE_END:
252 if (type == PB_BATCH_CLOSE)
253 {
254 break;
255 }
256 return FALSE;
257 }
258
259 if (this->state != old_state)
260 {
261 DBG2(DBG_TNC, "PB-TNC state transition from '%N' to '%N'",
262 pb_tnc_state_names, old_state, pb_tnc_state_names, this->state);
263 }
264 return TRUE;
265 }
266
267 METHOD(pb_tnc_state_machine_t, destroy, void,
268 private_pb_tnc_state_machine_t *this)
269 {
270 free(this);
271 }
272
273 /**
274 * See header
275 */
276 pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server)
277 {
278 private_pb_tnc_state_machine_t *this;
279
280 INIT(this,
281 .public = {
282 .get_state = _get_state,
283 .receive_batch = _receive_batch,
284 .send_batch = _send_batch,
285 .destroy = _destroy,
286 },
287 .is_server = is_server,
288 .state = PB_STATE_INIT,
289 );
290
291 return &this->public;
292 }