e1047aaa80822c5d069a6722a5c5feb5a973bbb3
[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, get_ref, pa_tnc_attr_t*,
200 private_ietf_attr_attr_request_t *this)
201 {
202 ref_get(&this->ref);
203 return &this->public.pa_tnc_attribute;
204 }
205
206 METHOD(pa_tnc_attr_t, destroy, void,
207 private_ietf_attr_attr_request_t *this)
208 {
209 if (ref_put(&this->ref))
210 {
211 this->list->destroy_function(this->list, free);
212 free(this->value.ptr);
213 free(this);
214 }
215 }
216
217 METHOD(ietf_attr_attr_request_t, create_enumerator, enumerator_t*,
218 private_ietf_attr_attr_request_t *this)
219 {
220 return this->list->create_enumerator(this->list);
221 }
222
223 /**
224 * Described in header.
225 */
226 pa_tnc_attr_t *ietf_attr_attr_request_create(pen_t vendor_id, u_int32_t type)
227 {
228 private_ietf_attr_attr_request_t *this;
229
230 INIT(this,
231 .public = {
232 .pa_tnc_attribute = {
233 .get_type = _get_type,
234 .get_value = _get_value,
235 .get_noskip_flag = _get_noskip_flag,
236 .set_noskip_flag = _set_noskip_flag,
237 .build = _build,
238 .process = _process,
239 .get_ref = _get_ref,
240 .destroy = _destroy,
241 },
242 .add = _add,
243 .create_enumerator = _create_enumerator,
244 },
245 .type = { PEN_IETF, IETF_ATTR_ATTRIBUTE_REQUEST },
246 .list = linked_list_create(),
247 .ref = 1,
248 );
249
250 if (vendor_id != PEN_RESERVED)
251 {
252 add(this, vendor_id, type);
253 }
254
255 return &this->public.pa_tnc_attribute;
256 }
257
258 /**
259 * Described in header.
260 */
261 pa_tnc_attr_t *ietf_attr_attr_request_create_from_data(size_t length,
262 chunk_t data)
263 {
264 private_ietf_attr_attr_request_t *this;
265
266 INIT(this,
267 .public = {
268 .pa_tnc_attribute = {
269 .get_type = _get_type,
270 .get_value = _get_value,
271 .get_noskip_flag = _get_noskip_flag,
272 .set_noskip_flag = _set_noskip_flag,
273 .build = _build,
274 .process = _process,
275 .get_ref = _get_ref,
276 .destroy = _destroy,
277 },
278 .add = _add,
279 .create_enumerator = _create_enumerator,
280 },
281 .type = { PEN_IETF, IETF_ATTR_ATTRIBUTE_REQUEST },
282 .length = length,
283 .value = chunk_clone(data),
284 .list = linked_list_create(),
285 .ref = 1,
286 );
287
288 return &this->public.pa_tnc_attribute;
289 }
290