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_inv.h"
17 #include "swima/swima_record.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>
25 typedef struct private_ietf_swima_attr_sw_inv_t private_ietf_swima_attr_sw_inv_t
;
28 * Software [Identifier] Inventory
29 * see sections 5.8/5.10 of IETF SW Inventory Message and Attributes for PA-TNC
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 * | Flags | Software Identifier Count |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | Request ID Copy / Subscription ID |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Record Identifier |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Data Model Type PEN |Data Model Type|
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | Source ID Num | Software Identifier Length |Software Id (v)|
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * | Software Locator Length | Software Locator (Var. Len) |
49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * Software Inventory only
52 * see section 5.10 of IETF SW Inventory Message and Attributes for PA-TNC
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 * | Record (Variable length) |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 * Private data of an ietf_swima_attr_sw_inv_t object.
64 struct private_ietf_swima_attr_sw_inv_t
{
67 * Public members of ietf_swima_attr_sw_inv_t
69 ietf_swima_attr_sw_inv_t
public;
72 * Vendor-specific attribute type
77 * Length of attribute value
82 * Offset up to which attribute value has been processed
87 * Current position of attribute value pointer
92 * Contains complete attribute or current segment
112 * Number of unprocessed software inventory evidence records in attribute
114 uint32_t record_count
;
117 * SWID Tag ID Inventory
119 swima_inventory_t
*inventory
;
127 METHOD(pa_tnc_attr_t
, get_type
, pen_type_t
,
128 private_ietf_swima_attr_sw_inv_t
*this)
133 METHOD(pa_tnc_attr_t
, get_value
, chunk_t
,
134 private_ietf_swima_attr_sw_inv_t
*this)
139 METHOD(pa_tnc_attr_t
, get_noskip_flag
, bool,
140 private_ietf_swima_attr_sw_inv_t
*this)
142 return this->noskip_flag
;
145 METHOD(pa_tnc_attr_t
, set_noskip_flag
,void,
146 private_ietf_swima_attr_sw_inv_t
*this, bool noskip
)
148 this->noskip_flag
= noskip
;
151 METHOD(pa_tnc_attr_t
, build
, void,
152 private_ietf_swima_attr_sw_inv_t
*this)
154 bio_writer_t
*writer
;
155 swima_record_t
*sw_record
;
156 chunk_t sw_id
, sw_locator
, record
;
157 pen_type_t data_model
;
158 uint32_t record_id
, last_eid
, eid_epoch
;
160 enumerator_t
*enumerator
;
166 last_eid
= this->inventory
->get_eid(this->inventory
, &eid_epoch
);
168 writer
= bio_writer_create(IETF_SWIMA_SW_INV_MIN_SIZE
);
169 writer
->write_uint8 (writer
, this->flags
);
170 writer
->write_uint24(writer
, this->inventory
->get_count(this->inventory
));
171 writer
->write_uint32(writer
, this->request_id
);
172 writer
->write_uint32(writer
, eid_epoch
);
173 writer
->write_uint32(writer
, last_eid
);
175 enumerator
= this->inventory
->create_enumerator(this->inventory
);
176 while (enumerator
->enumerate(enumerator
, &sw_record
))
178 record_id
= sw_record
->get_record_id(sw_record
);
179 data_model
= sw_record
->get_data_model(sw_record
);
180 source_id
= sw_record
->get_source_id(sw_record
);
181 sw_id
= sw_record
->get_sw_id(sw_record
, &sw_locator
);
183 writer
->write_uint32(writer
, record_id
);
184 writer
->write_uint24(writer
, data_model
.vendor_id
);
185 writer
->write_uint8 (writer
, data_model
.type
);
186 writer
->write_uint8 (writer
, source_id
);
187 writer
->write_data16(writer
, sw_id
);
188 writer
->write_data16(writer
, sw_locator
);
190 if (this->type
.type
== IETF_ATTR_SW_INVENTORY
)
192 record
= sw_record
->get_record(sw_record
);
193 writer
->write_data32(writer
, record
);
196 enumerator
->destroy(enumerator
);
198 this->value
= writer
->extract_buf(writer
);
199 this->segment
= this->value
;
200 this->length
= this->value
.len
;
201 writer
->destroy(writer
);
204 METHOD(pa_tnc_attr_t
, process
, status_t
,
205 private_ietf_swima_attr_sw_inv_t
*this, uint32_t *offset
)
207 bio_reader_t
*reader
;
208 uint32_t data_model_pen
, record_id
, last_eid
, eid_epoch
;
209 uint8_t data_model_type
, source_id
;
210 pen_type_t data_model
;
211 chunk_t sw_id
, sw_locator
, record
;
212 swima_record_t
*sw_record
;
213 status_t status
= NEED_MORE
;
215 if (this->offset
== 0)
217 if (this->length
< IETF_SWIMA_SW_INV_MIN_SIZE
)
219 DBG1(DBG_TNC
, "insufficient data for %N/%N", pen_names
, PEN_IETF
,
220 ietf_attr_names
, this->type
.type
);
221 *offset
= this->offset
;
224 if (this->value
.len
< IETF_SWIMA_SW_INV_MIN_SIZE
)
228 reader
= bio_reader_create(this->value
);
229 reader
->read_uint8 (reader
, &this->flags
);
230 reader
->read_uint24(reader
, &this->record_count
);
231 reader
->read_uint32(reader
, &this->request_id
);
232 reader
->read_uint32(reader
, &eid_epoch
);
233 reader
->read_uint32(reader
, &last_eid
);
234 this->offset
= IETF_SWIMA_SW_INV_MIN_SIZE
;
235 this->value
= reader
->peek(reader
);
236 this->inventory
->set_eid(this->inventory
, last_eid
, eid_epoch
);
237 reader
->destroy(reader
);
240 reader
= bio_reader_create(this->value
);
242 while (this->record_count
)
244 if (!reader
->read_uint32(reader
, &record_id
) ||
245 !reader
->read_uint24(reader
, &data_model_pen
) ||
246 !reader
->read_uint8 (reader
, &data_model_type
) ||
247 !reader
->read_uint8 (reader
, &source_id
) ||
248 !reader
->read_data16(reader
, &sw_id
) ||
249 !reader
->read_data16(reader
, &sw_locator
))
253 record
= chunk_empty
;
255 if (this->type
.type
== IETF_ATTR_SW_INVENTORY
&&
256 !reader
->read_data32(reader
, &record
))
260 data_model
= pen_type_create(data_model_pen
, data_model_type
);
261 sw_record
= swima_record_create(record_id
, sw_id
, sw_locator
);
262 sw_record
->set_data_model(sw_record
, data_model
);
263 sw_record
->set_source_id(sw_record
, source_id
);
264 sw_record
->set_record(sw_record
, record
);
265 this->inventory
->add(this->inventory
, sw_record
);
266 this->offset
+= this->value
.len
- reader
->remaining(reader
);
267 this->value
= reader
->peek(reader
);
269 /* at least one software inventory evidence record was processed */
271 this->record_count
--;
274 if (this->length
== this->offset
)
280 DBG1(DBG_TNC
, "inconsistent length for %N/%N", pen_names
, PEN_IETF
,
281 ietf_attr_names
, this->type
.type
);
282 *offset
= this->offset
;
287 reader
->destroy(reader
);
291 METHOD(pa_tnc_attr_t
, add_segment
, void,
292 private_ietf_swima_attr_sw_inv_t
*this, chunk_t segment
)
294 this->value
= chunk_cat("cc", this->value
, segment
);
295 chunk_free(&this->segment
);
296 this->segment
= this->value
;
299 METHOD(pa_tnc_attr_t
, get_ref
, pa_tnc_attr_t
*,
300 private_ietf_swima_attr_sw_inv_t
*this)
303 return &this->public.pa_tnc_attribute
;
306 METHOD(pa_tnc_attr_t
, destroy
, void,
307 private_ietf_swima_attr_sw_inv_t
*this)
309 if (ref_put(&this->ref
))
311 this->inventory
->destroy(this->inventory
);
312 free(this->segment
.ptr
);
317 METHOD(ietf_swima_attr_sw_inv_t
, get_flags
, uint8_t,
318 private_ietf_swima_attr_sw_inv_t
*this)
323 METHOD(ietf_swima_attr_sw_inv_t
, get_request_id
, uint32_t,
324 private_ietf_swima_attr_sw_inv_t
*this)
326 return this->request_id
;
329 METHOD(ietf_swima_attr_sw_inv_t
, get_record_count
, uint32_t,
330 private_ietf_swima_attr_sw_inv_t
*this)
332 return this->record_count
;
335 METHOD(ietf_swima_attr_sw_inv_t
, set_inventory
, void,
336 private_ietf_swima_attr_sw_inv_t
*this, swima_inventory_t
*inventory
)
338 this->inventory
->destroy(this->inventory
);
339 this->inventory
= inventory
->get_ref(inventory
);
342 METHOD(ietf_swima_attr_sw_inv_t
, get_inventory
, swima_inventory_t
*,
343 private_ietf_swima_attr_sw_inv_t
*this)
345 return this->inventory
;
348 METHOD(ietf_swima_attr_sw_inv_t
, clear_inventory
, void,
349 private_ietf_swima_attr_sw_inv_t
*this)
351 this->inventory
->clear(this->inventory
);
355 * Described in header.
357 pa_tnc_attr_t
*ietf_swima_attr_sw_inv_create(uint8_t flags
, uint32_t request_id
,
360 private_ietf_swima_attr_sw_inv_t
*this;
363 type
= sw_id_only ? IETF_ATTR_SW_ID_INVENTORY
: IETF_ATTR_SW_INVENTORY
;
367 .pa_tnc_attribute
= {
368 .get_type
= _get_type
,
369 .get_value
= _get_value
,
370 .get_noskip_flag
= _get_noskip_flag
,
371 .set_noskip_flag
= _set_noskip_flag
,
374 .add_segment
= _add_segment
,
378 .get_flags
= _get_flags
,
379 .get_request_id
= _get_request_id
,
380 .get_record_count
= _get_record_count
,
381 .set_inventory
= _set_inventory
,
382 .get_inventory
= _get_inventory
,
383 .clear_inventory
= _clear_inventory
,
385 .type
= { PEN_IETF
, type
},
387 .request_id
= request_id
,
388 .inventory
= swima_inventory_create(),
392 return &this->public.pa_tnc_attribute
;
397 * Described in header.
399 pa_tnc_attr_t
*ietf_swima_attr_sw_inv_create_from_data(size_t length
,
400 chunk_t data
, bool sw_id_only
)
402 private_ietf_swima_attr_sw_inv_t
*this;
405 type
= sw_id_only ? IETF_ATTR_SW_ID_INVENTORY
: IETF_ATTR_SW_INVENTORY
;
409 .pa_tnc_attribute
= {
410 .get_type
= _get_type
,
411 .get_value
= _get_value
,
412 .get_noskip_flag
= _get_noskip_flag
,
413 .set_noskip_flag
= _set_noskip_flag
,
416 .add_segment
= _add_segment
,
420 .get_flags
= _get_flags
,
421 .get_request_id
= _get_request_id
,
422 .get_record_count
= _get_record_count
,
423 .set_inventory
= _set_inventory
,
424 .get_inventory
= _get_inventory
,
425 .clear_inventory
= _clear_inventory
,
427 .type
= { PEN_IETF
, type
},
429 .segment
= chunk_clone(data
),
430 .inventory
= swima_inventory_create(),
434 /* received either complete attribute value or first segment */
435 this->value
= this->segment
;
437 return &this->public.pa_tnc_attribute
;