aboutsummaryrefslogtreecommitdiffstats
path: root/src/libimcv/seg
diff options
context:
space:
mode:
authorAndreas Steffen <andreas.steffen@strongswan.org>2014-08-28 21:14:13 +0200
committerAndreas Steffen <andreas.steffen@strongswan.org>2014-10-05 12:55:37 +0200
commite911ac9a5f9f605785613df04b0eeabb47121aa4 (patch)
tree1c0310a1d2a6db8af75b5ebc6dba09d602085b7b /src/libimcv/seg
parent89d12654b343e92fc7a4f511b32475402a5120ed (diff)
downloadstrongswan-e911ac9a5f9f605785613df04b0eeabb47121aa4.tar.bz2
strongswan-e911ac9a5f9f605785613df04b0eeabb47121aa4.tar.xz
Implemented IF-M segmentation
Diffstat (limited to 'src/libimcv/seg')
-rw-r--r--src/libimcv/seg/seg_contract.c413
-rw-r--r--src/libimcv/seg/seg_contract.h152
-rw-r--r--src/libimcv/seg/seg_contract_manager.c91
-rw-r--r--src/libimcv/seg/seg_contract_manager.h61
-rw-r--r--src/libimcv/seg/seg_env.c261
-rw-r--r--src/libimcv/seg/seg_env.h108
6 files changed, 1086 insertions, 0 deletions
diff --git a/src/libimcv/seg/seg_contract.c b/src/libimcv/seg/seg_contract.c
new file mode 100644
index 000000000..589d6d1cd
--- /dev/null
+++ b/src/libimcv/seg/seg_contract.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "seg_contract.h"
+#include "seg_env.h"
+
+#include <utils/debug.h>
+#include <bio/bio_writer.h>
+
+#include <tncif_pa_subtypes.h>
+
+#include <tcg/seg/tcg_seg_attr_seg_env.h>
+
+typedef struct private_seg_contract_t private_seg_contract_t;
+
+/**
+ * Private data of a seg_contract_t object.
+ */
+struct private_seg_contract_t {
+
+ /**
+ * Public seg_contract_t interface.
+ */
+ seg_contract_t public;
+
+ /**
+ * PA-TNC message type
+ */
+ pen_type_t msg_type;
+
+ /**
+ * Maximum PA-TNC attribute size
+ */
+ uint32_t max_attr_size;
+
+ /**
+ * Maximum PA-TNC attribute segment size
+ */
+ uint32_t max_seg_size;
+
+ /**
+ * Maximum PA-TNC attribute segment size
+ */
+ uint32_t last_base_attr_id;
+
+ /**
+ * List of attribute segment envelopes
+ */
+
+ linked_list_t *seg_envs;
+
+ /**
+ * Is this a null contract?
+ */
+ bool is_null;
+
+ /**
+ * Contract role
+ */
+ bool is_issuer;
+
+ /**
+ * Issuer ID (either IMV ID or IMC ID)
+ */
+ TNC_UInt32 issuer_id;
+
+ /**
+ * IMC/IMV role
+ */
+ bool is_imc;
+
+};
+
+METHOD(seg_contract_t, get_msg_type, pen_type_t,
+ private_seg_contract_t *this)
+{
+ return this->msg_type;
+}
+
+METHOD(seg_contract_t, set_max_size, void,
+ private_seg_contract_t *this, uint32_t max_attr_size, uint32_t max_seg_size)
+{
+ this->max_attr_size = max_attr_size;
+ this->max_seg_size = max_seg_size;
+ this->is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
+ max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE;
+}
+
+METHOD(seg_contract_t, get_max_size, void,
+ private_seg_contract_t *this, uint32_t *max_attr_size, uint32_t *max_seg_size)
+{
+ if (max_attr_size)
+ {
+ *max_attr_size = this->max_attr_size;
+ }
+ if (max_seg_size)
+ {
+ *max_seg_size = this->max_seg_size;
+ }
+}
+
+METHOD(seg_contract_t, check_size, bool,
+ private_seg_contract_t *this, pa_tnc_attr_t *attr, bool *oversize)
+{
+ chunk_t attr_value;
+ size_t attr_len;
+
+ *oversize = FALSE;
+
+ if (this->is_null)
+ {
+ /* null segmentation contract */
+ return FALSE;
+ }
+ attr->build(attr);
+ attr_value = attr->get_value(attr);
+ attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
+
+ if (attr_len > this->max_attr_size)
+ {
+ /* oversize attribute */
+ *oversize = TRUE;
+ return FALSE;
+ }
+ if (this->max_seg_size == SEG_CONTRACT_NO_FRAGMENTATION)
+ {
+ /* no fragmentation wanted */
+ return FALSE;
+ }
+ return attr_value.len > this->max_seg_size + TCG_SEG_ATTR_SEG_ENV_HEADER;
+}
+
+METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
+ private_seg_contract_t *this, pa_tnc_attr_t *attr)
+{
+ seg_env_t *seg_env;
+
+ seg_env = seg_env_create(++this->last_base_attr_id, attr,
+ this->max_seg_size);
+ if (!seg_env)
+ {
+ return NULL;
+ }
+ this->seg_envs->insert_last(this->seg_envs, seg_env);
+
+ return seg_env->first_segment(seg_env);
+}
+
+METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
+ private_seg_contract_t *this, uint32_t base_attr_id)
+{
+ pa_tnc_attr_t *seg_env_attr = NULL;
+ seg_env_t *seg_env;
+ bool last_segment = FALSE;
+ enumerator_t *enumerator;
+
+ enumerator = this->seg_envs->create_enumerator(this->seg_envs);
+ while (enumerator->enumerate(enumerator, &seg_env))
+ {
+ if (seg_env->get_base_attr_id(seg_env) == base_attr_id)
+ {
+ seg_env_attr = seg_env->next_segment(seg_env, &last_segment);
+ if (!seg_env_attr)
+ {
+ break;
+ }
+ if (last_segment)
+ {
+ this->seg_envs->remove_at(this->seg_envs, enumerator);
+ seg_env->destroy(seg_env);
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return seg_env_attr;
+}
+
+METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
+ private_seg_contract_t *this, pa_tnc_attr_t *attr, pa_tnc_attr_t **error,
+ bool *more)
+{
+ tcg_seg_attr_seg_env_t *seg_env_attr;
+ seg_env_t *current, *seg_env = NULL;
+ pa_tnc_attr_t *base_attr;
+ uint32_t base_attr_id;
+ uint8_t flags;
+ chunk_t segment_data;
+ enumerator_t *enumerator;
+
+ seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
+ base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
+ segment_data = seg_env_attr->get_segment(seg_env_attr, &flags);
+ *more = flags & SEG_ENV_FLAG_MORE;
+ *error = NULL;
+
+ enumerator = this->seg_envs->create_enumerator(this->seg_envs);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (current->get_base_attr_id(current) == base_attr_id)
+ {
+ seg_env = current;
+ if (!(*more))
+ {
+ this->seg_envs->remove_at(this->seg_envs, enumerator);
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (flags & SEG_ENV_FLAG_START)
+ {
+ if (seg_env)
+ {
+ DBG1(DBG_TNC, "base attribute ID %d is already in use",
+ base_attr_id);
+ return NULL;
+ }
+ DBG2(DBG_TNC, "received first segment for base attribute ID %d "
+ "(%d bytes)", base_attr_id, segment_data.len);
+ seg_env = seg_env_create_from_data(base_attr_id, segment_data,
+ this->max_seg_size);
+ this->seg_envs->insert_last(this->seg_envs, seg_env);
+ }
+ else
+ {
+ if (!seg_env)
+ {
+ DBG1(DBG_TNC, "base attribute ID %d not found", base_attr_id);
+ return NULL;
+ }
+ DBG2(DBG_TNC, "received %s segment for base attribute ID %d "
+ "(%d bytes)", (*more) ? "next" : "last", base_attr_id,
+ segment_data.len);
+ seg_env->add_segment(seg_env, segment_data);
+ }
+ if (*more)
+ {
+ return NULL;
+ }
+ base_attr = seg_env->get_base_attr(seg_env, error);
+ seg_env->destroy(seg_env);
+
+ return base_attr;
+}
+
+
+METHOD(seg_contract_t, is_issuer, bool,
+ private_seg_contract_t *this)
+{
+ return this->is_issuer;
+}
+
+METHOD(seg_contract_t, is_null, bool,
+ private_seg_contract_t *this)
+{
+ return this->is_null;
+}
+
+METHOD(seg_contract_t, get_info_string, void,
+ private_seg_contract_t *this, char *buf, size_t len, bool request)
+{
+ enum_name_t *pa_subtype_names;
+ uint32_t msg_vid, msg_subtype;
+ char *pos = buf;
+ int written;
+
+ /* nul-terminate the string buffer */
+ buf[--len] = '\0';
+
+ if (this->is_issuer && request)
+ {
+ written = snprintf(pos, len, "%s %d requests",
+ this->is_imc ? "IMC" : "IMV", this->issuer_id);
+ }
+ else
+ {
+ written = snprintf(pos, len, "received");
+ }
+ if (written < 0 || written > len)
+ {
+ return;
+ }
+ pos += written;
+ len -= written;
+
+ written = snprintf(pos, len, " a %ssegmentation contract%s ",
+ this->is_null ? "null" : "", request ? "" : " response");
+ if (written < 0 || written > len)
+ {
+ return;
+ }
+ pos += written;
+ len -= written;
+
+ if (!this->is_issuer && this->issuer_id != TNC_IMVID_ANY)
+ {
+ written = snprintf(pos, len, "from %s %d ",
+ this->is_imc ? "IMV" : "IMC", this->issuer_id);
+ if (written < 0 || written > len)
+ {
+ return;
+ }
+ pos += written;
+ len -= written;
+ }
+
+ msg_vid = this->msg_type.vendor_id;
+ msg_subtype = this->msg_type.type;
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len, "for PA message type '%N/%N' "
+ "0x%06x/0x%08x", pen_names, msg_vid,
+ pa_subtype_names, msg_subtype, msg_vid,
+ msg_subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len, "for PA message type '%N' "
+ "0x%06x/0x%08x", pen_names, msg_vid,
+ msg_vid, msg_subtype);
+ }
+ if (written < 0 || written > len)
+ {
+ return;
+ }
+ pos += written;
+ len -= written;
+
+ if (!this->is_null)
+ {
+ written = snprintf(pos, len, "\n maximum attribute size of %u bytes "
+ "with ", this->max_attr_size);
+ if (written < 0 || written > len)
+ {
+ return;
+ }
+ pos += written;
+ len -= written;
+
+ if (this->max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE)
+ {
+ written = snprintf(pos, len, "no segmentation");
+ }
+ else
+ {
+ written = snprintf(pos, len, "maximum segment size of %u bytes",
+ this->max_seg_size);
+ }
+ }
+}
+
+METHOD(seg_contract_t, destroy, void,
+ private_seg_contract_t *this)
+{
+ this->seg_envs->destroy_offset(this->seg_envs, offsetof(seg_env_t, destroy));
+ free(this);
+}
+
+/**
+ * See header
+ */
+seg_contract_t *seg_contract_create(pen_type_t msg_type,
+ uint32_t max_attr_size,
+ uint32_t max_seg_size,
+ bool is_issuer, TNC_UInt32 issuer_id,
+ bool is_imc)
+{
+ private_seg_contract_t *this;
+
+ INIT(this,
+ .public = {
+ .get_msg_type = _get_msg_type,
+ .set_max_size = _set_max_size,
+ .get_max_size = _get_max_size,
+ .check_size = _check_size,
+ .first_segment = _first_segment,
+ .next_segment = _next_segment,
+ .add_segment = _add_segment,
+ .is_issuer = _is_issuer,
+ .is_null = _is_null,
+ .get_info_string = _get_info_string,
+ .destroy = _destroy,
+ },
+ .msg_type = msg_type,
+ .max_attr_size = max_attr_size,
+ .max_seg_size = max_seg_size,
+ .seg_envs = linked_list_create(),
+ .is_issuer = is_issuer,
+ .issuer_id = issuer_id,
+ .is_imc = is_imc,
+ .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
+ max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE,
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libimcv/seg/seg_contract.h b/src/libimcv/seg/seg_contract.h
new file mode 100644
index 000000000..48828c472
--- /dev/null
+++ b/src/libimcv/seg/seg_contract.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup seg_contract seg_contract
+ * @{ @ingroup libimcv
+ */
+
+#ifndef SEG_CONTRACT_H_
+#define SEG_CONTRACT_H_
+
+typedef struct seg_contract_t seg_contract_t;
+
+#include "pa_tnc/pa_tnc_attr.h"
+
+#include <library.h>
+#include <pen/pen.h>
+
+#include <tncif.h>
+
+#define SEG_CONTRACT_MAX_SIZE_VALUE 0xffffffff
+#define SEG_CONTRACT_NO_FRAGMENTATION SEG_CONTRACT_MAX_SIZE_VALUE
+
+/**
+ * Interface for a PA-TNC attribute segmentation contract
+ *
+ */
+struct seg_contract_t {
+
+ /**
+ * Get the PA-TNC message type.
+ *
+ * @return PA-TNC Message type
+ */
+ pen_type_t (*get_msg_type)(seg_contract_t *this);
+
+ /**
+ * Set maximum PA-TNC attribute and segment size in octets
+ *
+ * @param max_attr_size Maximum PA-TNC attribute size in octets
+ * @param max_seg_size Maximum PA-TNC attribute segment size in octets
+ */
+ void (*set_max_size)(seg_contract_t *this, uint32_t max_attr_size,
+ uint32_t max_seg_size);
+
+ /**
+ * Get maximum PA-TNC attribute and segment size in octets
+ *
+ * @param max_attr_size Maximum PA-TNC attribute size in octets
+ * @param max_seg_size Maximum PA-TNC attribute segment size in octets
+ */
+ void (*get_max_size)(seg_contract_t *this, uint32_t *max_attr_size,
+ uint32_t *max_seg_size);
+
+ /**
+ * Check if a PA-TNC attribute must be segmented or is oversized
+ *
+ * @param attr PA-TNC attribute to be checked
+ * @param oversize PA-TNC attribute is larger than maximum size
+ * @return TRUE if PA-TNC attribute must be segmented
+ */
+ bool (*check_size)(seg_contract_t *this, pa_tnc_attr_t *attr,
+ bool *oversize);
+
+ /**
+ * Generate first segment of a PA-TNC attribute according to the contract
+ *
+ * @param attr PA-TNC attribute to be segmented
+ * @return First segment envelope attribute
+ */
+ pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr);
+
+ /**
+ * Generate next segment of a PA-TNC attribute according to the contract
+ *
+ * @param base_attr_id Base Attribute ID
+ * @return Next segment envelope attribute
+ */
+ pa_tnc_attr_t* (*next_segment)(seg_contract_t *this, uint32_t base_attr_id);
+
+ /**
+ * Add an attribute segments until the PA-TNC attribute is reconstructed
+ *
+ * @param attr Segment envelope attribute
+ * @param error Error attribute if an error occurred or NULL
+ * @param more Need more segments
+ * @return Completed PA-TNC attribute or NULL
+ */
+ pa_tnc_attr_t* (*add_segment)(seg_contract_t *this,
+ pa_tnc_attr_t *attr, pa_tnc_attr_t **error,
+ bool *more);
+
+ /**
+ * Get contract role
+ *
+ * @return TRUE: contracting party (issuer),
+ * FALSE: contracted party
+ */
+ bool (*is_issuer)(seg_contract_t *this);
+
+ /**
+ * Is this a null contract ?
+ *
+ * @return TRUE if null contract
+ */
+ bool (*is_null)(seg_contract_t *this);
+
+ /**
+ * Get an info string about the contract
+ *
+ * @param buf String buffer of at least size len
+ * @param len Size of string buffer
+ * @param request TRUE if contract request, FALSE if response
+ */
+ void (*get_info_string)(seg_contract_t *this, char *buf, size_t len,
+ bool request);
+
+ /**
+ * Destroys a seg_contract_t object.
+ */
+ void (*destroy)(seg_contract_t *this);
+};
+
+/**
+ * Create a PA-TNC attribute segmentation contract
+ *
+ * @param msg_type PA-TNC message type
+ * @param max_attr_size Maximum PA-TNC attribute size in octets
+ * @param max_seg_size Maximum PA-TNC attribute segment size in octets
+ * @param is_issuer TRUE if issuer of the contract
+ * @param issuer_id IMC or IMV ID of issuer
+ * @param is_imc TRUE if IMC, FALSE if IMV
+ */
+seg_contract_t* seg_contract_create(pen_type_t msg_type,
+ uint32_t max_attr_size,
+ uint32_t max_seg_size,
+ bool is_issuer, TNC_UInt32 issuer_id,
+ bool is_imc);
+
+#endif /** SEG_CONTRACT_H_ @}*/
diff --git a/src/libimcv/seg/seg_contract_manager.c b/src/libimcv/seg/seg_contract_manager.c
new file mode 100644
index 000000000..d099436fc
--- /dev/null
+++ b/src/libimcv/seg/seg_contract_manager.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "seg_contract_manager.h"
+
+typedef struct private_seg_contract_manager_t private_seg_contract_manager_t;
+
+/**
+ * Private data of a seg_contract_manager_t object.
+ *
+ */
+struct private_seg_contract_manager_t {
+
+ /**
+ * Public seg_contract_manager_t interface.
+ */
+ seg_contract_manager_t public;
+
+ /**
+ * List of PA-TNC segmentation contracts
+ */
+ linked_list_t *contracts;
+
+};
+
+METHOD(seg_contract_manager_t, add_contract, void,
+ private_seg_contract_manager_t *this, seg_contract_t *contract)
+{
+ this->contracts->insert_last(this->contracts, contract);
+}
+
+METHOD(seg_contract_manager_t, get_contract, seg_contract_t*,
+ private_seg_contract_manager_t *this, pen_type_t msg_type, bool is_issuer)
+{
+ enumerator_t *enumerator;
+ seg_contract_t *contract, *found = NULL;
+
+ enumerator = this->contracts->create_enumerator(this->contracts);
+ while (enumerator->enumerate(enumerator, &contract))
+ {
+ if (contract->is_issuer(contract) == is_issuer &&
+ pen_type_equals(contract->get_msg_type(contract), msg_type))
+ {
+ found = contract;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+METHOD(seg_contract_manager_t, destroy, void,
+ private_seg_contract_manager_t *this)
+{
+ this->contracts->destroy_offset(this->contracts,
+ offsetof(seg_contract_t, destroy));
+ free(this);
+}
+
+/**
+ * See header
+ */
+seg_contract_manager_t *seg_contract_manager_create(void)
+{
+ private_seg_contract_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add_contract = _add_contract,
+ .get_contract = _get_contract,
+ .destroy = _destroy,
+ },
+ .contracts = linked_list_create(),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libimcv/seg/seg_contract_manager.h b/src/libimcv/seg/seg_contract_manager.h
new file mode 100644
index 000000000..355822d99
--- /dev/null
+++ b/src/libimcv/seg/seg_contract_manager.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup seg_contract_manager seg_contract_manager
+ * @{ @ingroup libimcv
+ */
+
+#ifndef SEG_CONTRACT_MANAGER_H_
+#define SEG_CONTRACT_MANAGER_H_
+
+typedef struct seg_contract_manager_t seg_contract_manager_t;
+
+#include "seg_contract.h"
+
+/**
+ * Interface for a PA-TNC attribute segmentation contract manager
+ *
+ */
+struct seg_contract_manager_t {
+
+ /**
+ * Add segmentation contract
+ *
+ * @param contract Segmentation contract to be added
+ */
+ void (*add_contract)(seg_contract_manager_t *this, seg_contract_t *contract);
+
+ /**
+ * Get segmentation contract
+ *
+ * @param msg_type PA-TNC message type governed by contract
+ * @param is_issuer If TRUE get only issuer contracts
+ */
+ seg_contract_t* (*get_contract)(seg_contract_manager_t *this,
+ pen_type_t msg_type, bool is_issuer);
+
+ /**
+ * Destroys a seg_contract_manager_t object.
+ */
+ void (*destroy)(seg_contract_manager_t *this);
+};
+
+/**
+ * Create a PA-TNC attribute segmentation contract manager
+ */
+seg_contract_manager_t* seg_contract_manager_create();
+
+#endif /** SEG_CONTRACT_MANAGER_H_ @}*/
diff --git a/src/libimcv/seg/seg_env.c b/src/libimcv/seg/seg_env.c
new file mode 100644
index 000000000..1f4cfc53f
--- /dev/null
+++ b/src/libimcv/seg/seg_env.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "seg_env.h"
+
+#include "imcv.h"
+#include "pa_tnc/pa_tnc_msg.h"
+
+#include <utils/debug.h>
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
+
+#include <tcg/seg/tcg_seg_attr_seg_env.h>
+
+#define BASE_ATTR_ID_PREFIX 0xFF
+
+typedef struct private_seg_env_t private_seg_env_t;
+
+/**
+ * Private data of a seg_env_t object.
+ */
+struct private_seg_env_t {
+
+ /**
+ * Public seg_env_t interface.
+ */
+ seg_env_t public;
+
+ /**
+ * Base Attribute ID
+ */
+ uint32_t base_attr_id;
+
+ /**
+ * Base Attribute
+ */
+ pa_tnc_attr_t *base_attr;
+
+ /**
+ * Maximum PA-TNC attribute segment size
+ */
+ uint32_t max_seg_size;
+
+ /**
+ * TRUE if attribute is assembled from data
+ */
+ bool from_data;
+
+ /**
+ * Remaining attribute data to be sent or received data being accumulated
+ */
+ chunk_t data;
+
+};
+
+METHOD(seg_env_t, get_base_attr_id, uint32_t,
+ private_seg_env_t *this)
+{
+ return this->base_attr_id;
+}
+
+METHOD(seg_env_t, get_base_attr, pa_tnc_attr_t*,
+ private_seg_env_t *this, pa_tnc_attr_t** error)
+{
+ *error = NULL;
+
+ 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, first_segment, pa_tnc_attr_t*,
+ private_seg_env_t *this)
+{
+ pa_tnc_attr_t *seg_env_attr;
+ bio_writer_t *writer;
+ pen_type_t type;
+ chunk_t segment_data, value;
+ uint8_t flags, seg_env_flags;
+
+ /* get components of base attribute header and data */
+ flags = this->base_attr->get_noskip_flag(this->base_attr) ?
+ PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE;
+ type = this->base_attr->get_type(this->base_attr);
+
+ /* attribute data going into the first segment */
+ segment_data = this->data;
+ segment_data.len = this->max_seg_size - PA_TNC_ATTR_HEADER_SIZE;
+
+ /* build encoding of the base attribute header and first segment data */
+ writer = bio_writer_create(this->max_seg_size);
+ writer->write_uint8 (writer, flags);
+ writer->write_uint24(writer, type.vendor_id);
+ writer->write_uint32(writer, type.type);
+ writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + this->data.len);
+ writer->write_data (writer, segment_data);
+ value = writer->extract_buf(writer);
+ writer->destroy(writer);
+ this->data = chunk_skip(this->data, segment_data.len);
+
+ DBG2(DBG_TNC, "creating first segment for base attribute ID %d (%d bytes)",
+ this->base_attr_id, this->max_seg_size);
+
+ seg_env_flags = SEG_ENV_FLAG_START | SEG_ENV_FLAG_MORE;
+ seg_env_attr = tcg_seg_attr_seg_env_create(value, seg_env_flags,
+ this->base_attr_id);
+ chunk_free(&value);
+
+ return seg_env_attr;
+}
+
+METHOD(seg_env_t, next_segment, pa_tnc_attr_t*,
+ private_seg_env_t *this, bool *last)
+{
+ pa_tnc_attr_t *seg_env_attr;
+ chunk_t segment_data;
+ uint8_t seg_env_flags;
+ bool is_last_segment;
+
+ if (this->data.len == 0)
+ {
+ /* no more attribute data to segment available */
+ return NULL;
+ }
+
+ /* attribute data going into the next segment */
+ segment_data = this->data;
+ segment_data.len = min(this->max_seg_size, this->data.len);
+ this->data = chunk_skip(this->data, segment_data.len);
+
+ is_last_segment = (this->data.len == 0);
+ if (last)
+ {
+ *last = is_last_segment;
+ }
+ DBG2(DBG_TNC, "creating %s segment for base attribute ID %d (%d bytes)",
+ is_last_segment ? "last" : "next", this->base_attr_id,
+ segment_data.len);
+
+ seg_env_flags = is_last_segment ? SEG_ENV_FLAG_NONE : SEG_ENV_FLAG_MORE;
+ seg_env_attr = tcg_seg_attr_seg_env_create(segment_data, seg_env_flags,
+ this->base_attr_id);
+
+ return seg_env_attr;
+}
+
+METHOD(seg_env_t, add_segment, void,
+ private_seg_env_t *this, chunk_t segment_data)
+{
+ this->data = chunk_cat("mc", this->data, segment_data);
+}
+
+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);
+}
+
+/**
+ * See header
+ */
+seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
+ uint32_t max_seg_size)
+{
+ private_seg_env_t *this;
+ chunk_t value;
+
+ base_attr->build(base_attr);
+ value = base_attr->get_value(base_attr);
+
+ /**
+ * The PA-TNC attribute header must not be segmented and
+ * there must be at least a first and one next segment
+ */
+ if (max_seg_size < PA_TNC_ATTR_HEADER_SIZE ||
+ max_seg_size >= PA_TNC_ATTR_HEADER_SIZE + value.len)
+ {
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .get_base_attr_id = _get_base_attr_id,
+ .get_base_attr = _get_base_attr,
+ .first_segment = _first_segment,
+ .next_segment = _next_segment,
+ .add_segment = _add_segment,
+ .destroy = _destroy,
+ },
+ .base_attr_id = base_attr_id,
+ .base_attr = base_attr->get_ref(base_attr),
+ .max_seg_size = max_seg_size,
+ .data = base_attr->get_value(base_attr),
+ );
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
+ uint32_t max_seg_size)
+{
+ private_seg_env_t *this;
+
+ INIT(this,
+ .public = {
+ .get_base_attr_id = _get_base_attr_id,
+ .get_base_attr = _get_base_attr,
+ .first_segment = _first_segment,
+ .next_segment = _next_segment,
+ .add_segment = _add_segment,
+ .destroy = _destroy,
+ },
+ .base_attr_id = base_attr_id,
+ .max_seg_size = max_seg_size,
+ .data = chunk_clone(data),
+ .from_data = TRUE,
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libimcv/seg/seg_env.h b/src/libimcv/seg/seg_env.h
new file mode 100644
index 000000000..0dcefdde8
--- /dev/null
+++ b/src/libimcv/seg/seg_env.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup seg_env seg_env
+ * @{ @ingroup libimcv
+ */
+
+#ifndef SEG_ENV_H_
+#define SEG_ENV_H_
+
+typedef struct seg_env_t seg_env_t;
+typedef enum seg_env_flags_t seg_env_flags_t;
+
+#include <library.h>
+
+#include <pa_tnc/pa_tnc_attr.h>
+
+/**
+ * Segment Envelope flags
+ */
+enum seg_env_flags_t {
+ SEG_ENV_FLAG_NONE = 0,
+ SEG_ENV_FLAG_MORE = (1<<7),
+ SEG_ENV_FLAG_START = (1<<6)
+};
+
+/**
+ * Interface for a PA-TNC attribute segment envelope object
+ */
+struct seg_env_t {
+
+ /**
+ * Get Base Attribute ID
+ *
+ * @return Base Attribute ID
+ */
+ uint32_t (*get_base_attr_id)(seg_env_t *this);
+
+ /**
+ * Get Base Attribute
+ *
+ * @param error Error attribute if an error occurred or NULL
+ * @return Base Attribute (must be destroyed) or NULL
+ */
+ pa_tnc_attr_t* (*get_base_attr)(seg_env_t *this, pa_tnc_attr_t **error);
+
+ /**
+ * Generate the first segment envelope of the base attribute
+ *
+ * @return First attribute segment envelope
+ */
+ pa_tnc_attr_t* (*first_segment)(seg_env_t *this);
+
+ /**
+ * Generate the next segment envelope of the base attribute
+ *
+ * @param last TRUE if last segment
+ * @return Next attribute segment envelope
+ */
+ pa_tnc_attr_t* (*next_segment)(seg_env_t *this, bool *last);
+
+ /**
+ * Generate the first segment envelope of the base attribute
+ *
+ * @param segment Attribute segment to be added
+ */
+ void (*add_segment)(seg_env_t *this, chunk_t segment);
+
+ /**
+ * Destroys a seg_env_t object.
+ */
+ void (*destroy)(seg_env_t *this);
+};
+
+/**
+ * Create a PA-TNC attribute segment envelope object
+ *
+ * @param base_attr_id Base Attribute ID
+ * @param base_attr Base Attribute to be segmented
+ * @param max_seg_size Maximum segment size
+ */
+seg_env_t* seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
+ uint32_t max_seg_size);
+
+/**
+ * Create a PA-TNC attribute segment envelope object
+ *
+ * @param base_attr_id Base Attribute ID
+ * @param data First attribute segment
+ * @param max_seg_size Maximum segment size
+ */
+seg_env_t* seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
+ uint32_t max_seg_size);
+
+#endif /** SEG_ENV_H_ @}*/