]>
Commit | Line | Data |
---|---|---|
84c0366b AS |
1 | /* |
2 | * Copyright (C) 2017 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_swima_attr_sw_ev.h" | |
17 | #include "swima/swima_event.h" | |
18 | ||
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> | |
23 | ||
24 | #define SW_EV_TIMESTAMP_SIZE 20 | |
25 | ||
26 | typedef struct private_ietf_swima_attr_sw_ev_t private_ietf_swima_attr_sw_ev_t; | |
27 | ||
28 | /** | |
29 | * Software [Identifier] Events | |
2a26566e | 30 | * see sections 5.9/5.11 of RFC 8412 SWIMA |
84c0366b AS |
31 | * |
32 | * 1 2 3 | |
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 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
39 | * | EID Epoch | | |
40 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
41 | * | Last EID | | |
42 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
43 | * | Last Consulted EID | | |
44 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
45 | * | EID | | |
46 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
47 | * | Timestamp | | |
48 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
49 | * | Timestamp | | |
50 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
51 | * | Timestamp | | |
52 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
53 | * | Timestamp | | |
54 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
55 | * | Timestamp | | |
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 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
67 | * | |
68 | * Software Event only | |
69 | * see section 5.11 of IETF SW Inventory Message and Attributes for PA-TNC | |
70 | * | |
71 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
72 | * | Record Length | | |
73 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
74 | * | Record (Variable length) | | |
75 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
76 | */ | |
77 | ||
78 | /** | |
79 | * Private data of an ietf_swima_attr_sw_ev_t object. | |
80 | */ | |
81 | struct private_ietf_swima_attr_sw_ev_t { | |
82 | ||
83 | /** | |
84 | * Public members of ietf_swima_attr_sw_ev_t | |
85 | */ | |
86 | ietf_swima_attr_sw_ev_t public; | |
87 | ||
88 | /** | |
89 | * Vendor-specific attribute type | |
90 | */ | |
91 | pen_type_t type; | |
92 | ||
93 | /** | |
94 | * Length of attribute value | |
95 | */ | |
96 | size_t length; | |
97 | ||
98 | /** | |
99 | * Offset up to which attribute value has been processed | |
100 | */ | |
101 | size_t offset; | |
102 | ||
103 | /** | |
104 | * Current position of attribute value pointer | |
105 | */ | |
106 | chunk_t value; | |
107 | ||
108 | /** | |
109 | * Contains complete attribute or current segment | |
110 | */ | |
111 | chunk_t segment; | |
112 | ||
113 | /** | |
114 | * Noskip flag | |
115 | */ | |
116 | bool noskip_flag; | |
117 | ||
118 | /** | |
119 | * Request ID | |
120 | */ | |
121 | uint32_t request_id; | |
122 | ||
123 | /** | |
124 | * Attribute flags | |
125 | */ | |
126 | uint8_t flags; | |
127 | ||
128 | /** | |
129 | * Number of unprocessed software events in attribute | |
130 | */ | |
131 | uint32_t event_count; | |
132 | ||
133 | /** | |
134 | * Event list | |
135 | */ | |
136 | swima_events_t *events; | |
137 | ||
138 | /** | |
139 | * Reference count | |
140 | */ | |
141 | refcount_t ref; | |
142 | }; | |
143 | ||
144 | METHOD(pa_tnc_attr_t, get_type, pen_type_t, | |
145 | private_ietf_swima_attr_sw_ev_t *this) | |
146 | { | |
147 | return this->type; | |
148 | } | |
149 | ||
150 | METHOD(pa_tnc_attr_t, get_value, chunk_t, | |
151 | private_ietf_swima_attr_sw_ev_t *this) | |
152 | { | |
153 | return this->value; | |
154 | } | |
155 | ||
156 | METHOD(pa_tnc_attr_t, get_noskip_flag, bool, | |
157 | private_ietf_swima_attr_sw_ev_t *this) | |
158 | { | |
159 | return this->noskip_flag; | |
160 | } | |
161 | ||
162 | METHOD(pa_tnc_attr_t, set_noskip_flag,void, | |
163 | private_ietf_swima_attr_sw_ev_t *this, bool noskip) | |
164 | { | |
165 | this->noskip_flag = noskip; | |
166 | } | |
167 | ||
27ec213d AS |
168 | /** |
169 | * This function is shared with ietf_swima_attr_sw_inv.c | |
170 | **/ | |
171 | void ietf_swima_attr_sw_ev_build_sw_record(bio_writer_t *writer, | |
172 | uint8_t action, swima_record_t *sw_record, bool has_record) | |
173 | { | |
174 | pen_type_t data_model; | |
175 | chunk_t sw_locator; | |
176 | ||
177 | data_model = sw_record->get_data_model(sw_record); | |
178 | ||
179 | writer->write_uint32(writer, sw_record->get_record_id(sw_record)); | |
180 | writer->write_uint24(writer, data_model.vendor_id); | |
181 | writer->write_uint8 (writer, data_model.type); | |
182 | writer->write_uint8 (writer, sw_record->get_source_id(sw_record)); | |
183 | writer->write_uint8 (writer, action); | |
184 | writer->write_data16(writer, sw_record->get_sw_id(sw_record, &sw_locator)); | |
185 | writer->write_data16(writer, sw_locator); | |
186 | ||
187 | if (has_record) | |
188 | { | |
189 | writer->write_data32(writer, sw_record->get_record(sw_record)); | |
190 | } | |
191 | } | |
192 | ||
84c0366b AS |
193 | METHOD(pa_tnc_attr_t, build, void, |
194 | private_ietf_swima_attr_sw_ev_t *this) | |
195 | { | |
196 | bio_writer_t *writer; | |
197 | swima_event_t *sw_event; | |
198 | swima_record_t *sw_record; | |
27ec213d AS |
199 | chunk_t timestamp; |
200 | uint32_t last_eid, last_consulted_eid, eid_epoch; | |
201 | uint8_t action; | |
84c0366b AS |
202 | enumerator_t *enumerator; |
203 | ||
204 | if (this->value.ptr) | |
205 | { | |
206 | return; | |
207 | } | |
208 | last_consulted_eid = this->events->get_eid(this->events, &eid_epoch, | |
209 | &last_eid); | |
210 | ||
211 | writer = bio_writer_create(IETF_SWIMA_SW_EV_MIN_SIZE); | |
212 | writer->write_uint8 (writer, this->flags); | |
213 | writer->write_uint24(writer, this->events->get_count(this->events)); | |
214 | writer->write_uint32(writer, this->request_id); | |
215 | writer->write_uint32(writer, eid_epoch); | |
216 | writer->write_uint32(writer, last_eid); | |
217 | writer->write_uint32(writer, last_consulted_eid); | |
218 | ||
219 | enumerator = this->events->create_enumerator(this->events); | |
220 | while (enumerator->enumerate(enumerator, &sw_event)) | |
221 | { | |
84c0366b AS |
222 | action = sw_event->get_action(sw_event); |
223 | sw_record = sw_event->get_sw_record(sw_event); | |
84c0366b | 224 | |
27ec213d | 225 | writer->write_uint32(writer, sw_event->get_eid(sw_event, ×tamp)); |
84c0366b | 226 | writer->write_data (writer, timestamp); |
27ec213d AS |
227 | |
228 | ietf_swima_attr_sw_ev_build_sw_record(writer, action, sw_record, | |
229 | this->type.type == IETF_ATTR_SW_EVENTS); | |
84c0366b AS |
230 | } |
231 | enumerator->destroy(enumerator); | |
232 | ||
233 | this->value = writer->extract_buf(writer); | |
234 | this->segment = this->value; | |
235 | this->length = this->value.len; | |
236 | writer->destroy(writer); | |
237 | } | |
238 | ||
27ec213d AS |
239 | /** |
240 | * This function is shared with ietf_swima_attr_sw_inv.c | |
241 | **/ | |
242 | bool ietf_swima_attr_sw_ev_process_sw_record(bio_reader_t *reader, | |
243 | uint8_t *action, swima_record_t **sw_record, bool has_record) | |
244 | { | |
245 | pen_type_t data_model; | |
246 | swima_record_t *sw_rec; | |
247 | uint32_t data_model_pen, record_id; | |
248 | uint8_t data_model_type, source_id, reserved; | |
249 | chunk_t sw_id, sw_locator, record = chunk_empty; | |
250 | ||
251 | if (!reader->read_uint32(reader, &record_id) || | |
252 | !reader->read_uint24(reader, &data_model_pen) || | |
253 | !reader->read_uint8 (reader, &data_model_type) || | |
254 | !reader->read_uint8 (reader, &source_id) || | |
255 | !reader->read_uint8 (reader, &reserved) || | |
256 | !reader->read_data16(reader, &sw_id) || | |
257 | !reader->read_data16(reader, &sw_locator)) | |
258 | { | |
259 | return FALSE; | |
260 | } | |
261 | ||
262 | if (action) | |
263 | { | |
264 | *action = reserved; | |
265 | } | |
266 | ||
267 | if (has_record && !reader->read_data32(reader, &record)) | |
268 | { | |
269 | return FALSE; | |
270 | } | |
271 | ||
272 | data_model = pen_type_create(data_model_pen, data_model_type); | |
273 | sw_rec = swima_record_create(record_id, sw_id, sw_locator); | |
274 | sw_rec->set_data_model(sw_rec, data_model); | |
275 | sw_rec->set_source_id(sw_rec, source_id); | |
276 | sw_rec->set_record(sw_rec, record); | |
277 | *sw_record = sw_rec; | |
278 | ||
279 | return TRUE; | |
280 | } | |
281 | ||
84c0366b AS |
282 | METHOD(pa_tnc_attr_t, process, status_t, |
283 | private_ietf_swima_attr_sw_ev_t *this, uint32_t *offset) | |
284 | { | |
285 | bio_reader_t *reader; | |
84c0366b | 286 | uint32_t eid, eid_epoch, last_eid, last_consulted_eid; |
27ec213d AS |
287 | uint8_t action; |
288 | chunk_t timestamp; | |
84c0366b AS |
289 | swima_event_t *sw_event; |
290 | swima_record_t *sw_record; | |
291 | status_t status = NEED_MORE; | |
292 | ||
293 | if (this->offset == 0) | |
294 | { | |
295 | if (this->length < IETF_SWIMA_SW_EV_MIN_SIZE) | |
296 | { | |
297 | DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_IETF, | |
298 | ietf_attr_names, this->type.type); | |
299 | *offset = this->offset; | |
300 | return FAILED; | |
301 | } | |
302 | if (this->value.len < IETF_SWIMA_SW_EV_MIN_SIZE) | |
303 | { | |
304 | return NEED_MORE; | |
305 | } | |
306 | reader = bio_reader_create(this->value); | |
307 | reader->read_uint8 (reader, &this->flags); | |
308 | reader->read_uint24(reader, &this->event_count); | |
309 | reader->read_uint32(reader, &this->request_id); | |
310 | reader->read_uint32(reader, &eid_epoch); | |
311 | reader->read_uint32(reader, &last_eid); | |
312 | reader->read_uint32(reader, &last_consulted_eid); | |
313 | this->offset = IETF_SWIMA_SW_EV_MIN_SIZE; | |
314 | this->events->set_eid(this->events, last_consulted_eid, eid_epoch); | |
315 | this->events->set_last_eid(this->events, last_eid); | |
316 | this->value = reader->peek(reader); | |
317 | reader->destroy(reader); | |
318 | } | |
319 | ||
320 | reader = bio_reader_create(this->value); | |
321 | ||
322 | while (this->event_count) | |
323 | { | |
324 | if (!reader->read_uint32(reader, &eid) || | |
325 | !reader->read_data (reader, SW_EV_TIMESTAMP_SIZE, ×tamp) || | |
27ec213d AS |
326 | !ietf_swima_attr_sw_ev_process_sw_record(reader, &action, &sw_record, |
327 | this->type.type == IETF_ATTR_SW_EVENTS)) | |
84c0366b AS |
328 | { |
329 | goto end; | |
330 | } | |
84c0366b | 331 | |
27ec213d AS |
332 | if (action == SWIMA_EVENT_ACTION_NONE || |
333 | action > SWIMA_EVENT_ACTION_LAST) | |
84c0366b AS |
334 | { |
335 | DBG1(DBG_TNC, "invalid event action value for %N/%N", pen_names, | |
336 | PEN_IETF, ietf_attr_names, this->type.type); | |
337 | *offset = this->offset; | |
27ec213d | 338 | sw_record->destroy(sw_record); |
84c0366b AS |
339 | reader->destroy(reader); |
340 | ||
341 | return FAILED; | |
342 | } | |
343 | ||
84c0366b AS |
344 | sw_event = swima_event_create(eid, timestamp, action, sw_record); |
345 | this->events->add(this->events, sw_event); | |
346 | this->offset += this->value.len - reader->remaining(reader); | |
347 | this->value = reader->peek(reader); | |
348 | ||
349 | /* at least one software event was processed */ | |
350 | status = SUCCESS; | |
351 | this->event_count--; | |
352 | } | |
353 | ||
354 | if (this->length == this->offset) | |
355 | { | |
356 | status = SUCCESS; | |
357 | } | |
358 | else | |
359 | { | |
360 | DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_IETF, | |
361 | ietf_attr_names, this->type.type); | |
362 | *offset = this->offset; | |
363 | status = FAILED; | |
364 | } | |
365 | ||
366 | end: | |
367 | reader->destroy(reader); | |
368 | return status; | |
369 | } | |
370 | ||
371 | METHOD(pa_tnc_attr_t, add_segment, void, | |
372 | private_ietf_swima_attr_sw_ev_t *this, chunk_t segment) | |
373 | { | |
374 | this->value = chunk_cat("cc", this->value, segment); | |
375 | chunk_free(&this->segment); | |
376 | this->segment = this->value; | |
377 | } | |
378 | ||
379 | METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, | |
380 | private_ietf_swima_attr_sw_ev_t *this) | |
381 | { | |
382 | ref_get(&this->ref); | |
383 | return &this->public.pa_tnc_attribute; | |
384 | } | |
385 | ||
386 | METHOD(pa_tnc_attr_t, destroy, void, | |
387 | private_ietf_swima_attr_sw_ev_t *this) | |
388 | { | |
389 | if (ref_put(&this->ref)) | |
390 | { | |
391 | this->events->destroy(this->events); | |
392 | free(this->segment.ptr); | |
393 | free(this); | |
394 | } | |
395 | } | |
396 | ||
397 | METHOD(ietf_swima_attr_sw_ev_t, get_flags, uint8_t, | |
398 | private_ietf_swima_attr_sw_ev_t *this) | |
399 | { | |
400 | return this->flags; | |
401 | } | |
402 | ||
403 | METHOD(ietf_swima_attr_sw_ev_t, get_request_id, uint32_t, | |
404 | private_ietf_swima_attr_sw_ev_t *this) | |
405 | { | |
406 | return this->request_id; | |
407 | } | |
408 | ||
409 | METHOD(ietf_swima_attr_sw_ev_t, get_event_count, uint32_t, | |
410 | private_ietf_swima_attr_sw_ev_t *this) | |
411 | { | |
412 | return this->event_count; | |
413 | } | |
414 | ||
415 | METHOD(ietf_swima_attr_sw_ev_t, set_events, void, | |
416 | private_ietf_swima_attr_sw_ev_t *this, swima_events_t *events) | |
417 | { | |
418 | this->events->destroy(this->events); | |
419 | this->events = events->get_ref(events); | |
420 | } | |
421 | ||
422 | METHOD(ietf_swima_attr_sw_ev_t, get_events, swima_events_t*, | |
423 | private_ietf_swima_attr_sw_ev_t *this) | |
424 | { | |
425 | return this->events; | |
426 | } | |
427 | ||
428 | METHOD(ietf_swima_attr_sw_ev_t, clear_events, void, | |
429 | private_ietf_swima_attr_sw_ev_t *this) | |
430 | { | |
431 | this->events->clear(this->events); | |
432 | } | |
433 | ||
434 | /** | |
435 | * Described in header. | |
436 | */ | |
437 | pa_tnc_attr_t *ietf_swima_attr_sw_ev_create(uint8_t flags, uint32_t request_id, | |
438 | bool sw_id_only) | |
439 | { | |
440 | private_ietf_swima_attr_sw_ev_t *this; | |
441 | ietf_attr_t type; | |
442 | ||
443 | type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS; | |
444 | ||
445 | INIT(this, | |
446 | .public = { | |
447 | .pa_tnc_attribute = { | |
448 | .get_type = _get_type, | |
449 | .get_value = _get_value, | |
450 | .get_noskip_flag = _get_noskip_flag, | |
451 | .set_noskip_flag = _set_noskip_flag, | |
452 | .build = _build, | |
453 | .process = _process, | |
454 | .add_segment = _add_segment, | |
455 | .get_ref = _get_ref, | |
456 | .destroy = _destroy, | |
457 | }, | |
458 | .get_flags = _get_flags, | |
459 | .get_request_id = _get_request_id, | |
460 | .get_event_count = _get_event_count, | |
461 | .set_events = _set_events, | |
462 | .get_events = _get_events, | |
463 | .clear_events = _clear_events, | |
464 | }, | |
465 | .type = { PEN_IETF, type }, | |
466 | .flags = flags, | |
467 | .request_id = request_id, | |
468 | .events = swima_events_create(), | |
469 | .ref = 1, | |
470 | ); | |
471 | ||
472 | return &this->public.pa_tnc_attribute; | |
473 | } | |
474 | ||
475 | ||
476 | /** | |
477 | * Described in header. | |
478 | */ | |
479 | pa_tnc_attr_t *ietf_swima_attr_sw_ev_create_from_data(size_t length, | |
480 | chunk_t data, bool sw_id_only) | |
481 | { | |
482 | private_ietf_swima_attr_sw_ev_t *this; | |
483 | ietf_attr_t type; | |
484 | ||
485 | type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS; | |
486 | ||
487 | INIT(this, | |
488 | .public = { | |
489 | .pa_tnc_attribute = { | |
490 | .get_type = _get_type, | |
491 | .get_value = _get_value, | |
492 | .get_noskip_flag = _get_noskip_flag, | |
493 | .set_noskip_flag = _set_noskip_flag, | |
494 | .build = _build, | |
495 | .process = _process, | |
496 | .add_segment = _add_segment, | |
497 | .get_ref = _get_ref, | |
498 | .destroy = _destroy, | |
499 | }, | |
500 | .get_flags = _get_flags, | |
501 | .get_request_id = _get_request_id, | |
502 | .get_event_count = _get_event_count, | |
503 | .set_events = _set_events, | |
504 | .get_events = _get_events, | |
505 | .clear_events = _clear_events, | |
506 | }, | |
507 | .type = { PEN_IETF, type }, | |
508 | .length = length, | |
509 | .segment = chunk_clone(data), | |
510 | .events = swima_events_create(), | |
511 | .ref = 1, | |
512 | ); | |
513 | ||
514 | /* received either complete attribute value or first segment */ | |
515 | this->value = this->segment; | |
516 | ||
517 | return &this->public.pa_tnc_attribute; | |
518 | } |