]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libtnccs/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c
Corrected use of PB-TNC CRETRY and SRETRY batches
[thirdparty/strongswan.git] / src / libtnccs / 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
18 #include <utils/debug.h>
19
20 ENUM(pb_tnc_state_names, PB_STATE_INIT, PB_STATE_END,
21 "Init",
22 "Server Working",
23 "Client Working",
24 "Decided",
25 "End"
26 );
27
28 /**
29 * PB-TNC State Machine (see section 3.2 of RFC 5793)
30 *
31 * Receive CRETRY SRETRY
32 * or SRETRY +----------------+
33 * +--+ | |
34 * v | v |
35 * +---------+ CRETRY +---------+
36 * CDATA | Server |<---------| Decided | CLOSE
37 * +----------->| Working |--------->| |-------+
38 * | +---------+ RESULT +---------+ |
39 * | ^ | | v
40 * | | | +---------------------->=======
41 * ======== | | CLOSE " End "
42 * " Init " CDATA| |SDATA =======
43 * ======== | | ^ ^
44 * | | | v | |
45 * | | SDATA +---------+ CLOSE | |
46 * | +-------->| Client |----------------------+ |
47 * | | Working | |
48 * | +---------+ |
49 * | | ^ |
50 * | +--+ |
51 * | Receive CRETRY |
52 * | CLOSE |
53 * +--------------------------------------------------+
54 */
55
56 typedef struct private_pb_tnc_state_machine_t private_pb_tnc_state_machine_t;
57
58 /**
59 * Private data of a pb_tnc_state_machine_t object.
60 *
61 */
62 struct private_pb_tnc_state_machine_t {
63 /**
64 * Public pb_pa_message_t interface.
65 */
66 pb_tnc_state_machine_t public;
67
68 /**
69 * PB-TNC Server if TRUE, PB-TNC Client if FALSE
70 */
71 bool is_server;
72
73 /**
74 * Informs whether last received PB-TNC CDATA Batch was empty
75 */
76 bool empty_cdata;
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 type == PB_BATCH_SRETRY))
117 {
118 this->state = PB_STATE_CLIENT_WORKING;
119 break;
120 }
121 if (!this->is_server && type == PB_BATCH_RESULT)
122 {
123 this->state = PB_STATE_DECIDED;
124 break;
125 }
126 if (this->is_server && type == PB_BATCH_CRETRY)
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 &&
138 (type == PB_BATCH_CDATA || type == PB_BATCH_CRETRY))
139 {
140 this->state = PB_STATE_SERVER_WORKING;
141 break;
142 }
143 if (type == PB_BATCH_CLOSE)
144 {
145 this->state = PB_STATE_END;
146 break;
147 }
148 return FALSE;
149 case PB_STATE_DECIDED:
150 if ((this->is_server && type == PB_BATCH_CRETRY) ||
151 (!this->is_server && type == PB_BATCH_SRETRY))
152 {
153 this->state = PB_STATE_SERVER_WORKING;
154 break;
155 }
156 if (type == PB_BATCH_CLOSE)
157 {
158 this->state = PB_STATE_END;
159 break;
160 }
161 return FALSE;
162 case PB_STATE_END:
163 if (type == PB_BATCH_CLOSE)
164 {
165 break;
166 }
167 return FALSE;
168 }
169
170 if (this->state != old_state)
171 {
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);
174 }
175 return TRUE;
176 }
177
178 METHOD(pb_tnc_state_machine_t, send_batch, bool,
179 private_pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type)
180 {
181 pb_tnc_state_t old_state = this->state;
182
183 switch (this->state)
184 {
185 case PB_STATE_INIT:
186 if (!this->is_server && type == PB_BATCH_CDATA)
187 {
188 this->state = PB_STATE_SERVER_WORKING;
189 break;
190 }
191 if (this->is_server && type == PB_BATCH_SDATA)
192 {
193 this->state = PB_STATE_CLIENT_WORKING;
194 break;
195 }
196 if (type == PB_BATCH_CLOSE)
197 {
198 this->state = PB_STATE_END;
199 break;
200 }
201 return FALSE;
202 case PB_STATE_SERVER_WORKING:
203 if (this->is_server && (type == PB_BATCH_SDATA ||
204 type == PB_BATCH_SRETRY))
205 {
206 this->state = PB_STATE_CLIENT_WORKING;
207 break;
208 }
209 if (this->is_server && type == PB_BATCH_RESULT)
210 {
211 this->state = PB_STATE_DECIDED;
212 break;
213 }
214 if (!this->is_server && type == PB_BATCH_CRETRY)
215 {
216 break;
217 }
218 if (type == PB_BATCH_CLOSE)
219 {
220 this->state = PB_STATE_END;
221 break;
222 }
223 return FALSE;
224 case PB_STATE_CLIENT_WORKING:
225 if (!this->is_server && (type == PB_BATCH_CDATA ||
226 type == PB_BATCH_CRETRY))
227 {
228 this->state = PB_STATE_SERVER_WORKING;
229 break;
230 }
231 if (this->is_server && type == PB_BATCH_SRETRY)
232 {
233 break;
234 }
235 if (type == PB_BATCH_CLOSE)
236 {
237 this->state = PB_STATE_END;
238 break;
239 }
240 return FALSE;
241 case PB_STATE_DECIDED:
242 if ((this->is_server && type == PB_BATCH_SRETRY) ||
243 (!this->is_server && type == PB_BATCH_CRETRY))
244 {
245 this->state = PB_STATE_SERVER_WORKING;
246 break;
247 }
248 if (type == PB_BATCH_CLOSE)
249 {
250 this->state = PB_STATE_END;
251 break;
252 }
253 return FALSE;
254 case PB_STATE_END:
255 if (type == PB_BATCH_CLOSE)
256 {
257 break;
258 }
259 return FALSE;
260 }
261
262 if (this->state != old_state)
263 {
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);
266 }
267 return TRUE;
268 }
269
270 METHOD(pb_tnc_state_machine_t, get_empty_cdata, bool,
271 private_pb_tnc_state_machine_t *this)
272 {
273 return this->empty_cdata;
274 }
275
276 METHOD(pb_tnc_state_machine_t, set_empty_cdata, void,
277 private_pb_tnc_state_machine_t *this, bool empty)
278 {
279 if (empty)
280 {
281 DBG2(DBG_TNC, "received empty PB-TNC CDATA batch");
282 }
283 this->empty_cdata = empty;
284 }
285
286 METHOD(pb_tnc_state_machine_t, destroy, void,
287 private_pb_tnc_state_machine_t *this)
288 {
289 free(this);
290 }
291
292 /**
293 * See header
294 */
295 pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server)
296 {
297 private_pb_tnc_state_machine_t *this;
298
299 INIT(this,
300 .public = {
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,
306 .destroy = _destroy,
307 },
308 .is_server = is_server,
309 .state = PB_STATE_INIT,
310 );
311
312 return &this->public;
313 }