2 * Copyright (C) 2011-2014 Andreas Steffen
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "pa_tnc_attr_manager.h"
21 #include "pa_tnc_attr.h"
22 #include "ietf/ietf_attr_pa_tnc_error.h"
24 #include <collections/linked_list.h>
25 #include <utils/debug.h>
27 typedef struct private_pa_tnc_attr_manager_t private_pa_tnc_attr_manager_t
;
28 typedef struct entry_t entry_t
;
32 enum_name_t
*attr_names
;
33 pa_tnc_attr_create_t attr_create
;
37 * Private data of a pa_tnc_attr_manager_t object.
40 struct private_pa_tnc_attr_manager_t
{
43 * Public pa_tnc_attr_manager_t interface.
45 pa_tnc_attr_manager_t
public;
48 * List of PA-TNC vendor attributes
53 METHOD(pa_tnc_attr_manager_t
, add_vendor
, void,
54 private_pa_tnc_attr_manager_t
*this, pen_t vendor_id
,
55 pa_tnc_attr_create_t attr_create
, enum_name_t
*attr_names
)
59 entry
= malloc_thing(entry_t
);
60 entry
->vendor_id
= vendor_id
;
61 entry
->attr_create
= attr_create
;
62 entry
->attr_names
= attr_names
;
64 this->list
->insert_last(this->list
, entry
);
65 DBG2(DBG_TNC
, "added %N attributes", pen_names
, vendor_id
);
68 METHOD(pa_tnc_attr_manager_t
, remove_vendor
, void,
69 private_pa_tnc_attr_manager_t
*this, pen_t vendor_id
)
71 enumerator_t
*enumerator
;
74 enumerator
= this->list
->create_enumerator(this->list
);
75 while (enumerator
->enumerate(enumerator
, &entry
))
77 if (entry
->vendor_id
== vendor_id
)
79 this->list
->remove_at(this->list
, enumerator
);
81 DBG2(DBG_TNC
, "removed %N attributes", pen_names
, vendor_id
);
84 enumerator
->destroy(enumerator
);
87 METHOD(pa_tnc_attr_manager_t
, get_names
, enum_name_t
*,
88 private_pa_tnc_attr_manager_t
*this, pen_t vendor_id
)
90 enumerator_t
*enumerator
;
92 enum_name_t
*attr_names
= NULL
;
94 enumerator
= this->list
->create_enumerator(this->list
);
95 while (enumerator
->enumerate(enumerator
, &entry
))
97 if (entry
->vendor_id
== vendor_id
)
99 attr_names
= entry
->attr_names
;
103 enumerator
->destroy(enumerator
);
112 * 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
113 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114 * | Flags | PA-TNC Attribute Vendor ID |
115 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 * | PA-TNC Attribute Type |
117 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118 * | PA-TNC Attribute Length |
119 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120 * | Attribute Value (Variable Length) |
121 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124 METHOD(pa_tnc_attr_manager_t
, create
, pa_tnc_attr_t
*,
125 private_pa_tnc_attr_manager_t
*this, bio_reader_t
*reader
, bool segmented
,
126 uint32_t *offset
, chunk_t msg_info
, pa_tnc_attr_t
**error
)
129 uint32_t type
, length
, value_len
;
131 ietf_attr_pa_tnc_error_t
*error_attr
;
133 pen_type_t unsupported_type
;
134 pen_type_t error_code
= { PEN_IETF
, PA_ERROR_INVALID_PARAMETER
};
135 pa_tnc_attr_t
*attr
= NULL
;
136 enumerator_t
*enumerator
;
139 /* properly initialize error return argument in case of no error */
142 if (reader
->remaining(reader
) < PA_TNC_ATTR_HEADER_SIZE
)
144 DBG1(DBG_TNC
, "insufficient bytes for PA-TNC attribute header");
145 *error
= ietf_attr_pa_tnc_error_create_with_offset(error_code
,
149 reader
->read_uint8 (reader
, &flags
);
150 reader
->read_uint24(reader
, &vendor_id
);
151 reader
->read_uint32(reader
, &type
);
152 reader
->read_uint32(reader
, &length
);
154 imcv_list_pa_tnc_attribute_type("processing", vendor_id
, type
);
156 if (length
< PA_TNC_ATTR_HEADER_SIZE
)
158 DBG1(DBG_TNC
, "%u bytes too small for PA-TNC attribute length",
160 *error
= ietf_attr_pa_tnc_error_create_with_offset(error_code
,
161 msg_info
, *offset
+ PA_TNC_ATTR_INFO_SIZE
);
164 length
-= PA_TNC_ATTR_HEADER_SIZE
;
165 value_len
= segmented
? reader
->remaining(reader
) : length
;
167 if (!reader
->read_data(reader
, value_len
, &value
))
169 DBG1(DBG_TNC
, "insufficient bytes for PA-TNC attribute value");
170 *error
= ietf_attr_pa_tnc_error_create_with_offset(error_code
,
171 msg_info
, *offset
+ PA_TNC_ATTR_INFO_SIZE
);
174 DBG3(DBG_TNC
, "%B", &value
);
176 if (vendor_id
== PEN_RESERVED
)
178 *error
= ietf_attr_pa_tnc_error_create_with_offset(error_code
,
179 msg_info
, *offset
+ 1);
182 if (type
== IETF_ATTR_RESERVED
)
184 *error
= ietf_attr_pa_tnc_error_create_with_offset(error_code
,
185 msg_info
, *offset
+ 4);
189 /* check if the attribute type is registered */
190 enumerator
= this->list
->create_enumerator(this->list
);
191 while (enumerator
->enumerate(enumerator
, &entry
))
193 if (entry
->vendor_id
== vendor_id
)
195 if (entry
->attr_create
)
197 attr
= entry
->attr_create(type
, length
, value
);
202 enumerator
->destroy(enumerator
);
206 if (!(flags
& PA_TNC_ATTR_FLAG_NOSKIP
))
208 DBG1(DBG_TNC
, "skipping unsupported PA-TNC attribute");
209 (*offset
) += PA_TNC_ATTR_HEADER_SIZE
+ length
;
213 DBG1(DBG_TNC
, "unsupported PA-TNC attribute with NOSKIP flag");
214 unsupported_type
= pen_type_create(vendor_id
, type
);
215 error_code
= pen_type_create(PEN_IETF
, PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
);
216 *error
= ietf_attr_pa_tnc_error_create(error_code
, msg_info
);
217 error_attr
= (ietf_attr_pa_tnc_error_t
*)(*error
);
218 error_attr
->set_unsupported_attr(error_attr
, flags
, unsupported_type
);
221 (*offset
) += PA_TNC_ATTR_HEADER_SIZE
;
226 METHOD(pa_tnc_attr_manager_t
, construct
, pa_tnc_attr_t
*,
227 private_pa_tnc_attr_manager_t
*this, pen_t vendor_id
, uint32_t type
,
230 enum_name_t
*pa_attr_names
;
231 pa_tnc_attr_t
*attr
= NULL
;
232 enumerator_t
*enumerator
;
235 pa_attr_names
= imcv_pa_tnc_attributes
->get_names(imcv_pa_tnc_attributes
,
239 DBG2(DBG_TNC
, "generating PA-TNC attribute type '%N/%N' "
240 "0x%06x/0x%08x", pen_names
, vendor_id
,
241 pa_attr_names
, type
, vendor_id
, type
);
245 DBG2(DBG_TNC
, "generating PA-TNC attribute type '%N' "
246 "0x%06x/0x%08x", pen_names
, vendor_id
,
249 enumerator
= this->list
->create_enumerator(this->list
);
250 while (enumerator
->enumerate(enumerator
, &entry
))
252 if (entry
->vendor_id
== vendor_id
)
254 if (entry
->attr_create
)
256 attr
= entry
->attr_create(type
, value
.len
, value
);
261 enumerator
->destroy(enumerator
);
265 METHOD(pa_tnc_attr_manager_t
, destroy
, void,
266 private_pa_tnc_attr_manager_t
*this)
268 this->list
->destroy_function(this->list
, free
);
275 pa_tnc_attr_manager_t
*pa_tnc_attr_manager_create(void)
277 private_pa_tnc_attr_manager_t
*this;
281 .add_vendor
= _add_vendor
,
282 .remove_vendor
= _remove_vendor
,
283 .get_names
= _get_names
,
285 .construct
= _construct
,
288 .list
= linked_list_create(),
291 return &this->public;