2 * @file proposal_substructure.h
4 * @brief Implementation of proposal_substructure_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 #include "proposal_substructure.h"
28 #include <encoding/payloads/encodings.h>
29 #include <encoding/payloads/transform_substructure.h>
31 #include <utils/allocator.h>
32 #include <utils/linked_list.h>
34 typedef struct private_proposal_substructure_t private_proposal_substructure_t
;
37 * Private data of an proposal_substructure_t object.
40 struct private_proposal_substructure_t
{
42 * Public proposal_substructure_t interface.
44 proposal_substructure_t
public;
49 u_int8_t next_payload
;
52 * Length of this payload.
54 u_int16_t proposal_length
;
59 u_int8_t proposal_number
;
67 * SPI size of the following SPI.
72 * Number of transforms.
74 u_int8_t transforms_count
;
77 * SPI is stored as chunk.
82 * Transforms are stored in a linked_list_t.
84 linked_list_t
* transforms
;
87 * @brief Computes the length of this substructure.
89 * @param this calling private_proposal_substructure_t object
91 void (*compute_length
) (private_proposal_substructure_t
*this);
95 * Encoding rules to parse or generate a Proposal substructure.
97 * The defined offsets are the positions in a object of type
98 * private_proposal_substructure_t.
101 encoding_rule_t proposal_substructure_encodings
[] = {
102 /* 1 Byte next payload type, stored in the field next_payload */
103 { U_INT_8
, offsetof(private_proposal_substructure_t
, next_payload
) },
104 /* Reserved Byte is skipped */
105 { RESERVED_BYTE
, 0 },
106 /* Length of the whole proposal substructure payload*/
107 { PAYLOAD_LENGTH
, offsetof(private_proposal_substructure_t
, proposal_length
) },
108 /* proposal number is a number of 8 bit */
109 { U_INT_8
, offsetof(private_proposal_substructure_t
, proposal_number
) },
110 /* protocol ID is a number of 8 bit */
111 { U_INT_8
, offsetof(private_proposal_substructure_t
, protocol_id
) },
112 /* SPI Size has its own type */
113 { SPI_SIZE
, offsetof(private_proposal_substructure_t
, spi_size
) },
114 /* Number of transforms is a number of 8 bit */
115 { U_INT_8
, offsetof(private_proposal_substructure_t
, transforms_count
) },
116 /* SPI is a chunk of variable size*/
117 { SPI
, offsetof(private_proposal_substructure_t
, spi
) },
118 /* Transforms are stored in a transform substructure,
119 offset points to a linked_list_t pointer */
120 { TRANSFORMS
, offsetof(private_proposal_substructure_t
, transforms
) }
125 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
126 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
127 ! 0 (last) or 2 ! RESERVED ! Proposal Length !
128 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129 ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
130 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140 * Implementation of payload_t.verify.
142 static status_t
verify(private_proposal_substructure_t
*this)
144 status_t status
= SUCCESS
;
145 iterator_t
*iterator
;
147 if ((this->next_payload
!= NO_PAYLOAD
) && (this->next_payload
!= 2))
152 if (this->transforms_count
!= this->transforms
->get_count(this->transforms
))
154 /* must be the same! */
158 if (this->protocol_id
> 4)
160 /* reserved are not supported */
164 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
166 while(iterator
->has_next(iterator
))
168 payload_t
*current_transform
;
169 iterator
->current(iterator
,(void **)¤t_transform
);
171 status
= current_transform
->verify(current_transform
);
172 if (status
!= SUCCESS
)
178 iterator
->destroy(iterator
);
181 /* proposal number is checked in SA payload */
186 * Implementation of payload_t.get_encoding_rules.
188 static void get_encoding_rules(private_proposal_substructure_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
190 *rules
= proposal_substructure_encodings
;
191 *rule_count
= sizeof(proposal_substructure_encodings
) / sizeof(encoding_rule_t
);
195 * Implementation of payload_t.get_type.
197 static payload_type_t
get_type(private_proposal_substructure_t
*this)
199 return PROPOSAL_SUBSTRUCTURE
;
203 * Implementation of payload_t.get_next_type.
205 static payload_type_t
get_next_type(private_proposal_substructure_t
*this)
207 return (this->next_payload
);
211 * Implementation of payload_t.set_next_type.
213 static void set_next_type(private_proposal_substructure_t
*this,payload_type_t type
)
218 * Implementation of payload_t.get_length.
220 static size_t get_length(private_proposal_substructure_t
*this)
222 return this->proposal_length
;
226 * Implementation of proposal_substructure_t.create_transform_substructure_iterator.
228 static iterator_t
*create_transform_substructure_iterator (private_proposal_substructure_t
*this,bool forward
)
230 return (this->transforms
->create_iterator(this->transforms
,forward
));
234 * Implementation of proposal_substructure_t.add_transform_substructure.
236 static void add_transform_substructure (private_proposal_substructure_t
*this,transform_substructure_t
*transform
)
239 if (this->transforms
->get_count(this->transforms
) > 0)
241 transform_substructure_t
*last_transform
;
242 status
= this->transforms
->get_last(this->transforms
,(void **) &last_transform
);
243 /* last transform is now not anymore last one */
244 last_transform
->set_is_last_transform(last_transform
,FALSE
);
247 transform
->set_is_last_transform(transform
,TRUE
);
249 this->transforms
->insert_last(this->transforms
,(void *) transform
);
250 this->compute_length(this);
254 * Implementation of proposal_substructure_t.proposal_substructure_t.
256 static void set_is_last_proposal (private_proposal_substructure_t
*this, bool is_last
)
258 this->next_payload
= (is_last
) ?
0: PROPOSAL_TYPE_VALUE
;
263 * Implementation of proposal_substructure_t.set_proposal_number.
265 static void set_proposal_number(private_proposal_substructure_t
*this,u_int8_t proposal_number
)
267 this->proposal_number
= proposal_number
;
271 * Implementation of proposal_substructure_t.get_proposal_number.
273 static u_int8_t
get_proposal_number (private_proposal_substructure_t
*this)
275 return (this->proposal_number
);
279 * Implementation of proposal_substructure_t.set_protocol_id.
281 static void set_protocol_id(private_proposal_substructure_t
*this,u_int8_t protocol_id
)
283 this->protocol_id
= protocol_id
;
287 * Implementation of proposal_substructure_t.get_protocol_id.
289 static u_int8_t
get_protocol_id (private_proposal_substructure_t
*this)
291 return (this->protocol_id
);
295 * Implementation of proposal_substructure_t.set_spi.
297 static void set_spi (private_proposal_substructure_t
*this, chunk_t spi
)
299 /* first delete already set spi value */
300 if (this->spi
.ptr
!= NULL
)
302 allocator_free(this->spi
.ptr
);
303 this->spi
.ptr
= NULL
;
305 this->compute_length(this);
308 this->spi
.ptr
= allocator_clone_bytes(spi
.ptr
,spi
.len
);
309 this->spi
.len
= spi
.len
;
310 this->spi_size
= spi
.len
;
311 this->compute_length(this);
315 * Implementation of proposal_substructure_t.get_spi.
317 static chunk_t
get_spi (private_proposal_substructure_t
*this)
320 spi
.ptr
= this->spi
.ptr
;
321 spi
.len
= this->spi
.len
;
327 * Implementation of proposal_substructure_t.get_info_for_transform_type.
329 static status_t
get_info_for_transform_type (private_proposal_substructure_t
*this,transform_type_t type
, u_int16_t
*transform_id
, u_int16_t
*key_length
)
331 iterator_t
*iterator
;
333 u_int16_t found_transform_id
;
334 u_int16_t found_key_length
;
336 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
338 while (iterator
->has_next(iterator
))
340 transform_substructure_t
*current_transform
;
341 status
= iterator
->current(iterator
,(void **) ¤t_transform
);
342 if (status
!= SUCCESS
)
346 if (current_transform
->get_transform_type(current_transform
) == type
)
348 /* now get data for specific type */
349 found_transform_id
= current_transform
->get_transform_id(current_transform
);
350 status
= current_transform
->get_key_length(current_transform
,&found_key_length
);
351 *transform_id
= found_transform_id
;
352 *key_length
= found_key_length
;
353 iterator
->destroy(iterator
);
357 iterator
->destroy(iterator
);
362 * Implementation of private_proposal_substructure_t.compute_length.
364 static void compute_length (private_proposal_substructure_t
*this)
366 iterator_t
*iterator
;
367 size_t transforms_count
= 0;
368 size_t length
= PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
;
369 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
370 while (iterator
->has_next(iterator
))
372 payload_t
* current_transform
;
373 iterator
->current(iterator
,(void **) ¤t_transform
);
374 length
+= current_transform
->get_length(current_transform
);
377 iterator
->destroy(iterator
);
379 length
+= this->spi
.len
;
380 this->transforms_count
= transforms_count
;
381 this->proposal_length
= length
;
386 * Implementation of proposal_substructure_t.get_transform_count.
388 static size_t get_transform_count (private_proposal_substructure_t
*this)
390 return this->transforms
->get_count(this->transforms
);
394 * Implementation of proposal_substructure_t.get_spi_size.
396 static size_t get_spi_size (private_proposal_substructure_t
*this)
398 return this->spi
.len
;
402 * Implementation of proposal_substructure_t.clone.
404 static private_proposal_substructure_t
* clone(private_proposal_substructure_t
*this)
406 private_proposal_substructure_t
* new_clone
;
407 iterator_t
*transforms
;
409 new_clone
= (private_proposal_substructure_t
*) proposal_substructure_create();
411 new_clone
->next_payload
= this->next_payload
;
412 new_clone
->proposal_number
= this->proposal_number
;
413 new_clone
->protocol_id
= this->protocol_id
;
414 new_clone
->spi_size
= this->spi_size
;
415 if (this->spi
.ptr
!= NULL
)
417 new_clone
->spi
.ptr
= allocator_clone_bytes(this->spi
.ptr
,this->spi
.len
);
418 new_clone
->spi
.len
= this->spi
.len
;
421 transforms
= this->transforms
->create_iterator(this->transforms
,FALSE
);
423 while (transforms
->has_next(transforms
))
425 transform_substructure_t
*current_transform
;
426 transform_substructure_t
*current_transform_clone
;
428 transforms
->current(transforms
,(void **) ¤t_transform
);
430 current_transform_clone
= current_transform
->clone(current_transform
);
432 new_clone
->public.add_transform_substructure(&(new_clone
->public),current_transform_clone
);
435 transforms
->destroy(transforms
);
441 * Implements payload_t's and proposal_substructure_t's destroy function.
442 * See #payload_s.destroy or proposal_substructure_s.destroy for description.
444 static status_t
destroy(private_proposal_substructure_t
*this)
446 /* all proposals are getting destroyed */
447 while (this->transforms
->get_count(this->transforms
) > 0)
449 transform_substructure_t
*current_transform
;
450 if (this->transforms
->remove_last(this->transforms
,(void **)¤t_transform
) != SUCCESS
)
454 current_transform
->destroy(current_transform
);
456 this->transforms
->destroy(this->transforms
);
458 if (this->spi
.ptr
!= NULL
)
460 allocator_free(this->spi
.ptr
);
463 allocator_free(this);
469 * Described in header.
471 proposal_substructure_t
*proposal_substructure_create()
473 private_proposal_substructure_t
*this = allocator_alloc_thing(private_proposal_substructure_t
);
475 /* interface functions */
476 this->public.payload_interface
.verify
= (status_t (*) (payload_t
*))verify
;
477 this->public.payload_interface
.get_encoding_rules
= (void (*) (payload_t
*, encoding_rule_t
**, size_t *) ) get_encoding_rules
;
478 this->public.payload_interface
.get_length
= (size_t (*) (payload_t
*)) get_length
;
479 this->public.payload_interface
.get_next_type
= (payload_type_t (*) (payload_t
*)) get_next_type
;
480 this->public.payload_interface
.set_next_type
= (void (*) (payload_t
*,payload_type_t
)) set_next_type
;
481 this->public.payload_interface
.get_type
= (payload_type_t (*) (payload_t
*)) get_type
;
482 this->public.payload_interface
.destroy
= (void (*) (payload_t
*))destroy
;
484 /* public functions */
485 this->public.create_transform_substructure_iterator
= (iterator_t
* (*) (proposal_substructure_t
*,bool)) create_transform_substructure_iterator
;
486 this->public.add_transform_substructure
= (void (*) (proposal_substructure_t
*,transform_substructure_t
*)) add_transform_substructure
;
487 this->public.set_proposal_number
= (void (*) (proposal_substructure_t
*,u_int8_t
))set_proposal_number
;
488 this->public.get_proposal_number
= (u_int8_t (*) (proposal_substructure_t
*)) get_proposal_number
;
489 this->public.set_protocol_id
= (void (*) (proposal_substructure_t
*,u_int8_t
))set_protocol_id
;
490 this->public.get_protocol_id
= (u_int8_t (*) (proposal_substructure_t
*)) get_protocol_id
;
491 this->public.get_info_for_transform_type
= (status_t (*) (proposal_substructure_t
*,transform_type_t
,u_int16_t
*, u_int16_t
*))get_info_for_transform_type
;
492 this->public.set_is_last_proposal
= (void (*) (proposal_substructure_t
*,bool)) set_is_last_proposal
;
494 this->public.set_spi
= (void (*) (proposal_substructure_t
*,chunk_t
))set_spi
;
495 this->public.get_spi
= (chunk_t (*) (proposal_substructure_t
*)) get_spi
;
496 this->public.get_transform_count
= (size_t (*) (proposal_substructure_t
*)) get_transform_count
;
497 this->public.get_spi_size
= (size_t (*) (proposal_substructure_t
*)) get_spi_size
;
498 this->public.clone
= (proposal_substructure_t
* (*) (proposal_substructure_t
*)) clone
;
499 this->public.destroy
= (void (*) (proposal_substructure_t
*)) destroy
;
502 /* private functions */
503 this->compute_length
= compute_length
;
505 /* set default values of the fields */
506 this->next_payload
= NO_PAYLOAD
;
507 this->proposal_length
= 0;
508 this->proposal_number
= 0;
509 this->protocol_id
= 0;
510 this->transforms_count
= 0;
512 this->spi
.ptr
= NULL
;
515 this->transforms
= linked_list_create();
517 return (&(this->public));