2 * Copyright (C) 2017 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "ietf_swima_attr_sw_ev.h"
17 #include "swima/swima_event.h"
19 #include <pa_tnc/pa_tnc_msg.h>
20 #include <bio/bio_writer.h>
21 #include <bio/bio_reader.h>
22 #include <utils/debug.h>
24 #define SW_EV_TIMESTAMP_SIZE 20
26 typedef struct private_ietf_swima_attr_sw_ev_t private_ietf_swima_attr_sw_ev_t
;
29 * Software [Identifier] Events
30 * see sections 5.9/5.11 of IETF SW Inventory Message and Attributes for PA-TNC
33 * 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
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 * | Flags | Software Identifier Count |
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 * | Request ID Copy / Subscription ID |
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Last Consulted EID |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 * | Record Identifier |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 * | Data Model Type PEN |Data Model Type|
60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 * | Source ID Num | Action | Software Identifier Length |
62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 * | Software Identifier (Variable Length) |
64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 * | Software Locator Length | Software Locator (Var. Len) |
66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 * see section 5.11 of IETF SW Inventory Message and Attributes for PA-TNC
71 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 * | Record (Variable length) |
75 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 * Private data of an ietf_swima_attr_sw_ev_t object.
81 struct private_ietf_swima_attr_sw_ev_t
{
84 * Public members of ietf_swima_attr_sw_ev_t
86 ietf_swima_attr_sw_ev_t
public;
89 * Vendor-specific attribute type
94 * Length of attribute value
99 * Offset up to which attribute value has been processed
104 * Current position of attribute value pointer
109 * Contains complete attribute or current segment
129 * Number of unprocessed software events in attribute
131 uint32_t event_count
;
136 swima_events_t
*events
;
144 METHOD(pa_tnc_attr_t
, get_type
, pen_type_t
,
145 private_ietf_swima_attr_sw_ev_t
*this)
150 METHOD(pa_tnc_attr_t
, get_value
, chunk_t
,
151 private_ietf_swima_attr_sw_ev_t
*this)
156 METHOD(pa_tnc_attr_t
, get_noskip_flag
, bool,
157 private_ietf_swima_attr_sw_ev_t
*this)
159 return this->noskip_flag
;
162 METHOD(pa_tnc_attr_t
, set_noskip_flag
,void,
163 private_ietf_swima_attr_sw_ev_t
*this, bool noskip
)
165 this->noskip_flag
= noskip
;
168 METHOD(pa_tnc_attr_t
, build
, void,
169 private_ietf_swima_attr_sw_ev_t
*this)
171 bio_writer_t
*writer
;
172 swima_event_t
*sw_event
;
173 swima_record_t
*sw_record
;
174 chunk_t timestamp
, sw_id
, sw_locator
, record
;
175 pen_type_t data_model
;
176 uint32_t eid
, record_id
, last_eid
, last_consulted_eid
, eid_epoch
;
177 uint8_t action
, source_id
;
178 enumerator_t
*enumerator
;
184 last_consulted_eid
= this->events
->get_eid(this->events
, &eid_epoch
,
187 writer
= bio_writer_create(IETF_SWIMA_SW_EV_MIN_SIZE
);
188 writer
->write_uint8 (writer
, this->flags
);
189 writer
->write_uint24(writer
, this->events
->get_count(this->events
));
190 writer
->write_uint32(writer
, this->request_id
);
191 writer
->write_uint32(writer
, eid_epoch
);
192 writer
->write_uint32(writer
, last_eid
);
193 writer
->write_uint32(writer
, last_consulted_eid
);
195 enumerator
= this->events
->create_enumerator(this->events
);
196 while (enumerator
->enumerate(enumerator
, &sw_event
))
198 eid
= sw_event
->get_eid(sw_event
, ×tamp
);
199 action
= sw_event
->get_action(sw_event
);
200 sw_record
= sw_event
->get_sw_record(sw_event
);
201 record_id
= sw_record
->get_record_id(sw_record
);
202 data_model
= sw_record
->get_data_model(sw_record
);
203 source_id
= sw_record
->get_source_id(sw_record
);
204 sw_id
= sw_record
->get_sw_id(sw_record
, &sw_locator
);
206 writer
->write_uint32(writer
, eid
);
207 writer
->write_data (writer
, timestamp
);
208 writer
->write_uint32(writer
, record_id
);
209 writer
->write_uint24(writer
, data_model
.vendor_id
);
210 writer
->write_uint8 (writer
, data_model
.type
);
211 writer
->write_uint8 (writer
, source_id
);
212 writer
->write_uint8 (writer
, action
);
213 writer
->write_data16(writer
, sw_id
);
214 writer
->write_data16(writer
, sw_locator
);
216 if (this->type
.type
== IETF_ATTR_SW_EVENTS
)
218 record
= sw_record
->get_record(sw_record
);
219 writer
->write_data32(writer
, record
);
222 enumerator
->destroy(enumerator
);
224 this->value
= writer
->extract_buf(writer
);
225 this->segment
= this->value
;
226 this->length
= this->value
.len
;
227 writer
->destroy(writer
);
230 METHOD(pa_tnc_attr_t
, process
, status_t
,
231 private_ietf_swima_attr_sw_ev_t
*this, uint32_t *offset
)
233 bio_reader_t
*reader
;
234 uint32_t data_model_pen
, record_id
;
235 uint32_t eid
, eid_epoch
, last_eid
, last_consulted_eid
;
236 uint8_t data_model_type
, source_id
, action
;
237 pen_type_t data_model
;
238 chunk_t sw_id
, sw_locator
, record
, timestamp
;
239 swima_event_t
*sw_event
;
240 swima_record_t
*sw_record
;
241 status_t status
= NEED_MORE
;
243 if (this->offset
== 0)
245 if (this->length
< IETF_SWIMA_SW_EV_MIN_SIZE
)
247 DBG1(DBG_TNC
, "insufficient data for %N/%N", pen_names
, PEN_IETF
,
248 ietf_attr_names
, this->type
.type
);
249 *offset
= this->offset
;
252 if (this->value
.len
< IETF_SWIMA_SW_EV_MIN_SIZE
)
256 reader
= bio_reader_create(this->value
);
257 reader
->read_uint8 (reader
, &this->flags
);
258 reader
->read_uint24(reader
, &this->event_count
);
259 reader
->read_uint32(reader
, &this->request_id
);
260 reader
->read_uint32(reader
, &eid_epoch
);
261 reader
->read_uint32(reader
, &last_eid
);
262 reader
->read_uint32(reader
, &last_consulted_eid
);
263 this->offset
= IETF_SWIMA_SW_EV_MIN_SIZE
;
264 this->events
->set_eid(this->events
, last_consulted_eid
, eid_epoch
);
265 this->events
->set_last_eid(this->events
, last_eid
);
266 this->value
= reader
->peek(reader
);
267 reader
->destroy(reader
);
270 reader
= bio_reader_create(this->value
);
272 while (this->event_count
)
274 if (!reader
->read_uint32(reader
, &eid
) ||
275 !reader
->read_data (reader
, SW_EV_TIMESTAMP_SIZE
, ×tamp
) ||
276 !reader
->read_uint32(reader
, &record_id
) ||
277 !reader
->read_uint24(reader
, &data_model_pen
) ||
278 !reader
->read_uint8 (reader
, &data_model_type
) ||
279 !reader
->read_uint8 (reader
, &source_id
) ||
280 !reader
->read_uint8 (reader
, &action
) ||
281 !reader
->read_data16(reader
, &sw_id
) ||
282 !reader
->read_data16(reader
, &sw_locator
))
286 record
= chunk_empty
;
288 if (action
== 0 || action
> SWIMA_EVENT_ACTION_LAST
)
290 DBG1(DBG_TNC
, "invalid event action value for %N/%N", pen_names
,
291 PEN_IETF
, ietf_attr_names
, this->type
.type
);
292 *offset
= this->offset
;
293 reader
->destroy(reader
);
298 if (this->type
.type
== IETF_ATTR_SW_EVENTS
&&
299 !reader
->read_data32(reader
, &record
))
303 data_model
= pen_type_create(data_model_pen
, data_model_type
);
304 sw_record
= swima_record_create(record_id
, sw_id
, sw_locator
);
305 sw_record
->set_data_model(sw_record
, data_model
);
306 sw_record
->set_source_id(sw_record
, source_id
);
307 sw_record
->set_record(sw_record
, record
);
308 sw_event
= swima_event_create(eid
, timestamp
, action
, sw_record
);
309 this->events
->add(this->events
, sw_event
);
310 this->offset
+= this->value
.len
- reader
->remaining(reader
);
311 this->value
= reader
->peek(reader
);
313 /* at least one software event was processed */
318 if (this->length
== this->offset
)
324 DBG1(DBG_TNC
, "inconsistent length for %N/%N", pen_names
, PEN_IETF
,
325 ietf_attr_names
, this->type
.type
);
326 *offset
= this->offset
;
331 reader
->destroy(reader
);
335 METHOD(pa_tnc_attr_t
, add_segment
, void,
336 private_ietf_swima_attr_sw_ev_t
*this, chunk_t segment
)
338 this->value
= chunk_cat("cc", this->value
, segment
);
339 chunk_free(&this->segment
);
340 this->segment
= this->value
;
343 METHOD(pa_tnc_attr_t
, get_ref
, pa_tnc_attr_t
*,
344 private_ietf_swima_attr_sw_ev_t
*this)
347 return &this->public.pa_tnc_attribute
;
350 METHOD(pa_tnc_attr_t
, destroy
, void,
351 private_ietf_swima_attr_sw_ev_t
*this)
353 if (ref_put(&this->ref
))
355 this->events
->destroy(this->events
);
356 free(this->segment
.ptr
);
361 METHOD(ietf_swima_attr_sw_ev_t
, get_flags
, uint8_t,
362 private_ietf_swima_attr_sw_ev_t
*this)
367 METHOD(ietf_swima_attr_sw_ev_t
, get_request_id
, uint32_t,
368 private_ietf_swima_attr_sw_ev_t
*this)
370 return this->request_id
;
373 METHOD(ietf_swima_attr_sw_ev_t
, get_event_count
, uint32_t,
374 private_ietf_swima_attr_sw_ev_t
*this)
376 return this->event_count
;
379 METHOD(ietf_swima_attr_sw_ev_t
, set_events
, void,
380 private_ietf_swima_attr_sw_ev_t
*this, swima_events_t
*events
)
382 this->events
->destroy(this->events
);
383 this->events
= events
->get_ref(events
);
386 METHOD(ietf_swima_attr_sw_ev_t
, get_events
, swima_events_t
*,
387 private_ietf_swima_attr_sw_ev_t
*this)
392 METHOD(ietf_swima_attr_sw_ev_t
, clear_events
, void,
393 private_ietf_swima_attr_sw_ev_t
*this)
395 this->events
->clear(this->events
);
399 * Described in header.
401 pa_tnc_attr_t
*ietf_swima_attr_sw_ev_create(uint8_t flags
, uint32_t request_id
,
404 private_ietf_swima_attr_sw_ev_t
*this;
407 type
= sw_id_only ? IETF_ATTR_SW_ID_EVENTS
: IETF_ATTR_SW_EVENTS
;
411 .pa_tnc_attribute
= {
412 .get_type
= _get_type
,
413 .get_value
= _get_value
,
414 .get_noskip_flag
= _get_noskip_flag
,
415 .set_noskip_flag
= _set_noskip_flag
,
418 .add_segment
= _add_segment
,
422 .get_flags
= _get_flags
,
423 .get_request_id
= _get_request_id
,
424 .get_event_count
= _get_event_count
,
425 .set_events
= _set_events
,
426 .get_events
= _get_events
,
427 .clear_events
= _clear_events
,
429 .type
= { PEN_IETF
, type
},
431 .request_id
= request_id
,
432 .events
= swima_events_create(),
436 return &this->public.pa_tnc_attribute
;
441 * Described in header.
443 pa_tnc_attr_t
*ietf_swima_attr_sw_ev_create_from_data(size_t length
,
444 chunk_t data
, bool sw_id_only
)
446 private_ietf_swima_attr_sw_ev_t
*this;
449 type
= sw_id_only ? IETF_ATTR_SW_ID_EVENTS
: IETF_ATTR_SW_EVENTS
;
453 .pa_tnc_attribute
= {
454 .get_type
= _get_type
,
455 .get_value
= _get_value
,
456 .get_noskip_flag
= _get_noskip_flag
,
457 .set_noskip_flag
= _set_noskip_flag
,
460 .add_segment
= _add_segment
,
464 .get_flags
= _get_flags
,
465 .get_request_id
= _get_request_id
,
466 .get_event_count
= _get_event_count
,
467 .set_events
= _set_events
,
468 .get_events
= _get_events
,
469 .clear_events
= _clear_events
,
471 .type
= { PEN_IETF
, type
},
473 .segment
= chunk_clone(data
),
474 .events
= swima_events_create(),
478 /* received either complete attribute value or first segment */
479 this->value
= this->segment
;
481 return &this->public.pa_tnc_attribute
;