Added add_segment() method to IETF attributes
[strongswan.git] / src / libimcv / ietf / ietf_attr_op_status.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 "ietf_attr_op_status.h"
17
18 #include <pa_tnc/pa_tnc_msg.h>
19 #include <bio/bio_writer.h>
20 #include <bio/bio_reader.h>
21 #include <utils/debug.h>
22
23 #include <time.h>
24
25 typedef struct private_ietf_attr_op_status_t private_ietf_attr_op_status_t;
26
27 ENUM(op_status_names, OP_STATUS_UNKNOWN, OP_STATUS_OPERATIONAL,
28 "unknown",
29 "not installed",
30 "installed",
31 "operational"
32 );
33
34 ENUM(op_result_names, OP_RESULT_UNKNOWN, OP_RESULT_UNSUCCESSFUL,
35 "unknown",
36 "successful",
37 "errored",
38 "unsuccessful"
39 );
40
41 /**
42 * PA-TNC Operational Status type (see section 4.2.5 of RFC 5792)
43 *
44 * 1 2 3
45 * 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
46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 * | Status | Result | Reserved |
48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 * | Last Use |
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * | Last Use (continued) |
52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 * | Last Use (continued) |
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * | Last Use (continued) |
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 * | Last Use (continued) |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 */
60
61 #define OP_STATUS_SIZE 24
62
63 /**
64 * Private data of an ietf_attr_op_status_t object.
65 */
66 struct private_ietf_attr_op_status_t {
67
68 /**
69 * Public members of ietf_attr_op_status_t
70 */
71 ietf_attr_op_status_t public;
72
73 /**
74 * Vendor-specific attribute type
75 */
76 pen_type_t type;
77
78 /**
79 * Length of attribute value
80 */
81 size_t length;
82
83 /**
84 * Attribute value or segment
85 */
86 chunk_t value;
87
88 /**
89 * Noskip flag
90 */
91 bool noskip_flag;
92
93 /**
94 * Status
95 */
96 u_int8_t status;
97
98 /**
99 * Result
100 */
101 u_int8_t result;
102
103 /**
104 * Last Use
105 */
106 time_t last_use;
107
108 /**
109 * Reference count
110 */
111 refcount_t ref;
112 };
113
114 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
115 private_ietf_attr_op_status_t *this)
116 {
117 return this->type;
118 }
119
120 METHOD(pa_tnc_attr_t, get_value, chunk_t,
121 private_ietf_attr_op_status_t *this)
122 {
123 return this->value;
124 }
125
126 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
127 private_ietf_attr_op_status_t *this)
128 {
129 return this->noskip_flag;
130 }
131
132 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
133 private_ietf_attr_op_status_t *this, bool noskip)
134 {
135 this->noskip_flag = noskip;
136 }
137
138 METHOD(pa_tnc_attr_t, build, void,
139 private_ietf_attr_op_status_t *this)
140 {
141 bio_writer_t *writer;
142 char last_use[24];
143 struct tm t;
144
145 if (this->value.ptr)
146 {
147 return;
148 }
149
150 /* Conversion from time_t to RFC 3339 ASCII string */
151 gmtime_r(&this->last_use, &t);
152 snprintf(last_use, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.tm_year,
153 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
154
155 writer = bio_writer_create(OP_STATUS_SIZE);
156 writer->write_uint8 (writer, this->status);
157 writer->write_uint8 (writer, this->result);
158 writer->write_uint16(writer, 0x0000);
159 writer->write_data (writer, chunk_create(last_use, 20));
160
161 this->value = writer->extract_buf(writer);
162 this->length = this->value.len;
163 writer->destroy(writer);
164 }
165
166 METHOD(pa_tnc_attr_t, process, status_t,
167 private_ietf_attr_op_status_t *this, u_int32_t *offset)
168 {
169 bio_reader_t *reader;
170 chunk_t last_use;
171 u_int16_t reserved;
172 struct tm t;
173
174 *offset = 0;
175
176 if (this->value.len < this->length)
177 {
178 return NEED_MORE;
179 }
180 if (this->value.len != OP_STATUS_SIZE)
181 {
182 DBG1(DBG_TNC, "incorrect size for IETF operational status");
183 return FAILED;
184 }
185 reader = bio_reader_create(this->value);
186 reader->read_uint8 (reader, &this->status);
187 reader->read_uint8 (reader, &this->result);
188 reader->read_uint16(reader, &reserved);
189 reader->read_data (reader, 20, &last_use);
190 reader->destroy(reader);
191
192 if (this->status > OP_STATUS_ROOF)
193 {
194 DBG1(DBG_TNC, "invalid status value %c for IETF operational status",
195 this->status);
196 return FAILED;
197 }
198
199 *offset = 1;
200
201 if (this->result > OP_RESULT_ROOF)
202 {
203 DBG1(DBG_TNC, "invalid result value %c for IETF operational status",
204 this->result);
205 return FAILED;
206 }
207
208 *offset = 4;
209
210 /* Conversion from RFC 3339 ASCII string to time_t */
211 if (sscanf(last_use.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ", &t.tm_year, &t.tm_mon,
212 &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
213 {
214 DBG1(DBG_TNC, "invalid last_use time format in IETF operational status");
215 return FAILED;
216 }
217 t.tm_year -= 1900;
218 t.tm_mon -= 1;
219 t.tm_isdst = 0;
220 this->last_use = mktime(&t) - timezone;
221
222 return SUCCESS;
223 }
224
225 METHOD(pa_tnc_attr_t, add_segment, void,
226 private_ietf_attr_op_status_t *this, chunk_t segment)
227 {
228 this->value = chunk_cat("mc", this->value, segment);
229 }
230
231 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
232 private_ietf_attr_op_status_t *this)
233 {
234 ref_get(&this->ref);
235 return &this->public.pa_tnc_attribute;
236 }
237
238 METHOD(pa_tnc_attr_t, destroy, void,
239 private_ietf_attr_op_status_t *this)
240 {
241 if (ref_put(&this->ref))
242 {
243 free(this->value.ptr);
244 free(this);
245 }
246 }
247
248 METHOD(ietf_attr_op_status_t, get_status, u_int8_t,
249 private_ietf_attr_op_status_t *this)
250 {
251 return this->status;
252 }
253
254 METHOD(ietf_attr_op_status_t, get_result, u_int8_t,
255 private_ietf_attr_op_status_t *this)
256 {
257 return this->result;
258 }
259
260 METHOD(ietf_attr_op_status_t, get_last_use, time_t,
261 private_ietf_attr_op_status_t *this)
262 {
263 return this->last_use;
264 }
265
266 /**
267 * Described in header.
268 */
269 pa_tnc_attr_t *ietf_attr_op_status_create(u_int8_t status, u_int8_t result,
270 time_t last_use)
271 {
272 private_ietf_attr_op_status_t *this;
273
274 INIT(this,
275 .public = {
276 .pa_tnc_attribute = {
277 .get_type = _get_type,
278 .get_value = _get_value,
279 .get_noskip_flag = _get_noskip_flag,
280 .set_noskip_flag = _set_noskip_flag,
281 .build = _build,
282 .process = _process,
283 .add_segment = _add_segment,
284 .get_ref = _get_ref,
285 .destroy = _destroy,
286 },
287 .get_status = _get_status,
288 .get_result = _get_result,
289 .get_last_use = _get_last_use,
290 },
291 .type = { PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS },
292 .status = status,
293 .result = result,
294 .last_use = last_use,
295 .ref = 1,
296 );
297
298 return &this->public.pa_tnc_attribute;
299 }
300
301 /**
302 * Described in header.
303 */
304 pa_tnc_attr_t *ietf_attr_op_status_create_from_data(size_t length, chunk_t data)
305 {
306 private_ietf_attr_op_status_t *this;
307
308 INIT(this,
309 .public = {
310 .pa_tnc_attribute = {
311 .get_type = _get_type,
312 .get_value = _get_value,
313 .get_noskip_flag = _get_noskip_flag,
314 .set_noskip_flag = _set_noskip_flag,
315 .build = _build,
316 .process = _process,
317 .add_segment = _add_segment,
318 .get_ref = _get_ref,
319 .destroy = _destroy,
320 },
321 .get_status = _get_status,
322 .get_result = _get_result,
323 .get_last_use = _get_last_use,
324 },
325 .type = { PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS },
326 .value = chunk_clone(data),
327 .ref = 1,
328 );
329
330 return &this->public.pa_tnc_attribute;
331 }
332