ab575d425f151eee9aa6d63b80e3e26cd4602781
[strongswan.git] / Source / charon / encoding / payloads / proposal_substructure.c
1 /**
2 * @file proposal_substructure.h
3 *
4 * @brief Declaration of the class proposal_substructure_t.
5 *
6 * An object of this type represents an IKEv2 PROPOSAL Substructure and contains transforms.
7 *
8 */
9
10 /*
11 * Copyright (C) 2005 Jan Hutter, Martin Willi
12 * Hochschule fuer Technik Rapperswil
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25 /* offsetof macro */
26 #include <stddef.h>
27
28 #include "proposal_substructure.h"
29
30 #include <encoding/payloads/encodings.h>
31 #include <encoding/payloads/transform_substructure.h>
32 #include <types.h>
33 #include <utils/allocator.h>
34 #include <utils/linked_list.h>
35
36 typedef struct private_proposal_substructure_t private_proposal_substructure_t;
37
38 /**
39 * Private data of an proposal_substructure_t' Object
40 *
41 */
42 struct private_proposal_substructure_t {
43 /**
44 * public proposal_substructure_t interface
45 */
46 proposal_substructure_t public;
47
48 /**
49 * next payload type
50 */
51 u_int8_t next_payload;
52
53
54 /**
55 * Length of this payload
56 */
57 u_int16_t proposal_length;
58
59
60 /**
61 * Proposal number
62 */
63 u_int8_t proposal_number;
64
65 /**
66 * Protocol ID
67 */
68 u_int8_t protocol_id;
69
70 /**
71 * SPI size of the following SPI
72 */
73 u_int8_t spi_size;
74
75 /**
76 * Number of transforms
77 */
78 u_int8_t transforms_count;
79
80 /**
81 * SPI is stored as chunk
82 */
83 chunk_t spi;
84
85 /**
86 * Transforms are stored in a linked_list_t
87 */
88 linked_list_t * transforms;
89
90 /**
91 * @brief Computes the length of this substructure.
92 *
93 * @param this calling private_proposal_substructure_t object
94 * @return
95 * SUCCESS in any case
96 */
97 status_t (*compute_length) (private_proposal_substructure_t *this);
98 };
99
100 /**
101 * Encoding rules to parse or generate a Proposal substructure
102 *
103 * The defined offsets are the positions in a object of type
104 * private_proposal_substructure_t.
105 *
106 */
107 encoding_rule_t proposal_substructure_encodings[] = {
108 /* 1 Byte next payload type, stored in the field next_payload */
109 { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) },
110 /* Reserved Byte is skipped */
111 { RESERVED_BYTE, 0 },
112 /* Length of the whole proposal substructure payload*/
113 { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) },
114 /* proposal number is a number of 8 bit */
115 { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) },
116 /* protocol ID is a number of 8 bit */
117 { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) },
118 /* SPI Size has its own type */
119 { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) },
120 /* Number of transforms is a number of 8 bit */
121 { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) },
122 /* SPI is a chunk of variable size*/
123 { SPI, offsetof(private_proposal_substructure_t, spi) },
124 /* Transforms are stored in a transform substructure,
125 offset points to a linked_list_t pointer */
126 { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) }
127 };
128
129 /*
130 1 2 3
131 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133 ! 0 (last) or 2 ! RESERVED ! Proposal Length !
134 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135 ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137 ~ SPI (variable) ~
138 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 ! !
140 ~ <Transforms> ~
141 ! !
142 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143 */
144
145 /**
146 * Implements payload_t's verify function.
147 * See #payload_s.verify for description.
148 */
149 static status_t verify(private_proposal_substructure_t *this)
150 {
151 if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != PROPOSAL_SUBSTRUCTURE))
152 {
153 /* must be 0 or 2 */
154 return FAILED;
155 }
156 if (this->transforms_count != this->transforms->get_count(this->transforms))
157 {
158 /* must be the same! */
159 return FAILED;
160 }
161
162 if (this->protocol_id > 4)
163 {
164 /* reserved are not supported */
165 return FAILED;
166 }
167
168 /* proposal number is checked in SA payload */
169 return SUCCESS;
170 }
171
172 /**
173 * Implements payload_t's get_encoding_rules function.
174 * See #payload_s.get_encoding_rules for description.
175 */
176 static status_t get_encoding_rules(private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
177 {
178 *rules = proposal_substructure_encodings;
179 *rule_count = sizeof(proposal_substructure_encodings) / sizeof(encoding_rule_t);
180
181 return SUCCESS;
182 }
183
184 /**
185 * Implements payload_t's get_type function.
186 * See #payload_s.get_type for description.
187 */
188 static payload_type_t get_type(private_proposal_substructure_t *this)
189 {
190 return PROPOSAL_SUBSTRUCTURE;
191 }
192
193 /**
194 * Implements payload_t's get_next_type function.
195 * See #payload_s.get_next_type for description.
196 */
197 static payload_type_t get_next_type(private_proposal_substructure_t *this)
198 {
199 return (this->next_payload);
200 }
201
202 /**
203 * Implements payload_t's set_next_type function.
204 * See #payload_s.set_next_type for description.
205 */
206 static status_t set_next_type(private_proposal_substructure_t *this,payload_type_t type)
207 {
208 return SUCCESS;
209 }
210
211 /**
212 * Implements payload_t's get_length function.
213 * See #payload_s.get_length for description.
214 */
215 static size_t get_length(private_proposal_substructure_t *this)
216 {
217 return this->proposal_length;
218 }
219
220 /**
221 * Implements proposal_substructure_t's create_transform_substructure_iterator function.
222 * See #proposal_substructure_s.create_transform_substructure_iterator for description.
223 */
224 static status_t create_transform_substructure_iterator (private_proposal_substructure_t *this,iterator_t **iterator,bool forward)
225 {
226 return (this->transforms->create_iterator(this->transforms,iterator,forward));
227 }
228
229 /**
230 * Implements proposal_substructure_t's add_transform_substructure function.
231 * See #proposal_substructure_s.add_transform_substructure for description.
232 */
233 static status_t add_transform_substructure (private_proposal_substructure_t *this,transform_substructure_t *transform)
234 {
235 status_t status;
236 if (this->transforms->get_count(this->transforms) > 0)
237 {
238 transform_substructure_t *last_transform;
239 status = this->transforms->get_last(this->transforms,(void **) &last_transform);
240 /* last transform is now not anymore last one */
241 last_transform->set_is_last_transform(last_transform,FALSE);
242
243 }
244 transform->set_is_last_transform(transform,TRUE);
245
246 status = this->transforms->insert_last(this->transforms,(void *) transform);
247 this->compute_length(this);
248 return status;
249 }
250
251 /**
252 * Implements proposal_substructure_t's set_proposal_number function.
253 * See #proposal_substructure_s.set_proposal_number for description.
254 */
255 static status_t set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number)
256 {
257 this->proposal_number = proposal_number;
258 return SUCCESS;
259 }
260
261 /**
262 * Implements proposal_substructure_t's get_proposal_number function.
263 * See #proposal_substructure_s.get_proposal_number for description.
264 */
265 static u_int8_t get_proposal_number (private_proposal_substructure_t *this)
266 {
267 return (this->proposal_number);
268 }
269
270 /**
271 * Implements proposal_substructure_t's set_protocol_id function.
272 * See #proposal_substructure_s.set_protocol_id for description.
273 */
274 static status_t set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id)
275 {
276 this->protocol_id = protocol_id;
277 return SUCCESS;
278 }
279
280 /**
281 * Implements proposal_substructure_t's get_protocol_id function.
282 * See #proposal_substructure_s.get_protocol_id for description.
283 */
284 static u_int8_t get_protocol_id (private_proposal_substructure_t *this)
285 {
286 return (this->protocol_id);
287 }
288
289
290 /**
291 * Implements proposal_substructure_t's set_spi function.
292 * See #proposal_substructure_s.set_spi for description.
293 */
294 static status_t set_spi (private_proposal_substructure_t *this, chunk_t spi)
295 {
296 /* first delete already set spi value */
297 if (this->spi.ptr != NULL)
298 {
299 allocator_free(this->spi.ptr);
300 this->spi.ptr = NULL;
301 this->spi.len = 0;
302 this->compute_length(this);
303 }
304
305 this->spi.ptr = allocator_clone_bytes(spi.ptr,spi.len);
306 if (this->spi.ptr == NULL)
307 {
308 return OUT_OF_RES;
309 }
310 this->spi.len = spi.len;
311 this->spi_size = spi.len;
312 this->compute_length(this);
313
314 return SUCCESS;
315 }
316
317 /**
318 * Implements proposal_substructure_t's get_spi function.
319 * See #proposal_substructure_s.get_spi for description.
320 */
321 static chunk_t get_spi (private_proposal_substructure_t *this)
322 {
323 chunk_t spi;
324 spi.ptr = this->spi.ptr;
325 spi.len = this->spi.len;
326
327 return spi;
328 }
329
330 /**
331 * Implements private_proposal_substructure_t's compute_length function.
332 * See #private_proposal_substructure_s.compute_length for description.
333 */
334 static status_t compute_length (private_proposal_substructure_t *this)
335 {
336 iterator_t *iterator;
337 status_t status;
338 size_t transforms_count = 0;
339 size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
340 status = this->transforms->create_iterator(this->transforms,&iterator,TRUE);
341 if (status != SUCCESS)
342 {
343 return length;
344 }
345 while (iterator->has_next(iterator))
346 {
347 payload_t * current_transform;
348 iterator->current(iterator,(void **) &current_transform);
349 length += current_transform->get_length(current_transform);
350 transforms_count++;
351 }
352 iterator->destroy(iterator);
353
354 length += this->spi.len;
355 this->transforms_count= transforms_count;
356 this->proposal_length = length;
357
358 return SUCCESS;
359 }
360
361 /**
362 * Implements proposal_substructure_t's clone function.
363 * See #proposal_substructure_s.clone for description.
364 */
365 static status_t clone(private_proposal_substructure_t *this, private_proposal_substructure_t **clone)
366 {
367 private_proposal_substructure_t * new_clone;
368 iterator_t *transforms;
369 status_t status;
370
371 new_clone = (private_proposal_substructure_t *) proposal_substructure_create();
372
373 new_clone->next_payload = this->next_payload;
374 new_clone->proposal_number = this->proposal_number;
375 new_clone->protocol_id = this->protocol_id;
376 new_clone->spi_size = this->spi_size;
377 if (this->spi.ptr != NULL)
378 {
379 new_clone->spi.ptr = allocator_clone_bytes(this->spi.ptr,this->spi.len);
380 if (new_clone->spi.ptr == NULL)
381 {
382 new_clone->public.destroy(&(new_clone->public));
383 return OUT_OF_RES;
384 }
385 new_clone->spi.len = this->spi.len;
386 }
387
388 status = this->transforms->create_iterator(this->transforms,&transforms,FALSE);
389 if (status != SUCCESS)
390 {
391 new_clone->public.destroy(&(new_clone->public));
392 return status;
393 }
394
395 while (transforms->has_next(transforms))
396 {
397 transform_substructure_t *current_transform;
398 transform_substructure_t *current_transform_clone;
399 status = transforms->current(transforms,(void **) &current_transform);
400 if (status != SUCCESS)
401 {
402 transforms->destroy(transforms);
403 new_clone->public.destroy(&(new_clone->public));
404 return status;
405 }
406 status = current_transform->clone(current_transform,&current_transform_clone);
407 if (status != SUCCESS)
408 {
409 transforms->destroy(transforms);
410 new_clone->public.destroy(&(new_clone->public));
411 return status;
412 }
413
414 status = new_clone->public.add_transform_substructure(&(new_clone->public),current_transform_clone);
415 if (status != SUCCESS)
416 {
417 transforms->destroy(transforms);
418 current_transform_clone->destroy(current_transform_clone);
419 new_clone->public.destroy(&(new_clone->public));
420 return status;
421 }
422 }
423
424 transforms->destroy(transforms);
425
426 *clone = new_clone;
427
428 return SUCCESS;
429 }
430
431 /**
432 * Implements payload_t's and proposal_substructure_t's destroy function.
433 * See #payload_s.destroy or proposal_substructure_s.destroy for description.
434 */
435 static status_t destroy(private_proposal_substructure_t *this)
436 {
437 /* all proposals are getting destroyed */
438 while (this->transforms->get_count(this->transforms) > 0)
439 {
440 transform_substructure_t *current_transform;
441 if (this->transforms->remove_last(this->transforms,(void **)&current_transform) != SUCCESS)
442 {
443 break;
444 }
445 current_transform->destroy(current_transform);
446 }
447 this->transforms->destroy(this->transforms);
448
449 if (this->spi.ptr != NULL)
450 {
451 allocator_free(this->spi.ptr);
452 }
453
454 allocator_free(this);
455
456 return SUCCESS;
457 }
458
459 /*
460 * Described in header
461 */
462 proposal_substructure_t *proposal_substructure_create()
463 {
464 private_proposal_substructure_t *this = allocator_alloc_thing(private_proposal_substructure_t);
465 if (this == NULL)
466 {
467 return NULL;
468 }
469
470 /* interface functions */
471 this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
472 this->public.payload_interface.get_encoding_rules = (status_t (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
473 this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
474 this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
475 this->public.payload_interface.set_next_type = (status_t (*) (payload_t *,payload_type_t)) set_next_type;
476 this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
477 this->public.payload_interface.destroy = (status_t (*) (payload_t *))destroy;
478
479 /* public functions */
480 this->public.create_transform_substructure_iterator = (status_t (*) (proposal_substructure_t *,iterator_t **,bool)) create_transform_substructure_iterator;
481 this->public.add_transform_substructure = (status_t (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure;
482 this->public.set_proposal_number = (status_t (*) (proposal_substructure_t *,u_int8_t))set_proposal_number;
483 this->public.get_proposal_number = (u_int8_t (*) (proposal_substructure_t *)) get_proposal_number;
484 this->public.set_protocol_id = (status_t (*) (proposal_substructure_t *,u_int8_t))set_protocol_id;
485 this->public.get_protocol_id = (u_int8_t (*) (proposal_substructure_t *)) get_protocol_id;
486 this->public.set_spi = (status_t (*) (proposal_substructure_t *,chunk_t))set_spi;
487 this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi;
488 this->public.clone = (status_t (*) (proposal_substructure_t *, proposal_substructure_t **)) clone;
489 this->public.destroy = (status_t (*) (proposal_substructure_t *)) destroy;
490
491 /* private functions */
492 this->compute_length = compute_length;
493
494 /* set default values of the fields */
495 this->next_payload = NO_PAYLOAD;
496 this->proposal_length = 0;
497 this->proposal_number = 0;
498 this->protocol_id = 0;
499 this->transforms_count = 0;
500 this->spi_size = 0;
501 this->spi.ptr = NULL;
502 this->spi.len = 0;
503
504 this->transforms = linked_list_create();
505
506 if (this->transforms == NULL)
507 {
508 allocator_free(this);
509 return NULL;
510 }
511 return (&(this->public));
512 }