Merged libpts into libimcv
[strongswan.git] / src / libimcv / seg / seg_env.c
1 /*
2 * Copyright (C) 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 "seg_env.h"
17
18 #include "imcv.h"
19 #include "pa_tnc/pa_tnc_msg.h"
20 #include "tcg/seg/tcg_seg_attr_seg_env.h"
21
22 #include <utils/debug.h>
23 #include <bio/bio_reader.h>
24 #include <bio/bio_writer.h>
25
26 #define BASE_ATTR_ID_PREFIX 0xFF
27
28 typedef struct private_seg_env_t private_seg_env_t;
29
30 /**
31 * Private data of a seg_env_t object.
32 */
33 struct private_seg_env_t {
34
35 /**
36 * Public seg_env_t interface.
37 */
38 seg_env_t public;
39
40 /**
41 * Base Attribute ID
42 */
43 uint32_t base_attr_id;
44
45 /**
46 * Base Attribute
47 */
48 pa_tnc_attr_t *base_attr;
49
50 /**
51 * Maximum PA-TNC attribute segment size
52 */
53 uint32_t max_seg_size;
54
55 /**
56 * TRUE if attribute is assembled from data
57 */
58 bool from_data;
59
60 /**
61 * Remaining attribute data to be sent or received data being accumulated
62 */
63 chunk_t data;
64
65 };
66
67 METHOD(seg_env_t, get_base_attr_id, uint32_t,
68 private_seg_env_t *this)
69 {
70 return this->base_attr_id;
71 }
72
73 METHOD(seg_env_t, get_base_attr, pa_tnc_attr_t*,
74 private_seg_env_t *this, pa_tnc_attr_t** error)
75 {
76 *error = NULL;
77
78 if (!this->base_attr)
79 {
80 bio_writer_t *writer;
81 bio_reader_t *reader;
82 chunk_t msg_info;
83 uint32_t offset = 0;
84
85 writer = bio_writer_create(8);
86 writer->write_uint8 (writer, PA_TNC_VERSION);
87 writer->write_uint24(writer, PA_TNC_RESERVED);
88 writer->write_uint8 (writer, BASE_ATTR_ID_PREFIX);
89 writer->write_uint24(writer, this->base_attr_id);
90 msg_info = writer->extract_buf(writer);
91 writer->destroy(writer);
92
93 reader = bio_reader_create(this->data);
94 this->base_attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
95 reader, &offset, msg_info, error);
96 chunk_free(&msg_info);
97 reader->destroy(reader);
98 }
99
100 return this->base_attr ? this->base_attr->get_ref(this->base_attr) : NULL;
101 }
102
103 METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
104 private_seg_env_t *this)
105 {
106 pa_tnc_attr_t *seg_env_attr;
107 bio_writer_t *writer;
108 pen_type_t type;
109 chunk_t segment_data, value;
110 uint8_t flags, seg_env_flags;
111
112 /* get components of base attribute header and data */
113 flags = this->base_attr->get_noskip_flag(this->base_attr) ?
114 PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE;
115 type = this->base_attr->get_type(this->base_attr);
116
117 /* attribute data going into the first segment */
118 segment_data = this->data;
119 segment_data.len = this->max_seg_size - PA_TNC_ATTR_HEADER_SIZE;
120
121 /* build encoding of the base attribute header and first segment data */
122 writer = bio_writer_create(this->max_seg_size);
123 writer->write_uint8 (writer, flags);
124 writer->write_uint24(writer, type.vendor_id);
125 writer->write_uint32(writer, type.type);
126 writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + this->data.len);
127 writer->write_data (writer, segment_data);
128 value = writer->extract_buf(writer);
129 writer->destroy(writer);
130 this->data = chunk_skip(this->data, segment_data.len);
131
132 DBG2(DBG_TNC, "creating first segment for base attribute ID %d (%d bytes)",
133 this->base_attr_id, this->max_seg_size);
134
135 seg_env_flags = SEG_ENV_FLAG_START | SEG_ENV_FLAG_MORE;
136 seg_env_attr = tcg_seg_attr_seg_env_create(value, seg_env_flags,
137 this->base_attr_id);
138 chunk_free(&value);
139
140 return seg_env_attr;
141 }
142
143 METHOD(seg_env_t, next_segment, pa_tnc_attr_t*,
144 private_seg_env_t *this, bool *last)
145 {
146 pa_tnc_attr_t *seg_env_attr;
147 chunk_t segment_data;
148 uint8_t seg_env_flags;
149 bool is_last_segment;
150
151 if (this->data.len == 0)
152 {
153 /* no more attribute data to segment available */
154 return NULL;
155 }
156
157 /* attribute data going into the next segment */
158 segment_data = this->data;
159 segment_data.len = min(this->max_seg_size, this->data.len);
160 this->data = chunk_skip(this->data, segment_data.len);
161
162 is_last_segment = (this->data.len == 0);
163 if (last)
164 {
165 *last = is_last_segment;
166 }
167 DBG2(DBG_TNC, "creating %s segment for base attribute ID %d (%d bytes)",
168 is_last_segment ? "last" : "next", this->base_attr_id,
169 segment_data.len);
170
171 seg_env_flags = is_last_segment ? SEG_ENV_FLAG_NONE : SEG_ENV_FLAG_MORE;
172 seg_env_attr = tcg_seg_attr_seg_env_create(segment_data, seg_env_flags,
173 this->base_attr_id);
174
175 return seg_env_attr;
176 }
177
178 METHOD(seg_env_t, add_segment, void,
179 private_seg_env_t *this, chunk_t segment_data)
180 {
181 this->data = chunk_cat("mc", this->data, segment_data);
182 }
183
184 METHOD(seg_env_t, destroy, void,
185 private_seg_env_t *this)
186 {
187 if (this->from_data)
188 {
189 chunk_free(&this->data);
190 }
191 DESTROY_IF(this->base_attr);
192 free(this);
193 }
194
195 /**
196 * See header
197 */
198 seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
199 uint32_t max_seg_size)
200 {
201 private_seg_env_t *this;
202 chunk_t value;
203
204 base_attr->build(base_attr);
205 value = base_attr->get_value(base_attr);
206
207 /**
208 * The PA-TNC attribute header must not be segmented and
209 * there must be at least a first and one next segment
210 */
211 if (max_seg_size < PA_TNC_ATTR_HEADER_SIZE ||
212 max_seg_size >= PA_TNC_ATTR_HEADER_SIZE + value.len)
213 {
214 return NULL;
215 }
216
217 INIT(this,
218 .public = {
219 .get_base_attr_id = _get_base_attr_id,
220 .get_base_attr = _get_base_attr,
221 .first_segment = _first_segment,
222 .next_segment = _next_segment,
223 .add_segment = _add_segment,
224 .destroy = _destroy,
225 },
226 .base_attr_id = base_attr_id,
227 .base_attr = base_attr->get_ref(base_attr),
228 .max_seg_size = max_seg_size,
229 .data = base_attr->get_value(base_attr),
230 );
231
232 return &this->public;
233 }
234
235 /**
236 * See header
237 */
238 seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
239 uint32_t max_seg_size)
240 {
241 private_seg_env_t *this;
242
243 INIT(this,
244 .public = {
245 .get_base_attr_id = _get_base_attr_id,
246 .get_base_attr = _get_base_attr,
247 .first_segment = _first_segment,
248 .next_segment = _next_segment,
249 .add_segment = _add_segment,
250 .destroy = _destroy,
251 },
252 .base_attr_id = base_attr_id,
253 .max_seg_size = max_seg_size,
254 .data = chunk_clone(data),
255 .from_data = TRUE,
256 );
257
258 return &this->public;
259 }
260