Moved data structures to new collections subfolder
[strongswan.git] / src / libcharon / encoding / payloads / transform_substructure.c
1 /*
2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stddef.h>
19
20 #include "transform_substructure.h"
21
22 #include <encoding/payloads/transform_attribute.h>
23 #include <encoding/payloads/encodings.h>
24 #include <library.h>
25 #include <collections/linked_list.h>
26 #include <daemon.h>
27
28 typedef struct private_transform_substructure_t private_transform_substructure_t;
29
30 /**
31 * Private data of an transform_substructure_t object.
32 */
33 struct private_transform_substructure_t {
34
35 /**
36 * Public transform_substructure_t interface.
37 */
38 transform_substructure_t public;
39
40 /**
41 * Next payload type.
42 */
43 u_int8_t next_payload;
44
45 /**
46 * Reserved byte
47 */
48 u_int8_t reserved[3];
49
50 /**
51 * Length of this payload.
52 */
53 u_int16_t transform_length;
54
55 /**
56 * Type or number, Type of the transform in IKEv2, number in IKEv2.
57 */
58 u_int8_t transform_ton;
59
60 /**
61 * Transform ID, as encoded in IKEv1.
62 */
63 u_int8_t transform_id_v1;
64
65 /**
66 * Transform ID, as encoded in IKEv2.
67 */
68 u_int16_t transform_id_v2;
69
70 /**
71 * Transforms Attributes are stored in a linked_list_t.
72 */
73 linked_list_t *attributes;
74
75 /**
76 * Payload type, TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1
77 */
78 payload_type_t type;
79 };
80
81 /**
82 * Encoding rules for TRANSFORM_SUBSTRUCTURE
83 */
84 static encoding_rule_t encodings_v2[] = {
85 /* 1 Byte next payload type, stored in the field next_payload */
86 { U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
87 /* 1 Reserved Byte */
88 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) },
89 /* Length of the whole transform substructure*/
90 { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)},
91 /* transform type */
92 { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) },
93 /* transform identifier, as used by IKEv1 */
94 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) },
95 /* transform identifier, as used by IKEv2 */
96 { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) },
97 /* Attributes in a transform attribute list */
98 { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE,
99 offsetof(private_transform_substructure_t, attributes) }
100 };
101
102 /**
103 * Encoding rules for TRANSFORM_SUBSTRUCTURE_V1
104 */
105 static encoding_rule_t encodings_v1[] = {
106 /* 1 Byte next payload type, stored in the field next_payload */
107 { U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
108 /* 1 Reserved Byte */
109 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) },
110 /* Length of the whole transform substructure*/
111 { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)},
112 /* transform number */
113 { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)},
114 /* transform identifier, as used by IKEv1 */
115 { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) },
116 /* transform identifier, as used by IKEv2 */
117 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) },
118 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) },
119 /* Attributes in a transform attribute list */
120 { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1,
121 offsetof(private_transform_substructure_t, attributes) }
122 };
123
124 /*
125 1 2 3
126 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
127 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128 ! 0 (last) or 3 ! RESERVED ! Transform Length !
129 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130 ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 !
131 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132 ! !
133 ~ Transform Attributes ~
134 ! !
135 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136 */
137
138 METHOD(payload_t, verify, status_t,
139 private_transform_substructure_t *this)
140 {
141 status_t status = SUCCESS;
142 enumerator_t *enumerator;
143 payload_t *attribute;
144
145 if (this->next_payload != NO_PAYLOAD && this->next_payload != 3)
146 {
147 DBG1(DBG_ENC, "inconsistent next payload");
148 return FAILED;
149 }
150
151 enumerator = this->attributes->create_enumerator(this->attributes);
152 while (enumerator->enumerate(enumerator, &attribute))
153 {
154 status = attribute->verify(attribute);
155 if (status != SUCCESS)
156 {
157 DBG1(DBG_ENC, "TRANSFORM_ATTRIBUTE verification failed");
158 break;
159 }
160 }
161 enumerator->destroy(enumerator);
162
163 /* proposal number is checked in SA payload */
164 return status;
165 }
166
167 METHOD(payload_t, get_encoding_rules, int,
168 private_transform_substructure_t *this, encoding_rule_t **rules)
169 {
170 if (this->type == TRANSFORM_SUBSTRUCTURE)
171 {
172 *rules = encodings_v2;
173 return countof(encodings_v2);
174 }
175 *rules = encodings_v1;
176 return countof(encodings_v1);
177 }
178
179 METHOD(payload_t, get_header_length, int,
180 private_transform_substructure_t *this)
181 {
182 return 8;
183 }
184
185 METHOD(payload_t, get_type, payload_type_t,
186 private_transform_substructure_t *this)
187 {
188 return this->type;
189 }
190
191 METHOD(payload_t, get_next_type, payload_type_t,
192 private_transform_substructure_t *this)
193 {
194 return this->next_payload;
195 }
196
197 /**
198 * recompute the length of the payload.
199 */
200 static void compute_length(private_transform_substructure_t *this)
201 {
202 enumerator_t *enumerator;
203 payload_t *attribute;
204
205 this->transform_length = get_header_length(this);
206 enumerator = this->attributes->create_enumerator(this->attributes);
207 while (enumerator->enumerate(enumerator, &attribute))
208 {
209 this->transform_length += attribute->get_length(attribute);
210 }
211 enumerator->destroy(enumerator);
212 }
213
214 METHOD(payload_t, get_length, size_t,
215 private_transform_substructure_t *this)
216 {
217 return this->transform_length;
218 }
219
220 METHOD(transform_substructure_t, add_transform_attribute, void,
221 private_transform_substructure_t *this, transform_attribute_t *attribute)
222 {
223 this->attributes->insert_last(this->attributes, attribute);
224 compute_length(this);
225 }
226
227 METHOD(transform_substructure_t, set_is_last_transform, void,
228 private_transform_substructure_t *this, bool is_last)
229 {
230 this->next_payload = is_last ? 0: TRANSFORM_TYPE_VALUE;
231 }
232
233 METHOD(payload_t, set_next_type, void,
234 private_transform_substructure_t *this,payload_type_t type)
235 {
236 }
237
238 METHOD(transform_substructure_t, get_transform_type_or_number, u_int8_t,
239 private_transform_substructure_t *this)
240 {
241 return this->transform_ton;
242 }
243
244 METHOD(transform_substructure_t, get_transform_id, u_int16_t,
245 private_transform_substructure_t *this)
246 {
247 if (this->type == TRANSFORM_SUBSTRUCTURE)
248 {
249 return this->transform_id_v2;
250 }
251 return this->transform_id_v1;
252 }
253
254 METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*,
255 private_transform_substructure_t *this)
256 {
257 return this->attributes->create_enumerator(this->attributes);
258 }
259
260 METHOD2(payload_t, transform_substructure_t, destroy, void,
261 private_transform_substructure_t *this)
262 {
263 this->attributes->destroy_offset(this->attributes,
264 offsetof(payload_t, destroy));
265 free(this);
266 }
267
268 /*
269 * Described in header.
270 */
271 transform_substructure_t *transform_substructure_create(payload_type_t type)
272 {
273 private_transform_substructure_t *this;
274
275 INIT(this,
276 .public = {
277 .payload_interface = {
278 .verify = _verify,
279 .get_encoding_rules = _get_encoding_rules,
280 .get_header_length = _get_header_length,
281 .get_length = _get_length,
282 .get_next_type = _get_next_type,
283 .set_next_type = _set_next_type,
284 .get_type = _get_type,
285 .destroy = _destroy,
286 },
287 .add_transform_attribute = _add_transform_attribute,
288 .set_is_last_transform = _set_is_last_transform,
289 .get_transform_type_or_number = _get_transform_type_or_number,
290 .get_transform_id = _get_transform_id,
291 .create_attribute_enumerator = _create_attribute_enumerator,
292 .destroy = _destroy,
293 },
294 .next_payload = NO_PAYLOAD,
295 .transform_length = get_header_length(this),
296 .attributes = linked_list_create(),
297 .type = type,
298 );
299 return &this->public;
300 }
301
302 /*
303 * Described in header
304 */
305 transform_substructure_t *transform_substructure_create_type(payload_type_t type,
306 u_int8_t type_or_number, u_int16_t id)
307 {
308 private_transform_substructure_t *this;
309
310 this = (private_transform_substructure_t*)transform_substructure_create(type);
311
312 this->transform_ton = type_or_number;
313 if (type == TRANSFORM_SUBSTRUCTURE)
314 {
315 this->transform_id_v2 = id;
316 }
317 else
318 {
319 this->transform_id_v1 = id;
320 }
321 return &this->public;
322 }
323