Update delete_payload length when adding SPIs
[strongswan.git] / src / libcharon / encoding / payloads / delete_payload.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 "delete_payload.h"
21
22
23 typedef struct private_delete_payload_t private_delete_payload_t;
24
25 /**
26 * Private data of an delete_payload_t object.
27 *
28 */
29 struct private_delete_payload_t {
30 /**
31 * Public delete_payload_t interface.
32 */
33 delete_payload_t public;
34
35 /**
36 * Next payload type.
37 */
38 u_int8_t next_payload;
39
40 /**
41 * Critical flag.
42 */
43 bool critical;
44
45 /**
46 * Length of this payload.
47 */
48 u_int16_t payload_length;
49
50 /**
51 * Protocol ID.
52 */
53 u_int8_t protocol_id;
54
55 /**
56 * SPI Size.
57 */
58 u_int8_t spi_size;
59
60 /**
61 * Number of SPI's.
62 */
63 u_int16_t spi_count;
64
65 /**
66 * The contained SPI's.
67 */
68 chunk_t spis;
69 };
70
71 /**
72 * Encoding rules to parse or generate a DELETE payload
73 *
74 * The defined offsets are the positions in a object of type
75 * private_delete_payload_t.
76 */
77 encoding_rule_t delete_payload_encodings[] = {
78 /* 1 Byte next payload type, stored in the field next_payload */
79 { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
80 /* the critical bit */
81 { FLAG, offsetof(private_delete_payload_t, critical) },
82 /* 7 Bit reserved bits, nowhere stored */
83 { RESERVED_BIT, 0 },
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 /* Length of the whole payload*/
91 { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) },
92 { U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
93 { U_INT_8, offsetof(private_delete_payload_t, spi_size) },
94 { U_INT_16, offsetof(private_delete_payload_t, spi_count) },
95 /* some delete data bytes, length is defined in PAYLOAD_LENGTH */
96 { SPIS, offsetof(private_delete_payload_t, spis) }
97 };
98
99 /*
100 1 2 3
101 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
102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 ! Next Payload !C! RESERVED ! Payload Length !
104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 ! Protocol ID ! SPI Size ! # of SPIs !
106 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 ! !
108 ~ Security Parameter Index(es) (SPI) ~
109 ! !
110 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 */
112
113 METHOD(payload_t, verify, status_t,
114 private_delete_payload_t *this)
115 {
116 switch (this->protocol_id)
117 {
118 case PROTO_AH:
119 case PROTO_ESP:
120 if (this->spi_size != 4)
121 {
122 return FAILED;
123 }
124 break;
125 case PROTO_IKE:
126 case 0:
127 /* IKE deletion has no spi assigned! */
128 if (this->spi_size != 0)
129 {
130 return FAILED;
131 }
132 break;
133 default:
134 return FAILED;
135 }
136 if (this->spis.len != (this->spi_count * this->spi_size))
137 {
138 return FAILED;
139 }
140 return SUCCESS;
141 }
142
143 METHOD(payload_t, get_encoding_rules, void,
144 private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
145 {
146 *rules = delete_payload_encodings;
147 *rule_count = countof(delete_payload_encodings);
148 }
149
150 METHOD(payload_t, get_payload_type, payload_type_t,
151 private_delete_payload_t *this)
152 {
153 return DELETE;
154 }
155
156 METHOD(payload_t, get_next_type, payload_type_t,
157 private_delete_payload_t *this)
158 {
159 return this->next_payload;
160 }
161
162 METHOD(payload_t, set_next_type, void,
163 private_delete_payload_t *this,payload_type_t type)
164 {
165 this->next_payload = type;
166 }
167
168 METHOD(payload_t, get_length, size_t,
169 private_delete_payload_t *this)
170 {
171 return this->payload_length;
172 }
173
174 METHOD(delete_payload_t, get_protocol_id, protocol_id_t,
175 private_delete_payload_t *this)
176 {
177 return this->protocol_id;
178 }
179
180 METHOD(delete_payload_t, add_spi, void,
181 private_delete_payload_t *this, u_int32_t spi)
182 {
183 switch (this->protocol_id)
184 {
185 case PROTO_AH:
186 case PROTO_ESP:
187 this->spi_count++;
188 this->payload_length += sizeof(spi);
189 this->spis = chunk_cat("mc", this->spis, chunk_from_thing(spi));
190 break;
191 default:
192 break;
193 }
194 }
195
196 /**
197 * SPI enumerator implementation
198 */
199 typedef struct {
200 /** implements enumerator_t */
201 enumerator_t public;
202 /** remaining SPIs */
203 chunk_t spis;
204 } spi_enumerator_t;
205
206 METHOD(enumerator_t, spis_enumerate, bool,
207 spi_enumerator_t *this, u_int32_t *spi)
208 {
209 if (this->spis.len >= sizeof(*spi))
210 {
211 memcpy(spi, this->spis.ptr, sizeof(*spi));
212 this->spis = chunk_skip(this->spis, sizeof(*spi));
213 return TRUE;
214 }
215 return FALSE;
216 }
217
218 METHOD(delete_payload_t, create_spi_enumerator, enumerator_t*,
219 private_delete_payload_t *this)
220 {
221 spi_enumerator_t *e;
222
223 if (this->spi_size != sizeof(u_int32_t))
224 {
225 return enumerator_create_empty();
226 }
227 INIT(e,
228 .public = {
229 .enumerate = (void*)_spis_enumerate,
230 .destroy = (void*)free,
231 },
232 .spis = this->spis,
233 );
234 return &e->public;
235 }
236
237 METHOD2(payload_t, delete_payload_t, destroy, void,
238 private_delete_payload_t *this)
239 {
240 free(this->spis.ptr);
241 free(this);
242 }
243
244 /*
245 * Described in header
246 */
247 delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
248 {
249 private_delete_payload_t *this;
250
251 INIT(this,
252 .public = {
253 .payload_interface = {
254 .verify = _verify,
255 .get_encoding_rules = _get_encoding_rules,
256 .get_length = _get_length,
257 .get_next_type = _get_next_type,
258 .set_next_type = _set_next_type,
259 .get_type = _get_payload_type,
260 .destroy = _destroy,
261 },
262 .get_protocol_id = _get_protocol_id,
263 .add_spi = _add_spi,
264 .create_spi_enumerator = _create_spi_enumerator,
265 .destroy = _destroy,
266 },
267 .next_payload = NO_PAYLOAD,
268 .payload_length = DELETE_PAYLOAD_HEADER_LENGTH,
269 .protocol_id = protocol_id,
270 .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0,
271 );
272 return &this->public;
273 }