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>
35 * String mappings for protocol_id_t.
37 mapping_t protocol_id_m
[] = {
38 {UNDEFINED_PROTOCOL_ID
, "UNDEFINED_PROTOCOL_ID"},
46 typedef struct private_proposal_substructure_t private_proposal_substructure_t
;
49 * Private data of an proposal_substructure_t object.
52 struct private_proposal_substructure_t
{
54 * Public proposal_substructure_t interface.
56 proposal_substructure_t
public;
61 u_int8_t next_payload
;
64 * Length of this payload.
66 u_int16_t proposal_length
;
71 u_int8_t proposal_number
;
79 * SPI size of the following SPI.
84 * Number of transforms.
86 u_int8_t transforms_count
;
89 * SPI is stored as chunk.
94 * Transforms are stored in a linked_list_t.
96 linked_list_t
* transforms
;
99 * @brief Computes the length of this substructure.
101 * @param this calling private_proposal_substructure_t object
103 void (*compute_length
) (private_proposal_substructure_t
*this);
107 * Encoding rules to parse or generate a Proposal substructure.
109 * The defined offsets are the positions in a object of type
110 * private_proposal_substructure_t.
113 encoding_rule_t proposal_substructure_encodings
[] = {
114 /* 1 Byte next payload type, stored in the field next_payload */
115 { U_INT_8
, offsetof(private_proposal_substructure_t
, next_payload
) },
116 /* Reserved Byte is skipped */
117 { RESERVED_BYTE
, 0 },
118 /* Length of the whole proposal substructure payload*/
119 { PAYLOAD_LENGTH
, offsetof(private_proposal_substructure_t
, proposal_length
) },
120 /* proposal number is a number of 8 bit */
121 { U_INT_8
, offsetof(private_proposal_substructure_t
, proposal_number
) },
122 /* protocol ID is a number of 8 bit */
123 { U_INT_8
, offsetof(private_proposal_substructure_t
, protocol_id
) },
124 /* SPI Size has its own type */
125 { SPI_SIZE
, offsetof(private_proposal_substructure_t
, spi_size
) },
126 /* Number of transforms is a number of 8 bit */
127 { U_INT_8
, offsetof(private_proposal_substructure_t
, transforms_count
) },
128 /* SPI is a chunk of variable size*/
129 { SPI
, offsetof(private_proposal_substructure_t
, spi
) },
130 /* Transforms are stored in a transform substructure,
131 offset points to a linked_list_t pointer */
132 { TRANSFORMS
, offsetof(private_proposal_substructure_t
, transforms
) }
137 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
138 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 ! 0 (last) or 2 ! RESERVED ! Proposal Length !
140 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141 ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
142 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152 * Implementation of payload_t.verify.
154 static status_t
verify(private_proposal_substructure_t
*this)
156 status_t status
= SUCCESS
;
157 iterator_t
*iterator
;
159 if ((this->next_payload
!= NO_PAYLOAD
) && (this->next_payload
!= 2))
164 if (this->transforms_count
!= this->transforms
->get_count(this->transforms
))
166 /* must be the same! */
170 if (this->protocol_id
> 4)
172 /* reserved are not supported */
176 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
178 while(iterator
->has_next(iterator
))
180 payload_t
*current_transform
;
181 iterator
->current(iterator
,(void **)¤t_transform
);
183 status
= current_transform
->verify(current_transform
);
184 if (status
!= SUCCESS
)
190 iterator
->destroy(iterator
);
193 /* proposal number is checked in SA payload */
198 * Implementation of payload_t.get_encoding_rules.
200 static void get_encoding_rules(private_proposal_substructure_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
202 *rules
= proposal_substructure_encodings
;
203 *rule_count
= sizeof(proposal_substructure_encodings
) / sizeof(encoding_rule_t
);
207 * Implementation of payload_t.get_type.
209 static payload_type_t
get_type(private_proposal_substructure_t
*this)
211 return PROPOSAL_SUBSTRUCTURE
;
215 * Implementation of payload_t.get_next_type.
217 static payload_type_t
get_next_type(private_proposal_substructure_t
*this)
219 return (this->next_payload
);
223 * Implementation of payload_t.set_next_type.
225 static void set_next_type(private_proposal_substructure_t
*this,payload_type_t type
)
230 * Implementation of payload_t.get_length.
232 static size_t get_length(private_proposal_substructure_t
*this)
234 return this->proposal_length
;
238 * Implementation of proposal_substructure_t.create_transform_substructure_iterator.
240 static iterator_t
*create_transform_substructure_iterator (private_proposal_substructure_t
*this,bool forward
)
242 return (this->transforms
->create_iterator(this->transforms
,forward
));
246 * Implementation of proposal_substructure_t.add_transform_substructure.
248 static void add_transform_substructure (private_proposal_substructure_t
*this,transform_substructure_t
*transform
)
251 if (this->transforms
->get_count(this->transforms
) > 0)
253 transform_substructure_t
*last_transform
;
254 status
= this->transforms
->get_last(this->transforms
,(void **) &last_transform
);
255 /* last transform is now not anymore last one */
256 last_transform
->set_is_last_transform(last_transform
,FALSE
);
259 transform
->set_is_last_transform(transform
,TRUE
);
261 this->transforms
->insert_last(this->transforms
,(void *) transform
);
262 this->compute_length(this);
266 * Implementation of proposal_substructure_t.proposal_substructure_t.
268 static void set_is_last_proposal (private_proposal_substructure_t
*this, bool is_last
)
270 this->next_payload
= (is_last
) ? 0: PROPOSAL_TYPE_VALUE
;
275 * Implementation of proposal_substructure_t.set_proposal_number.
277 static void set_proposal_number(private_proposal_substructure_t
*this,u_int8_t proposal_number
)
279 this->proposal_number
= proposal_number
;
283 * Implementation of proposal_substructure_t.get_proposal_number.
285 static u_int8_t
get_proposal_number (private_proposal_substructure_t
*this)
287 return (this->proposal_number
);
291 * Implementation of proposal_substructure_t.set_protocol_id.
293 static void set_protocol_id(private_proposal_substructure_t
*this,u_int8_t protocol_id
)
295 this->protocol_id
= protocol_id
;
299 * Implementation of proposal_substructure_t.get_protocol_id.
301 static u_int8_t
get_protocol_id (private_proposal_substructure_t
*this)
303 return (this->protocol_id
);
307 * Implementation of proposal_substructure_t.set_spi.
309 static void set_spi (private_proposal_substructure_t
*this, chunk_t spi
)
311 /* first delete already set spi value */
312 if (this->spi
.ptr
!= NULL
)
314 allocator_free(this->spi
.ptr
);
315 this->spi
.ptr
= NULL
;
317 this->compute_length(this);
320 this->spi
.ptr
= allocator_clone_bytes(spi
.ptr
,spi
.len
);
321 this->spi
.len
= spi
.len
;
322 this->spi_size
= spi
.len
;
323 this->compute_length(this);
327 * Implementation of proposal_substructure_t.get_spi.
329 static chunk_t
get_spi (private_proposal_substructure_t
*this)
332 spi
.ptr
= this->spi
.ptr
;
333 spi
.len
= this->spi
.len
;
339 * Implementation of proposal_substructure_t.get_info_for_transform_type.
341 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
)
343 iterator_t
*iterator
;
345 u_int16_t found_transform_id
;
346 u_int16_t found_key_length
;
348 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
350 while (iterator
->has_next(iterator
))
352 transform_substructure_t
*current_transform
;
353 status
= iterator
->current(iterator
,(void **) ¤t_transform
);
354 if (status
!= SUCCESS
)
358 if (current_transform
->get_transform_type(current_transform
) == type
)
360 /* now get data for specific type */
361 found_transform_id
= current_transform
->get_transform_id(current_transform
);
362 status
= current_transform
->get_key_length(current_transform
,&found_key_length
);
363 *transform_id
= found_transform_id
;
364 *key_length
= found_key_length
;
365 iterator
->destroy(iterator
);
369 iterator
->destroy(iterator
);
374 * Implementation of private_proposal_substructure_t.compute_length.
376 static void compute_length (private_proposal_substructure_t
*this)
378 iterator_t
*iterator
;
379 size_t transforms_count
= 0;
380 size_t length
= PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
;
381 iterator
= this->transforms
->create_iterator(this->transforms
,TRUE
);
382 while (iterator
->has_next(iterator
))
384 payload_t
* current_transform
;
385 iterator
->current(iterator
,(void **) ¤t_transform
);
386 length
+= current_transform
->get_length(current_transform
);
389 iterator
->destroy(iterator
);
391 length
+= this->spi
.len
;
392 this->transforms_count
= transforms_count
;
393 this->proposal_length
= length
;
398 * Implementation of proposal_substructure_t.get_transform_count.
400 static size_t get_transform_count (private_proposal_substructure_t
*this)
402 return this->transforms
->get_count(this->transforms
);
406 * Implementation of proposal_substructure_t.get_spi_size.
408 static size_t get_spi_size (private_proposal_substructure_t
*this)
410 return this->spi
.len
;
414 * Implementation of proposal_substructure_t.clone.
416 static private_proposal_substructure_t
* clone(private_proposal_substructure_t
*this)
418 private_proposal_substructure_t
* new_clone
;
419 iterator_t
*transforms
;
421 new_clone
= (private_proposal_substructure_t
*) proposal_substructure_create();
423 new_clone
->next_payload
= this->next_payload
;
424 new_clone
->proposal_number
= this->proposal_number
;
425 new_clone
->protocol_id
= this->protocol_id
;
426 new_clone
->spi_size
= this->spi_size
;
427 if (this->spi
.ptr
!= NULL
)
429 new_clone
->spi
.ptr
= allocator_clone_bytes(this->spi
.ptr
,this->spi
.len
);
430 new_clone
->spi
.len
= this->spi
.len
;
433 transforms
= this->transforms
->create_iterator(this->transforms
,FALSE
);
435 while (transforms
->has_next(transforms
))
437 transform_substructure_t
*current_transform
;
438 transform_substructure_t
*current_transform_clone
;
440 transforms
->current(transforms
,(void **) ¤t_transform
);
442 current_transform_clone
= current_transform
->clone(current_transform
);
444 new_clone
->public.add_transform_substructure(&(new_clone
->public),current_transform_clone
);
447 transforms
->destroy(transforms
);
453 * Implements payload_t's and proposal_substructure_t's destroy function.
454 * See #payload_s.destroy or proposal_substructure_s.destroy for description.
456 static status_t
destroy(private_proposal_substructure_t
*this)
458 /* all proposals are getting destroyed */
459 while (this->transforms
->get_count(this->transforms
) > 0)
461 transform_substructure_t
*current_transform
;
462 if (this->transforms
->remove_last(this->transforms
,(void **)¤t_transform
) != SUCCESS
)
466 current_transform
->destroy(current_transform
);
468 this->transforms
->destroy(this->transforms
);
470 if (this->spi
.ptr
!= NULL
)
472 allocator_free(this->spi
.ptr
);
475 allocator_free(this);
481 * Described in header.
483 proposal_substructure_t
*proposal_substructure_create()
485 private_proposal_substructure_t
*this = allocator_alloc_thing(private_proposal_substructure_t
);
487 /* interface functions */
488 this->public.payload_interface
.verify
= (status_t (*) (payload_t
*))verify
;
489 this->public.payload_interface
.get_encoding_rules
= (void (*) (payload_t
*, encoding_rule_t
**, size_t *) ) get_encoding_rules
;
490 this->public.payload_interface
.get_length
= (size_t (*) (payload_t
*)) get_length
;
491 this->public.payload_interface
.get_next_type
= (payload_type_t (*) (payload_t
*)) get_next_type
;
492 this->public.payload_interface
.set_next_type
= (void (*) (payload_t
*,payload_type_t
)) set_next_type
;
493 this->public.payload_interface
.get_type
= (payload_type_t (*) (payload_t
*)) get_type
;
494 this->public.payload_interface
.destroy
= (void (*) (payload_t
*))destroy
;
496 /* public functions */
497 this->public.create_transform_substructure_iterator
= (iterator_t
* (*) (proposal_substructure_t
*,bool)) create_transform_substructure_iterator
;
498 this->public.add_transform_substructure
= (void (*) (proposal_substructure_t
*,transform_substructure_t
*)) add_transform_substructure
;
499 this->public.set_proposal_number
= (void (*) (proposal_substructure_t
*,u_int8_t
))set_proposal_number
;
500 this->public.get_proposal_number
= (u_int8_t (*) (proposal_substructure_t
*)) get_proposal_number
;
501 this->public.set_protocol_id
= (void (*) (proposal_substructure_t
*,u_int8_t
))set_protocol_id
;
502 this->public.get_protocol_id
= (u_int8_t (*) (proposal_substructure_t
*)) get_protocol_id
;
503 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
;
504 this->public.set_is_last_proposal
= (void (*) (proposal_substructure_t
*,bool)) set_is_last_proposal
;
506 this->public.set_spi
= (void (*) (proposal_substructure_t
*,chunk_t
))set_spi
;
507 this->public.get_spi
= (chunk_t (*) (proposal_substructure_t
*)) get_spi
;
508 this->public.get_transform_count
= (size_t (*) (proposal_substructure_t
*)) get_transform_count
;
509 this->public.get_spi_size
= (size_t (*) (proposal_substructure_t
*)) get_spi_size
;
510 this->public.clone
= (proposal_substructure_t
* (*) (proposal_substructure_t
*)) clone
;
511 this->public.destroy
= (void (*) (proposal_substructure_t
*)) destroy
;
514 /* private functions */
515 this->compute_length
= compute_length
;
517 /* set default values of the fields */
518 this->next_payload
= NO_PAYLOAD
;
519 this->proposal_length
= 0;
520 this->proposal_number
= 0;
521 this->protocol_id
= 0;
522 this->transforms_count
= 0;
524 this->spi
.ptr
= NULL
;
527 this->transforms
= linked_list_create();
529 return (&(this->public));