4 * @brief Implementation of sa_payload_t.
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 #include "sa_payload.h"
28 #include <encoding/payloads/encodings.h>
29 #include <utils/linked_list.h>
33 typedef struct private_sa_payload_t private_sa_payload_t
;
36 * Private data of an sa_payload_t object.
39 struct private_sa_payload_t
{
41 * Public sa_payload_t interface.
48 u_int8_t next_payload
;
56 * Length of this payload.
58 u_int16_t payload_length
;
61 * Proposals in this payload are stored in a linked_list_t.
63 linked_list_t
* proposals
;
67 * Encoding rules to parse or generate a IKEv2-SA Payload
69 * The defined offsets are the positions in a object of type
70 * private_sa_payload_t.
73 encoding_rule_t sa_payload_encodings
[] = {
74 /* 1 Byte next payload type, stored in the field next_payload */
75 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
76 /* the critical bit */
77 { FLAG
, offsetof(private_sa_payload_t
, critical
) },
78 /* 7 Bit reserved bits, nowhere stored */
86 /* Length of the whole SA payload*/
87 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
88 /* Proposals are stored in a proposal substructure,
89 offset points to a linked_list_t pointer */
90 { PROPOSALS
, offsetof(private_sa_payload_t
, proposals
) }
95 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
96 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 ! Next Payload !C! RESERVED ! Payload Length !
98 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 * Implementation of payload_t.verify.
108 static status_t
verify(private_sa_payload_t
*this)
110 int expected_number
= 1, current_number
;
111 status_t status
= SUCCESS
;
112 iterator_t
*iterator
;
113 proposal_substructure_t
*current_proposal
;
116 /* check proposal numbering */
117 iterator
= this->proposals
->create_iterator(this->proposals
,TRUE
);
119 while(iterator
->iterate(iterator
, (void**)¤t_proposal
))
121 current_number
= current_proposal
->get_proposal_number(current_proposal
);
122 if (current_number
< expected_number
)
124 if (current_number
!= (expected_number
+ 1))
126 DBG1(DBG_ENC
, "proposal number is %d, excepted %d or %d",
127 current_number
, expected_number
, expected_number
+ 1);
132 else if (current_number
< expected_number
)
134 /* must not be smaller then proceeding one */
135 DBG1(DBG_ENC
, "proposal number smaller than that of previous proposal");
140 status
= current_proposal
->payload_interface
.verify(&(current_proposal
->payload_interface
));
141 if (status
!= SUCCESS
)
143 DBG1(DBG_ENC
, "PROPOSAL_SUBSTRUCTURE verification failed");
147 expected_number
= current_number
;
150 iterator
->destroy(iterator
);
156 * Implementation of payload_t.destroy and sa_payload_t.destroy.
158 static status_t
destroy(private_sa_payload_t
*this)
160 this->proposals
->destroy_offset(this->proposals
,
161 offsetof(proposal_substructure_t
, destroy
));
167 * Implementation of payload_t.get_encoding_rules.
169 static void get_encoding_rules(private_sa_payload_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
171 *rules
= sa_payload_encodings
;
172 *rule_count
= sizeof(sa_payload_encodings
) / sizeof(encoding_rule_t
);
176 * Implementation of payload_t.get_type.
178 static payload_type_t
get_type(private_sa_payload_t
*this)
180 return SECURITY_ASSOCIATION
;
184 * Implementation of payload_t.get_next_type.
186 static payload_type_t
get_next_type(private_sa_payload_t
*this)
188 return (this->next_payload
);
192 * Implementation of payload_t.set_next_type.
194 static void set_next_type(private_sa_payload_t
*this,payload_type_t type
)
196 this->next_payload
= type
;
200 * recompute length of the payload.
202 static void compute_length (private_sa_payload_t
*this)
204 iterator_t
*iterator
;
205 payload_t
*current_proposal
;
206 size_t length
= SA_PAYLOAD_HEADER_LENGTH
;
208 iterator
= this->proposals
->create_iterator(this->proposals
,TRUE
);
209 while (iterator
->iterate(iterator
, (void **)¤t_proposal
))
211 length
+= current_proposal
->get_length(current_proposal
);
213 iterator
->destroy(iterator
);
215 this->payload_length
= length
;
219 * Implementation of payload_t.get_length.
221 static size_t get_length(private_sa_payload_t
*this)
223 compute_length(this);
224 return this->payload_length
;
228 * Implementation of sa_payload_t.create_proposal_substructure_iterator.
230 static iterator_t
*create_proposal_substructure_iterator (private_sa_payload_t
*this,bool forward
)
232 return this->proposals
->create_iterator(this->proposals
,forward
);
236 * Implementation of sa_payload_t.add_proposal_substructure.
238 static void add_proposal_substructure(private_sa_payload_t
*this,proposal_substructure_t
*proposal
)
241 u_int proposal_count
= this->proposals
->get_count(this->proposals
);
243 if (proposal_count
> 0)
245 proposal_substructure_t
*last_proposal
;
246 status
= this->proposals
->get_last(this->proposals
,(void **) &last_proposal
);
247 /* last transform is now not anymore last one */
248 last_proposal
->set_is_last_proposal(last_proposal
, FALSE
);
250 proposal
->set_is_last_proposal(proposal
, TRUE
);
251 proposal
->set_proposal_number(proposal
, proposal_count
+ 1);
252 this->proposals
->insert_last(this->proposals
,(void *) proposal
);
253 compute_length(this);
257 * Implementation of sa_payload_t.add_proposal.
259 static void add_proposal(private_sa_payload_t
*this, proposal_t
*proposal
)
261 proposal_substructure_t
*substructure
;
263 substructure
= proposal_substructure_create_from_proposal(proposal
);
264 add_proposal_substructure(this, substructure
);
268 * Implementation of sa_payload_t.get_proposals.
270 static linked_list_t
*get_proposals(private_sa_payload_t
*this)
272 int struct_number
= 0;
273 int ignore_struct_number
= 0;
274 iterator_t
*iterator
;
275 proposal_substructure_t
*proposal_struct
;
276 linked_list_t
*proposal_list
;
278 /* this list will hold our proposals */
279 proposal_list
= linked_list_create();
281 /* we do not support proposals split up to two proposal substructures, as
282 * AH+ESP bundles are not supported in RFC4301 anymore.
283 * To handle such structures safely, we just skip proposals with multiple
286 iterator
= this->proposals
->create_iterator(this->proposals
, TRUE
);
287 while (iterator
->iterate(iterator
, (void **)&proposal_struct
))
289 proposal_t
*proposal
;
291 /* check if a proposal has a single protocol */
292 if (proposal_struct
->get_proposal_number(proposal_struct
) == struct_number
)
294 if (ignore_struct_number
< struct_number
)
296 /* remova an already added, if first of series */
297 proposal_list
->remove_last(proposal_list
, (void**)&proposal
);
298 proposal
->destroy(proposal
);
299 ignore_struct_number
= struct_number
;
304 proposal
= proposal_struct
->get_proposal(proposal_struct
);
307 proposal_list
->insert_last(proposal_list
, proposal
);
310 iterator
->destroy(iterator
);
311 return proposal_list
;
315 * Described in header.
317 sa_payload_t
*sa_payload_create()
319 private_sa_payload_t
*this = malloc_thing(private_sa_payload_t
);
321 /* public interface */
322 this->public.payload_interface
.verify
= (status_t (*) (payload_t
*))verify
;
323 this->public.payload_interface
.get_encoding_rules
= (void (*) (payload_t
*, encoding_rule_t
**, size_t *) ) get_encoding_rules
;
324 this->public.payload_interface
.get_length
= (size_t (*) (payload_t
*)) get_length
;
325 this->public.payload_interface
.get_next_type
= (payload_type_t (*) (payload_t
*)) get_next_type
;
326 this->public.payload_interface
.set_next_type
= (void (*) (payload_t
*,payload_type_t
)) set_next_type
;
327 this->public.payload_interface
.get_type
= (payload_type_t (*) (payload_t
*)) get_type
;
328 this->public.payload_interface
.destroy
= (void (*) (payload_t
*))destroy
;
330 /* public functions */
331 this->public.create_proposal_substructure_iterator
= (iterator_t
* (*) (sa_payload_t
*,bool)) create_proposal_substructure_iterator
;
332 this->public.add_proposal_substructure
= (void (*) (sa_payload_t
*,proposal_substructure_t
*)) add_proposal_substructure
;
333 this->public.add_proposal
= (void (*) (sa_payload_t
*,proposal_t
*))add_proposal
;
334 this->public.get_proposals
= (linked_list_t
* (*) (sa_payload_t
*)) get_proposals
;
335 this->public.destroy
= (void (*) (sa_payload_t
*)) destroy
;
337 /* set default values of the fields */
338 this->critical
= FALSE
;
339 this->next_payload
= NO_PAYLOAD
;
340 this->payload_length
= SA_PAYLOAD_HEADER_LENGTH
;
341 this->proposals
= linked_list_create();
342 return &this->public;
346 * Described in header.
348 sa_payload_t
*sa_payload_create_from_proposal_list(linked_list_t
*proposals
)
350 iterator_t
*iterator
;
351 proposal_t
*proposal
;
352 sa_payload_t
*sa_payload
= sa_payload_create();
354 /* add every payload from the list */
355 iterator
= proposals
->create_iterator(proposals
, TRUE
);
356 while (iterator
->iterate(iterator
, (void**)&proposal
))
358 add_proposal((private_sa_payload_t
*)sa_payload
, proposal
);
360 iterator
->destroy(iterator
);
366 * Described in header.
368 sa_payload_t
*sa_payload_create_from_proposal(proposal_t
*proposal
)
370 sa_payload_t
*sa_payload
= sa_payload_create();
372 add_proposal((private_sa_payload_t
*)sa_payload
, proposal
);