aboutsummaryrefslogtreecommitdiffstats
path: root/src/libimcv/seg/seg_env.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libimcv/seg/seg_env.c')
-rw-r--r--src/libimcv/seg/seg_env.c131
1 files changed, 91 insertions, 40 deletions
diff --git a/src/libimcv/seg/seg_env.c b/src/libimcv/seg/seg_env.c
index 1ec8a367b..b961589bf 100644
--- a/src/libimcv/seg/seg_env.c
+++ b/src/libimcv/seg/seg_env.c
@@ -17,6 +17,7 @@
#include "imcv.h"
#include "pa_tnc/pa_tnc_msg.h"
+#include "ietf/ietf_attr_pa_tnc_error.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include <utils/debug.h>
@@ -48,20 +49,25 @@ struct private_seg_env_t {
pa_tnc_attr_t *base_attr;
/**
- * Maximum PA-TNC attribute segment size
+ * Base Attribute Info to be used for PA-TNC error messages
*/
- uint32_t max_seg_size;
+ u_char base_attr_info[8];
/**
- * TRUE if attribute is assembled from data
+ * Base Attribute needs more segment data
*/
- bool from_data;
+ bool need_more;
/**
- * Remaining attribute data to be sent or received data being accumulated
+ * Pointer to remaining attribute data to be sent
*/
chunk_t data;
+ /**
+ * Maximum PA-TNC attribute segment size
+ */
+ uint32_t max_seg_size;
+
};
METHOD(seg_env_t, get_base_attr_id, uint32_t,
@@ -71,33 +77,15 @@ METHOD(seg_env_t, get_base_attr_id, uint32_t,
}
METHOD(seg_env_t, get_base_attr, pa_tnc_attr_t*,
- private_seg_env_t *this, pa_tnc_attr_t** error)
+ private_seg_env_t *this)
{
- *error = NULL;
+ return this->need_more ? NULL : this->base_attr->get_ref(this->base_attr);
+}
- if (!this->base_attr)
- {
- bio_writer_t *writer;
- bio_reader_t *reader;
- chunk_t msg_info;
- uint32_t offset = 0;
-
- writer = bio_writer_create(8);
- writer->write_uint8 (writer, PA_TNC_VERSION);
- writer->write_uint24(writer, PA_TNC_RESERVED);
- writer->write_uint8 (writer, BASE_ATTR_ID_PREFIX);
- writer->write_uint24(writer, this->base_attr_id);
- msg_info = writer->extract_buf(writer);
- writer->destroy(writer);
-
- reader = bio_reader_create(this->data);
- this->base_attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
- reader, &offset, msg_info, error);
- chunk_free(&msg_info);
- reader->destroy(reader);
- }
-
- return this->base_attr ? this->base_attr->get_ref(this->base_attr) : NULL;
+METHOD(seg_env_t, get_base_attr_info, chunk_t,
+ private_seg_env_t *this)
+{
+ return chunk_create(this->base_attr_info, 8);
}
METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
@@ -175,19 +163,44 @@ METHOD(seg_env_t, next_segment, pa_tnc_attr_t*,
return seg_env_attr;
}
-METHOD(seg_env_t, add_segment, void,
- private_seg_env_t *this, chunk_t segment_data)
+METHOD(seg_env_t, add_segment, bool,
+ private_seg_env_t *this, chunk_t segment, pa_tnc_attr_t **error)
{
- this->data = chunk_cat("mc", this->data, segment_data);
+ pen_type_t type, error_code;
+ uint32_t attr_offset;
+ chunk_t msg_info;
+ status_t status;
+
+ /* not all attributes might have implemented the add_segment method */
+ if (!this->base_attr->add_segment)
+ {
+ return FALSE;
+ }
+ this->base_attr->add_segment(this->base_attr, segment);
+ status = this->base_attr->process(this->base_attr, &attr_offset);
+
+ if (status != SUCCESS && status != NEED_MORE)
+ {
+ type = this->base_attr->get_type(this->base_attr);
+ if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
+ {
+ /* error while processing a PA-TNC error attribute - abort */
+ return FALSE;
+ }
+ error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+ msg_info = get_base_attr_info(this);
+ *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+ msg_info, PA_TNC_ATTR_HEADER_SIZE + attr_offset);
+ return FALSE;
+ }
+ this->need_more = (status == NEED_MORE);
+
+ return TRUE;
}
METHOD(seg_env_t, destroy, void,
private_seg_env_t *this)
{
- if (this->from_data)
- {
- chunk_free(&this->data);
- }
DESTROY_IF(this->base_attr);
free(this);
}
@@ -218,6 +231,7 @@ seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
.public = {
.get_base_attr_id = _get_base_attr_id,
.get_base_attr = _get_base_attr,
+ .get_base_attr_info = _get_base_attr_info,
.first_segment = _first_segment,
.next_segment = _next_segment,
.add_segment = _add_segment,
@@ -236,14 +250,20 @@ seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
* See header
*/
seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
- uint32_t max_seg_size)
+ uint32_t max_seg_size, pa_tnc_attr_t** error)
{
private_seg_env_t *this;
+ pen_type_t type, error_code;
+ bio_reader_t *reader;
+ chunk_t msg_info;
+ uint32_t offset = 0, attr_offset;
+ status_t status;
INIT(this,
.public = {
.get_base_attr_id = _get_base_attr_id,
.get_base_attr = _get_base_attr,
+ .get_base_attr_info = _get_base_attr_info,
.first_segment = _first_segment,
.next_segment = _next_segment,
.add_segment = _add_segment,
@@ -251,10 +271,41 @@ seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
},
.base_attr_id = base_attr_id,
.max_seg_size = max_seg_size,
- .data = chunk_clone(data),
- .from_data = TRUE,
);
+ /* create info field to be used by PA-TNC error messages */
+ memset(this->base_attr_info, 0xff, 4);
+ htoun32(this->base_attr_info + 4, base_attr_id);
+ msg_info = get_base_attr_info(this);
+
+ /* extract from base attribute segment from data */
+ reader = bio_reader_create(data);
+ this->base_attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
+ reader, TRUE, &offset, msg_info, error);
+ reader->destroy(reader);
+
+ if (!this->base_attr)
+ {
+ destroy(this);
+ return NULL;
+ }
+ status = this->base_attr->process(this->base_attr, &attr_offset);
+
+ if (status != SUCCESS && status != NEED_MORE)
+ {
+ type = this->base_attr->get_type(this->base_attr);
+ if (!(type.vendor_id == PEN_IETF &&
+ type.type == IETF_ATTR_PA_TNC_ERROR))
+ {
+ error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+ *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+ msg_info, PA_TNC_ATTR_HEADER_SIZE + attr_offset);
+ }
+ destroy(this);
+ return NULL;
+ }
+ this->need_more = (status == NEED_MORE);
+
return &this->public;
}