]>
Commit | Line | Data |
---|---|---|
da42afc5 | 1 | /** |
113f461e | 2 | * @file sa_payload.c |
da42afc5 | 3 | * |
3fe05870 | 4 | * @brief Implementation of sa_payload_t. |
da42afc5 JH |
5 | * |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2005 Jan Hutter, Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
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>. | |
16 | * | |
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 | |
20 | * for more details. | |
21 | */ | |
5113680f | 22 | |
da42afc5 JH |
23 | #include <stddef.h> |
24 | ||
25 | #include "sa_payload.h" | |
26 | ||
4a962238 | 27 | #include <encoding/payloads/encodings.h> |
696be022 | 28 | #include <utils/linked_list.h> |
da42afc5 JH |
29 | |
30 | ||
95c61cb9 JH |
31 | typedef struct private_sa_payload_t private_sa_payload_t; |
32 | ||
da42afc5 | 33 | /** |
3fe05870 | 34 | * Private data of an sa_payload_t object. |
da42afc5 JH |
35 | * |
36 | */ | |
95c61cb9 | 37 | struct private_sa_payload_t { |
da42afc5 | 38 | /** |
3fe05870 | 39 | * Public sa_payload_t interface. |
da42afc5 JH |
40 | */ |
41 | sa_payload_t public; | |
42 | ||
43 | /** | |
3fe05870 | 44 | * Next payload type. |
da42afc5 JH |
45 | */ |
46 | u_int8_t next_payload; | |
47 | ||
48 | /** | |
3fe05870 | 49 | * Critical flag. |
da42afc5 JH |
50 | */ |
51 | bool critical; | |
52 | ||
53 | /** | |
3fe05870 | 54 | * Length of this payload. |
da42afc5 JH |
55 | */ |
56 | u_int16_t payload_length; | |
57 | ||
58 | /** | |
3fe05870 | 59 | * Proposals in this payload are stored in a linked_list_t. |
da42afc5 JH |
60 | */ |
61 | linked_list_t * proposals; | |
32cbc7bc JH |
62 | |
63 | /** | |
64 | * @brief Computes the length of this payload. | |
65 | * | |
66 | * @param this calling private_sa_payload_t object | |
32cbc7bc | 67 | */ |
3fe05870 | 68 | void (*compute_length) (private_sa_payload_t *this); |
da42afc5 JH |
69 | }; |
70 | ||
71 | /** | |
113f461e | 72 | * Encoding rules to parse or generate a IKEv2-SA Payload |
da42afc5 JH |
73 | * |
74 | * The defined offsets are the positions in a object of type | |
75 | * private_sa_payload_t. | |
76 | * | |
77 | */ | |
78 | encoding_rule_t sa_payload_encodings[] = { | |
79 | /* 1 Byte next payload type, stored in the field next_payload */ | |
80 | { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, | |
81 | /* the critical bit */ | |
82 | { FLAG, offsetof(private_sa_payload_t, critical) }, | |
83 | /* 7 Bit reserved bits, nowhere stored */ | |
84 | { RESERVED_BIT, 0 }, | |
85 | { RESERVED_BIT, 0 }, | |
86 | { RESERVED_BIT, 0 }, | |
87 | { RESERVED_BIT, 0 }, | |
88 | { RESERVED_BIT, 0 }, | |
89 | { RESERVED_BIT, 0 }, | |
90 | { RESERVED_BIT, 0 }, | |
91 | /* Length of the whole SA payload*/ | |
92 | { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, | |
93 | /* Proposals are stored in a proposal substructure, | |
94 | offset points to a linked_list_t pointer */ | |
95 | { PROPOSALS, offsetof(private_sa_payload_t, proposals) } | |
96 | }; | |
97 | ||
e31eb71e JH |
98 | /* |
99 | 1 2 3 | |
100 | 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 | |
101 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
102 | ! Next Payload !C! RESERVED ! Payload Length ! | |
103 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
104 | ! ! | |
105 | ~ <Proposals> ~ | |
106 | ! ! | |
107 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
108 | */ | |
109 | ||
110 | /** | |
3fe05870 | 111 | * Implementation of payload_t.verify. |
e31eb71e JH |
112 | */ |
113 | static status_t verify(private_sa_payload_t *this) | |
114 | { | |
115 | int proposal_number = 1; | |
346af6f3 | 116 | status_t status = SUCCESS; |
bdb141cb | 117 | iterator_t *iterator; |
e31eb71e | 118 | bool first = TRUE; |
e31eb71e JH |
119 | |
120 | /* check proposal numbering */ | |
a0753941 | 121 | iterator = this->proposals->create_iterator(this->proposals,TRUE); |
e31eb71e JH |
122 | |
123 | while(iterator->has_next(iterator)) | |
124 | { | |
125 | proposal_substructure_t *current_proposal; | |
346af6f3 | 126 | iterator->current(iterator,(void **)¤t_proposal); |
e31eb71e JH |
127 | if (current_proposal->get_proposal_number(current_proposal) > proposal_number) |
128 | { | |
129 | if (first) | |
130 | { | |
131 | /* first number must be 1 */ | |
132 | status = FAILED; | |
133 | break; | |
134 | } | |
135 | ||
136 | if (current_proposal->get_proposal_number(current_proposal) != (proposal_number + 1)) | |
137 | { | |
138 | /* must be only one more then previous proposal */ | |
139 | status = FAILED; | |
140 | break; | |
141 | } | |
142 | } | |
143 | else if (current_proposal->get_proposal_number(current_proposal) < proposal_number) | |
144 | { | |
e31eb71e JH |
145 | /* must not be smaller then proceeding one */ |
146 | status = FAILED; | |
147 | break; | |
148 | } | |
346af6f3 JH |
149 | |
150 | status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface)); | |
151 | if (status != SUCCESS) | |
152 | { | |
153 | break; | |
154 | } | |
e31eb71e JH |
155 | first = FALSE; |
156 | } | |
157 | ||
158 | iterator->destroy(iterator); | |
159 | return status; | |
160 | } | |
161 | ||
162 | ||
da42afc5 | 163 | /** |
3fe05870 | 164 | * Implementation of payload_t.destroy and sa_payload_t.destroy. |
da42afc5 JH |
165 | */ |
166 | static status_t destroy(private_sa_payload_t *this) | |
167 | { | |
168 | /* all proposals are getting destroyed */ | |
169 | while (this->proposals->get_count(this->proposals) > 0) | |
170 | { | |
171 | proposal_substructure_t *current_proposal; | |
3fe05870 | 172 | this->proposals->remove_last(this->proposals,(void **)¤t_proposal); |
da42afc5 JH |
173 | current_proposal->destroy(current_proposal); |
174 | } | |
175 | this->proposals->destroy(this->proposals); | |
176 | ||
5113680f | 177 | free(this); |
da42afc5 JH |
178 | |
179 | return SUCCESS; | |
180 | } | |
181 | ||
182 | /** | |
3fe05870 | 183 | * Implementation of payload_t.get_encoding_rules. |
da42afc5 | 184 | */ |
3fe05870 | 185 | static void get_encoding_rules(private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) |
da42afc5 JH |
186 | { |
187 | *rules = sa_payload_encodings; | |
188 | *rule_count = sizeof(sa_payload_encodings) / sizeof(encoding_rule_t); | |
da42afc5 JH |
189 | } |
190 | ||
191 | /** | |
3fe05870 | 192 | * Implementation of payload_t.get_type. |
da42afc5 JH |
193 | */ |
194 | static payload_type_t get_type(private_sa_payload_t *this) | |
195 | { | |
196 | return SECURITY_ASSOCIATION; | |
197 | } | |
198 | ||
199 | /** | |
3fe05870 | 200 | * Implementation of payload_t.get_next_type. |
da42afc5 JH |
201 | */ |
202 | static payload_type_t get_next_type(private_sa_payload_t *this) | |
203 | { | |
204 | return (this->next_payload); | |
205 | } | |
206 | ||
32cbc7bc | 207 | /** |
3fe05870 | 208 | * Implementation of payload_t.set_next_type. |
32cbc7bc | 209 | */ |
3fe05870 | 210 | static void set_next_type(private_sa_payload_t *this,payload_type_t type) |
32cbc7bc JH |
211 | { |
212 | this->next_payload = type; | |
32cbc7bc JH |
213 | } |
214 | ||
da42afc5 | 215 | /** |
3fe05870 | 216 | * Implementation of payload_t.get_length. |
da42afc5 JH |
217 | */ |
218 | static size_t get_length(private_sa_payload_t *this) | |
219 | { | |
32cbc7bc | 220 | this->compute_length(this); |
da42afc5 JH |
221 | return this->payload_length; |
222 | } | |
223 | ||
b860cffd | 224 | /** |
3fe05870 | 225 | * Implementation of sa_payload_t.create_proposal_substructure_iterator. |
b860cffd | 226 | */ |
a0753941 | 227 | static iterator_t *create_proposal_substructure_iterator (private_sa_payload_t *this,bool forward) |
b860cffd | 228 | { |
a0753941 | 229 | return this->proposals->create_iterator(this->proposals,forward); |
b860cffd JH |
230 | } |
231 | ||
232 | /** | |
3fe05870 | 233 | * Implementation of sa_payload_t.add_proposal_substructure. |
b860cffd | 234 | */ |
3fe05870 | 235 | static void add_proposal_substructure (private_sa_payload_t *this,proposal_substructure_t *proposal) |
b860cffd | 236 | { |
b737e9d9 JH |
237 | status_t status; |
238 | if (this->proposals->get_count(this->proposals) > 0) | |
239 | { | |
240 | proposal_substructure_t *last_proposal; | |
241 | status = this->proposals->get_last(this->proposals,(void **) &last_proposal); | |
242 | /* last transform is now not anymore last one */ | |
243 | last_proposal->set_is_last_proposal(last_proposal,FALSE); | |
244 | } | |
245 | proposal->set_is_last_proposal(proposal,TRUE); | |
246 | ||
3fe05870 | 247 | this->proposals->insert_last(this->proposals,(void *) proposal); |
32cbc7bc | 248 | this->compute_length(this); |
32cbc7bc JH |
249 | } |
250 | ||
384efc76 | 251 | /** |
ce461bbd | 252 | * Implementation of sa_payload_t.add_proposal. |
384efc76 | 253 | */ |
ce461bbd | 254 | static void add_proposal(private_sa_payload_t *this, proposal_t *proposal) |
384efc76 MW |
255 | { |
256 | proposal_substructure_t *substructure; | |
c06dbbab MW |
257 | protocol_id_t proto[2]; |
258 | u_int i; | |
384efc76 | 259 | |
c06dbbab MW |
260 | /* build the substructures for every protocol */ |
261 | proposal->get_protocols(proposal, proto); | |
262 | for (i = 0; i<2; i++) | |
384efc76 | 263 | { |
dec59822 | 264 | if (proto[i] != PROTO_NONE) |
c06dbbab | 265 | { |
ce461bbd | 266 | substructure = proposal_substructure_create_from_proposal(proposal, proto[i]); |
c06dbbab MW |
267 | add_proposal_substructure(this, substructure); |
268 | } | |
384efc76 | 269 | } |
384efc76 MW |
270 | } |
271 | ||
b737e9d9 | 272 | /** |
ce461bbd | 273 | * Implementation of sa_payload_t.get_proposals. |
b737e9d9 | 274 | */ |
ce461bbd | 275 | static linked_list_t *get_proposals(private_sa_payload_t *this) |
343acebe | 276 | { |
c06dbbab | 277 | int proposal_struct_number = 0; |
343acebe | 278 | iterator_t *iterator; |
ce461bbd | 279 | proposal_t *proposal; |
c06dbbab | 280 | linked_list_t *proposal_list; |
343acebe | 281 | |
c06dbbab MW |
282 | /* this list will hold our proposals */ |
283 | proposal_list = linked_list_create(); | |
7fa8decb | 284 | |
ce461bbd | 285 | /* iterate over structures, one OR MORE structures will result in a proposal */ |
c06dbbab | 286 | iterator = this->proposals->create_iterator(this->proposals,TRUE); |
343acebe JH |
287 | while (iterator->has_next(iterator)) |
288 | { | |
c06dbbab MW |
289 | proposal_substructure_t *proposal_struct; |
290 | iterator->current(iterator,(void **)&(proposal_struct)); | |
343acebe | 291 | |
c06dbbab | 292 | if (proposal_struct->get_proposal_number(proposal_struct) > proposal_struct_number) |
343acebe | 293 | { |
c06dbbab MW |
294 | /* here starts a new proposal, create a new one and add it to the list */ |
295 | proposal_struct_number = proposal_struct->get_proposal_number(proposal_struct); | |
ce461bbd | 296 | proposal = proposal_create(proposal_struct_number); |
c06dbbab | 297 | proposal_list->insert_last(proposal_list, proposal); |
343acebe | 298 | } |
c06dbbab | 299 | /* proposal_substructure_t does the dirty work and builds up the proposal */ |
ce461bbd | 300 | proposal_struct->add_to_proposal(proposal_struct, proposal); |
343acebe | 301 | } |
c06dbbab MW |
302 | iterator->destroy(iterator); |
303 | return proposal_list; | |
343acebe JH |
304 | } |
305 | ||
32cbc7bc | 306 | /** |
3fe05870 | 307 | * Implementation of private_sa_payload_t.compute_length. |
32cbc7bc | 308 | */ |
3fe05870 | 309 | static void compute_length (private_sa_payload_t *this) |
32cbc7bc | 310 | { |
bdb141cb | 311 | iterator_t *iterator; |
32cbc7bc | 312 | size_t length = SA_PAYLOAD_HEADER_LENGTH; |
a0753941 | 313 | iterator = this->proposals->create_iterator(this->proposals,TRUE); |
32cbc7bc JH |
314 | while (iterator->has_next(iterator)) |
315 | { | |
316 | payload_t *current_proposal; | |
317 | iterator->current(iterator,(void **) ¤t_proposal); | |
318 | length += current_proposal->get_length(current_proposal); | |
319 | } | |
320 | iterator->destroy(iterator); | |
321 | ||
322 | this->payload_length = length; | |
b860cffd JH |
323 | } |
324 | ||
da42afc5 | 325 | /* |
3fe05870 | 326 | * Described in header. |
da42afc5 JH |
327 | */ |
328 | sa_payload_t *sa_payload_create() | |
329 | { | |
5113680f | 330 | private_sa_payload_t *this = malloc_thing(private_sa_payload_t); |
da42afc5 | 331 | |
e31eb71e JH |
332 | /* public interface */ |
333 | this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; | |
3fe05870 | 334 | this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; |
da42afc5 JH |
335 | this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; |
336 | this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; | |
3fe05870 | 337 | this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; |
da42afc5 | 338 | this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; |
3fe05870 | 339 | this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; |
e31eb71e JH |
340 | |
341 | /* public functions */ | |
a0753941 | 342 | this->public.create_proposal_substructure_iterator = (iterator_t* (*) (sa_payload_t *,bool)) create_proposal_substructure_iterator; |
3fe05870 | 343 | this->public.add_proposal_substructure = (void (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure; |
ce461bbd | 344 | this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals; |
3fe05870 | 345 | this->public.destroy = (void (*) (sa_payload_t *)) destroy; |
da42afc5 | 346 | |
32cbc7bc JH |
347 | /* private functions */ |
348 | this->compute_length = compute_length; | |
349 | ||
da42afc5 | 350 | /* set default values of the fields */ |
dec59822 | 351 | this->critical = FALSE; |
da42afc5 JH |
352 | this->next_payload = NO_PAYLOAD; |
353 | this->payload_length = SA_PAYLOAD_HEADER_LENGTH; | |
354 | ||
355 | this->proposals = linked_list_create(); | |
da42afc5 JH |
356 | return (&(this->public)); |
357 | } | |
358 | ||
b737e9d9 JH |
359 | /* |
360 | * Described in header. | |
361 | */ | |
ce461bbd | 362 | sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) |
c06dbbab MW |
363 | { |
364 | iterator_t *iterator; | |
ce461bbd | 365 | proposal_t *proposal; |
c06dbbab | 366 | sa_payload_t *sa_payload = sa_payload_create(); |
343acebe | 367 | |
c06dbbab MW |
368 | /* add every payload from the list */ |
369 | iterator = proposals->create_iterator(proposals, TRUE); | |
370 | while (iterator->has_next(iterator)) | |
343acebe | 371 | { |
c06dbbab | 372 | iterator->current(iterator, (void**)&proposal); |
ce461bbd | 373 | add_proposal((private_sa_payload_t*)sa_payload, proposal); |
343acebe | 374 | } |
dfa6e086 | 375 | iterator->destroy(iterator); |
343acebe JH |
376 | |
377 | return sa_payload; | |
378 | } | |
93df94ac MW |
379 | |
380 | /* | |
381 | * Described in header. | |
382 | */ | |
ce461bbd | 383 | sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) |
93df94ac MW |
384 | { |
385 | sa_payload_t *sa_payload = sa_payload_create(); | |
386 | ||
ce461bbd | 387 | add_proposal((private_sa_payload_t*)sa_payload, proposal); |
93df94ac MW |
388 | |
389 | return sa_payload; | |
390 | } |