]>
Commit | Line | Data |
---|---|---|
da42afc5 JH |
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 | */ | |
b860cffd | 24 | |
da42afc5 JH |
25 | /* offsetof macro */ |
26 | #include <stddef.h> | |
27 | ||
28 | #include "proposal_substructure.h" | |
29 | ||
4a962238 MW |
30 | #include <encoding/payloads/encodings.h> |
31 | #include <encoding/payloads/transform_substructure.h> | |
696be022 JH |
32 | #include <types.h> |
33 | #include <utils/allocator.h> | |
34 | #include <utils/linked_list.h> | |
da42afc5 | 35 | |
95c61cb9 JH |
36 | typedef struct private_proposal_substructure_t private_proposal_substructure_t; |
37 | ||
da42afc5 JH |
38 | /** |
39 | * Private data of an proposal_substructure_t' Object | |
40 | * | |
41 | */ | |
95c61cb9 | 42 | struct private_proposal_substructure_t { |
da42afc5 JH |
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; | |
67978e0b JH |
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); | |
da42afc5 JH |
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 }, | |
b860cffd | 112 | /* Length of the whole proposal substructure payload*/ |
da42afc5 JH |
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 | ||
e31eb71e JH |
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 | ||
da42afc5 JH |
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 | ||
32cbc7bc JH |
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 | ||
da42afc5 JH |
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 | ||
b860cffd JH |
220 | /** |
221 | * Implements proposal_substructure_t's create_transform_substructure_iterator function. | |
222 | * See #proposal_substructure_s.create_transform_substructure_iterator for description. | |
223 | */ | |
bdb141cb | 224 | static status_t create_transform_substructure_iterator (private_proposal_substructure_t *this,iterator_t **iterator,bool forward) |
b860cffd JH |
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 | { | |
a14dffd1 JH |
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); | |
67978e0b | 247 | this->compute_length(this); |
a14dffd1 | 248 | return status; |
67978e0b JH |
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); | |
b860cffd JH |
287 | } |
288 | ||
67978e0b JH |
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 | { | |
bdb141cb | 336 | iterator_t *iterator; |
67978e0b JH |
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 **) ¤t_transform); | |
349 | length += current_transform->get_length(current_transform); | |
350 | transforms_count++; | |
351 | } | |
a14dffd1 | 352 | iterator->destroy(iterator); |
67978e0b JH |
353 | |
354 | length += this->spi.len; | |
67978e0b JH |
355 | this->transforms_count= transforms_count; |
356 | this->proposal_length = length; | |
357 | ||
358 | return SUCCESS; | |
359 | } | |
360 | ||
b9459040 JH |
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; | |
bdb141cb | 368 | iterator_t *transforms; |
b9459040 JH |
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 **) ¤t_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,¤t_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 **)¤t_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 | } | |
67978e0b | 458 | |
da42afc5 JH |
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 | } | |
e31eb71e JH |
469 | |
470 | /* interface functions */ | |
471 | this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; | |
da42afc5 JH |
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; | |
32cbc7bc | 475 | this->public.payload_interface.set_next_type = (status_t (*) (payload_t *,payload_type_t)) set_next_type; |
da42afc5 JH |
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; | |
e31eb71e JH |
478 | |
479 | /* public functions */ | |
bdb141cb | 480 | this->public.create_transform_substructure_iterator = (status_t (*) (proposal_substructure_t *,iterator_t **,bool)) create_transform_substructure_iterator; |
b860cffd | 481 | this->public.add_transform_substructure = (status_t (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure; |
67978e0b JH |
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; | |
b9459040 | 488 | this->public.clone = (status_t (*) (proposal_substructure_t *, proposal_substructure_t **)) clone; |
da42afc5 JH |
489 | this->public.destroy = (status_t (*) (proposal_substructure_t *)) destroy; |
490 | ||
67978e0b JH |
491 | /* private functions */ |
492 | this->compute_length = compute_length; | |
493 | ||
da42afc5 JH |
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 | } |