Added add_segment() method to IETF attributes
[strongswan.git] / src / libimcv / ietf / ietf_attr_attr_request.c
1 /*
2 * Copyright (C) 2012-2014 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "imcv.h"
17 #include "ietf_attr_attr_request.h"
18
19 #include <pa_tnc/pa_tnc_msg.h>
20 #include <bio/bio_writer.h>
21 #include <bio/bio_reader.h>
22 #include <collections/linked_list.h>
23
24 #include <utils/debug.h>
25
26 typedef struct private_ietf_attr_attr_request_t private_ietf_attr_attr_request_t;
27
28 /**
29 * PA-TNC Attribute Request type (see section 4.2.1 of RFC 5792)
30 *
31 * 1 2 3
32 * 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
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * | Reserved | PA-TNC Attribute Vendor ID |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | PA-TNC Attribute Type |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * | Reserved | PA-TNC Attribute Vendor ID |
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | PA-TNC Attribute Type |
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 */
43
44 #define ATTR_REQUEST_ENTRY_SIZE 8
45
46 /**
47 * Private data of an ietf_attr_attr_request_t object.
48 */
49 struct private_ietf_attr_attr_request_t {
50
51 /**
52 * Public members of ietf_attr_attr_request_t
53 */
54 ietf_attr_attr_request_t public;
55
56 /**
57 * Vendor-specific attribute type
58 */
59 pen_type_t type;
60
61 /**
62 * Length of attribute value
63 */
64 size_t length;
65
66 /**
67 * Attribute value or segment
68 */
69 chunk_t value;
70
71 /**
72 * Noskip flag
73 */
74 bool noskip_flag;
75
76 /**
77 * List of requested attribute types
78 */
79 linked_list_t *list;
80
81 /**
82 * Reference count
83 */
84 refcount_t ref;
85 };
86
87 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
88 private_ietf_attr_attr_request_t *this)
89 {
90 return this->type;
91 }
92
93 METHOD(pa_tnc_attr_t, get_value, chunk_t,
94 private_ietf_attr_attr_request_t *this)
95 {
96 return this->value;
97 }
98
99 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
100 private_ietf_attr_attr_request_t *this)
101 {
102 return this->noskip_flag;
103 }
104
105 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
106 private_ietf_attr_attr_request_t *this, bool noskip)
107 {
108 this->noskip_flag = noskip;
109 }
110
111 METHOD(pa_tnc_attr_t, build, void,
112 private_ietf_attr_attr_request_t *this)
113 {
114 bio_writer_t *writer;
115 enumerator_t *enumerator;
116 pen_type_t *entry;
117
118 if (this->value.ptr)
119 {
120 return;
121 }
122 writer = bio_writer_create(ATTR_REQUEST_ENTRY_SIZE *
123 this->list->get_count(this->list));
124
125 enumerator = this->list->create_enumerator(this->list);
126 while (enumerator->enumerate(enumerator, &entry))
127 {
128 writer->write_uint32(writer, entry->vendor_id);
129 writer->write_uint32(writer, entry->type);
130 }
131 enumerator->destroy(enumerator);
132
133 this->value = writer->extract_buf(writer);
134 this->length = this->value.len;
135 writer->destroy(writer);
136 }
137
138 METHOD(ietf_attr_attr_request_t, add, void,
139 private_ietf_attr_attr_request_t *this, pen_t vendor_id, u_int32_t type)
140 {
141 pen_type_t *entry;
142
143 entry = malloc_thing(pen_type_t);
144 entry->vendor_id = vendor_id;
145 entry->type = type;
146 this->list->insert_last(this->list, entry);
147 }
148
149 METHOD(pa_tnc_attr_t, process, status_t,
150 private_ietf_attr_attr_request_t *this, u_int32_t *offset)
151 {
152 bio_reader_t *reader;
153 enum_name_t *pa_attr_names;
154 pen_t vendor_id;
155 u_int32_t type;
156 u_int8_t reserved;
157 int count;
158
159 *offset = 0;
160
161 if (this->value.len < this->length)
162 {
163 return NEED_MORE;
164 }
165
166 count = this->value.len / ATTR_REQUEST_ENTRY_SIZE;
167 if (this->value.len != ATTR_REQUEST_ENTRY_SIZE * count)
168 {
169 DBG1(DBG_TNC, "incorrect attribute length for IETF attribute request");
170 return FAILED;
171 }
172
173 reader = bio_reader_create(this->value);
174 while (count--)
175 {
176 reader->read_uint8 (reader, &reserved);
177 reader->read_uint24(reader, &vendor_id);
178 reader->read_uint32(reader, &type);
179
180 pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
181 vendor_id);
182 if (pa_attr_names)
183 {
184 DBG2(DBG_TNC, " 0x%06x/0x%08x '%N/%N'", vendor_id, type,
185 pen_names, vendor_id, pa_attr_names, type);
186 }
187 else
188 {
189 DBG2(DBG_TNC, " 0x%06x/0x%08x '%N'", vendor_id, type,
190 pen_names, vendor_id);
191 }
192 add(this, vendor_id, type);
193 }
194 reader->destroy(reader);
195
196 return SUCCESS;
197 }
198
199 METHOD(pa_tnc_attr_t, add_segment, void,
200 private_ietf_attr_attr_request_t *this, chunk_t segment)
201 {
202 this->value = chunk_cat("mc", this->value, segment);
203 }
204
205 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
206 private_ietf_attr_attr_request_t *this)
207 {
208 ref_get(&this->ref);
209 return &this->public.pa_tnc_attribute;
210 }
211
212 METHOD(pa_tnc_attr_t, destroy, void,
213 private_ietf_attr_attr_request_t *this)
214 {
215 if (ref_put(&this->ref))
216 {
217 this->list->destroy_function(this->list, free);
218 free(this->value.ptr);
219 free(this);
220 }
221 }
222
223 METHOD(ietf_attr_attr_request_t, create_enumerator, enumerator_t*,
224 private_ietf_attr_attr_request_t *this)
225 {
226 return this->list->create_enumerator(this->list);
227 }
228
229 /**
230 * Described in header.
231 */
232 pa_tnc_attr_t *ietf_attr_attr_request_create(pen_t vendor_id, u_int32_t type)
233 {
234 private_ietf_attr_attr_request_t *this;
235
236 INIT(this,
237 .public = {
238 .pa_tnc_attribute = {
239 .get_type = _get_type,
240 .get_value = _get_value,
241 .get_noskip_flag = _get_noskip_flag,
242 .set_noskip_flag = _set_noskip_flag,
243 .build = _build,
244 .process = _process,
245 .add_segment = _add_segment,
246 .get_ref = _get_ref,
247 .destroy = _destroy,
248 },
249 .add = _add,
250 .create_enumerator = _create_enumerator,
251 },
252 .type = { PEN_IETF, IETF_ATTR_ATTRIBUTE_REQUEST },
253 .list = linked_list_create(),
254 .ref = 1,
255 );
256
257 if (vendor_id != PEN_RESERVED)
258 {
259 add(this, vendor_id, type);
260 }
261
262 return &this->public.pa_tnc_attribute;
263 }
264
265 /**
266 * Described in header.
267 */
268 pa_tnc_attr_t *ietf_attr_attr_request_create_from_data(size_t length,
269 chunk_t data)
270 {
271 private_ietf_attr_attr_request_t *this;
272
273 INIT(this,
274 .public = {
275 .pa_tnc_attribute = {
276 .get_type = _get_type,
277 .get_value = _get_value,
278 .get_noskip_flag = _get_noskip_flag,
279 .set_noskip_flag = _set_noskip_flag,
280 .build = _build,
281 .process = _process,
282 .add_segment = _add_segment,
283 .get_ref = _get_ref,
284 .destroy = _destroy,
285 },
286 .add = _add,
287 .create_enumerator = _create_enumerator,
288 },
289 .type = { PEN_IETF, IETF_ATTR_ATTRIBUTE_REQUEST },
290 .length = length,
291 .value = chunk_clone(data),
292 .list = linked_list_create(),
293 .ref = 1,
294 );
295
296 return &this->public.pa_tnc_attribute;
297 }
298