2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "sa_payload.h"
21 #include <encoding/payloads/encodings.h>
22 #include <utils/linked_list.h>
26 typedef struct private_sa_payload_t private_sa_payload_t
;
29 * Private data of an sa_payload_t object.
31 struct private_sa_payload_t
{
34 * Public sa_payload_t interface.
41 u_int8_t next_payload
;
49 * Length of this payload.
51 u_int16_t payload_length
;
54 * Proposals in this payload are stored in a linked_list_t.
56 linked_list_t
* proposals
;
60 * Encoding rules to parse or generate a IKEv2-SA Payload
62 * The defined offsets are the positions in a object of type
63 * private_sa_payload_t.
65 encoding_rule_t sa_payload_encodings
[] = {
66 /* 1 Byte next payload type, stored in the field next_payload */
67 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
68 /* the critical bit */
69 { FLAG
, offsetof(private_sa_payload_t
, critical
) },
70 /* 7 Bit reserved bits, nowhere stored */
78 /* Length of the whole SA payload*/
79 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
80 /* Proposals are stored in a proposal substructure,
81 offset points to a linked_list_t pointer */
82 { PROPOSALS
, offsetof(private_sa_payload_t
, proposals
) },
87 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
88 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89 ! Next Payload !C! RESERVED ! Payload Length !
90 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 METHOD(payload_t
, verify
, status_t
,
98 private_sa_payload_t
*this)
100 int expected_number
= 1, current_number
;
101 status_t status
= SUCCESS
;
102 enumerator_t
*enumerator
;
103 proposal_substructure_t
*substruct
;
106 /* check proposal numbering */
107 enumerator
= this->proposals
->create_enumerator(this->proposals
);
108 while (enumerator
->enumerate(enumerator
, (void**)&substruct
))
110 current_number
= substruct
->get_proposal_number(substruct
);
111 if (current_number
< expected_number
)
113 if (current_number
!= expected_number
+ 1)
115 DBG1(DBG_ENC
, "proposal number is %d, expected %d or %d",
116 current_number
, expected_number
, expected_number
+ 1);
121 else if (current_number
< expected_number
)
123 DBG1(DBG_ENC
, "proposal number smaller than previous");
128 status
= substruct
->payload_interface
.verify(&substruct
->payload_interface
);
129 if (status
!= SUCCESS
)
131 DBG1(DBG_ENC
, "PROPOSAL_SUBSTRUCTURE verification failed");
135 expected_number
= current_number
;
137 enumerator
->destroy(enumerator
);
141 METHOD(payload_t
, get_encoding_rules
, void,
142 private_sa_payload_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
144 *rules
= sa_payload_encodings
;
145 *rule_count
= countof(sa_payload_encodings
);
148 METHOD(payload_t
, get_type
, payload_type_t
,
149 private_sa_payload_t
*this)
151 return SECURITY_ASSOCIATION
;
154 METHOD(payload_t
, get_next_type
, payload_type_t
,
155 private_sa_payload_t
*this)
157 return this->next_payload
;
160 METHOD(payload_t
, set_next_type
, void,
161 private_sa_payload_t
*this,payload_type_t type
)
163 this->next_payload
= type
;
167 * recompute length of the payload.
169 static void compute_length(private_sa_payload_t
*this)
171 enumerator_t
*enumerator
;
173 size_t length
= SA_PAYLOAD_HEADER_LENGTH
;
175 enumerator
= this->proposals
->create_enumerator(this->proposals
);
176 while (enumerator
->enumerate(enumerator
, (void **)¤t
))
178 length
+= current
->get_length(current
);
180 enumerator
->destroy(enumerator
);
182 this->payload_length
= length
;
185 METHOD(payload_t
, get_length
, size_t,
186 private_sa_payload_t
*this)
188 compute_length(this);
189 return this->payload_length
;
192 METHOD(sa_payload_t
, add_proposal
, void,
193 private_sa_payload_t
*this, proposal_t
*proposal
)
195 proposal_substructure_t
*substruct
, *last
;
198 count
= this->proposals
->get_count(this->proposals
);
199 substruct
= proposal_substructure_create_from_proposal(proposal
);
202 this->proposals
->get_last(this->proposals
, (void**)&last
);
203 /* last transform is now not anymore last one */
204 last
->set_is_last_proposal(last
, FALSE
);
206 substruct
->set_is_last_proposal(substruct
, TRUE
);
207 if (proposal
->get_number(proposal
))
208 { /* use the selected proposals number, if any */
209 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
213 substruct
->set_proposal_number(substruct
, count
+ 1);
215 this->proposals
->insert_last(this->proposals
, substruct
);
216 compute_length(this);
219 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
220 private_sa_payload_t
*this)
222 int struct_number
= 0;
223 int ignore_struct_number
= 0;
224 enumerator_t
*enumerator
;
225 proposal_substructure_t
*substruct
;
227 proposal_t
*proposal
;
229 list
= linked_list_create();
230 /* we do not support proposals split up to two proposal substructures, as
231 * AH+ESP bundles are not supported in RFC4301 anymore.
232 * To handle such structures safely, we just skip proposals with multiple
235 enumerator
= this->proposals
->create_enumerator(this->proposals
);
236 while (enumerator
->enumerate(enumerator
, &substruct
))
238 /* check if a proposal has a single protocol */
239 if (substruct
->get_proposal_number(substruct
) == struct_number
)
241 if (ignore_struct_number
< struct_number
)
243 /* remove an already added, if first of series */
244 list
->remove_last(list
, (void**)&proposal
);
245 proposal
->destroy(proposal
);
246 ignore_struct_number
= struct_number
;
251 proposal
= substruct
->get_proposal(substruct
);
254 list
->insert_last(list
, proposal
);
257 enumerator
->destroy(enumerator
);
261 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
262 private_sa_payload_t
*this)
264 this->proposals
->destroy_offset(this->proposals
,
265 offsetof(proposal_substructure_t
, destroy
));
270 * Described in header.
272 sa_payload_t
*sa_payload_create()
274 private_sa_payload_t
*this;
278 .payload_interface
= {
280 .get_encoding_rules
= _get_encoding_rules
,
281 .get_length
= _get_length
,
282 .get_next_type
= _get_next_type
,
283 .set_next_type
= _set_next_type
,
284 .get_type
= _get_type
,
287 .add_proposal
= _add_proposal
,
288 .get_proposals
= _get_proposals
,
291 .next_payload
= NO_PAYLOAD
,
292 .payload_length
= SA_PAYLOAD_HEADER_LENGTH
,
293 .proposals
= linked_list_create(),
295 return &this->public;
299 * Described in header.
301 sa_payload_t
*sa_payload_create_from_proposal_list(linked_list_t
*proposals
)
303 private_sa_payload_t
*this;
304 enumerator_t
*enumerator
;
305 proposal_t
*proposal
;
307 this = (private_sa_payload_t
*)sa_payload_create();
308 enumerator
= proposals
->create_enumerator(proposals
);
309 while (enumerator
->enumerate(enumerator
, &proposal
))
311 add_proposal(this, proposal
);
313 enumerator
->destroy(enumerator
);
315 return &this->public;
319 * Described in header.
321 sa_payload_t
*sa_payload_create_from_proposal(proposal_t
*proposal
)
323 private_sa_payload_t
*this;
325 this = (private_sa_payload_t
*)sa_payload_create();
326 add_proposal(this, proposal
);
328 return &this->public;