Support of multiple directed segmentation contracts
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 11 Oct 2014 12:49:23 +0000 (14:49 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 11 Oct 2014 12:50:08 +0000 (14:50 +0200)
src/libimcv/imc/imc_msg.c
src/libimcv/imv/imv_msg.c
src/libimcv/seg/seg_contract.c
src/libimcv/seg/seg_contract.h
src/libimcv/seg/seg_contract_manager.c
src/libimcv/seg/seg_contract_manager.h

index 810a92a..83337cf 100644 (file)
@@ -117,7 +117,8 @@ METHOD(imc_msg_t, send_, TNC_Result,
 
        /* Get IF-M segmentation contract for this subtype if any */
        contracts = this->state->get_contracts(this->state);
-       contract = contracts->get_contract(contracts, this->msg_type, FALSE);
+       contract = contracts->get_contract(contracts, this->msg_type,
+                                                                          FALSE, this->dst_id);
 
        while (this->attr_list->get_count(this->attr_list))
        {
@@ -287,6 +288,10 @@ METHOD(imc_msg_t, receive, TNC_Result,
                        return TNC_RESULT_FATAL;
        }
 
+       /* determine target IMC ID */
+       target_imc_id = (this->dst_id != TNC_IMCID_ANY) ?
+                                        this->dst_id : this->agent->get_id(this->agent);
+
        /* process any IF-M segmentation contracts */
        enumerator = this->pa_msg->create_attribute_enumerator(this->pa_msg);
        while (enumerator->enumerate(enumerator, &attr))
@@ -316,7 +321,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                attr_cast->get_attr_size(attr_cast, &max_attr_size,
                                                                                                        &max_seg_size);
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         FALSE);
+                                                                                                  FALSE, this->src_id);
                                if (contract)
                                {
                                        contract->set_max_size(contract, max_attr_size,
@@ -326,6 +331,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                {
                                        contract = seg_contract_create(this->msg_type, max_attr_size,
                                                                        max_seg_size, FALSE, this->src_id, TRUE);
+                                       contract->set_responder(contract, target_imc_id);
                                        contracts->add_contract(contracts, contract);
                                }
                                contract->get_info_string(contract, buf, BUF_LEN, TRUE);
@@ -364,7 +370,18 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                attr_cast->get_attr_size(attr_cast, &max_attr_size,
                                                                                                        &max_seg_size);
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         TRUE);
+                                                                                                  TRUE, this->src_id);
+                               if (!contract)
+                               {
+                                       contract = contracts->get_contract(contracts, this->msg_type,
+                                                                                                          TRUE, TNC_IMCID_ANY);
+                                       if (contract)
+                                       {
+                                               contract = contract->clone(contract);
+                                               contract->set_responder(contract, this->src_id);
+                                               contracts->add_contract(contracts, contract);
+                                       }
+                               }
                                if (contract)
                                {
                                        contract->get_max_size(contract, &my_max_attr_size,
@@ -397,7 +414,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
 
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         TRUE);
+                                                                                                  TRUE, this->src_id);
                                if (!contract)
                                {
                                        DBG2(DBG_IMC, "no contract for received attribute segment "
@@ -430,7 +447,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                base_attr_id = attr_cast->get_base_attr_id(attr_cast);
 
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         FALSE);
+                                                                                                  FALSE, this->src_id);
                                if (!contract)
                                {
                                        /* TODO no contract - generate error message */
@@ -457,10 +474,6 @@ METHOD(imc_msg_t, receive, TNC_Result,
        }
        enumerator->destroy(enumerator);
 
-       /* determine target IMC ID */
-       target_imc_id = (this->dst_id != TNC_IMCID_ANY) ?
-                                        this->dst_id : this->agent->get_id(this->agent);
-
        /* preprocess any received IETF standard error attributes */
        non_fatal_types = this->agent->get_non_fatal_attr_types(this->agent);
        *fatal_error = this->pa_msg->process_ietf_std_errors(this->pa_msg,
index 6c4b998..fdf6332 100644 (file)
@@ -134,7 +134,8 @@ METHOD(imv_msg_t, send_, TNC_Result,
 
        /* Get IF-M segmentation contract for this subtype if any */
        contracts = this->state->get_contracts(this->state);
-       contract = contracts->get_contract(contracts, this->msg_type, FALSE);
+       contract = contracts->get_contract(contracts, this->msg_type,
+                                                                          FALSE, this->dst_id);
 
        while (this->attr_list->get_count(this->attr_list))
        {
@@ -270,6 +271,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
        private_imv_msg_t *this, imv_msg_t *out_msg, bool *fatal_error)
 {
        TNC_Result result = TNC_RESULT_SUCCESS;
+       TNC_UInt32 target_imv_id;
        linked_list_t *non_fatal_types;
        enumerator_t *enumerator;
        pa_tnc_attr_t *attr;
@@ -322,6 +324,10 @@ METHOD(imv_msg_t, receive, TNC_Result,
                        return TNC_RESULT_FATAL;
        }
 
+       /* determine target IMV ID */
+       target_imv_id = (this->dst_id != TNC_IMVID_ANY) ?
+                                        this->dst_id : this->agent->get_id(this->agent);
+
        /* process IF-M segmentation attributes */
        enumerator = this->pa_msg->create_attribute_enumerator(this->pa_msg);
        while (enumerator->enumerate(enumerator, &attr))
@@ -351,7 +357,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                attr_cast->get_attr_size(attr_cast, &max_attr_size,
                                                                                                        &max_seg_size);
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         FALSE);
+                                                                                                  FALSE, this->src_id);
                                if (contract)
                                {
                                        contract->set_max_size(contract, max_attr_size,
@@ -361,6 +367,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                {
                                        contract = seg_contract_create(this->msg_type, max_attr_size,
                                                                        max_seg_size, FALSE, this->src_id, FALSE);
+                                       contract->set_responder(contract, target_imv_id);
                                        contracts->add_contract(contracts, contract);
                                }
                                contract->get_info_string(contract, buf, BUF_LEN, TRUE);
@@ -399,7 +406,18 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                attr_cast->get_attr_size(attr_cast, &max_attr_size,
                                                                                                        &max_seg_size);
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         TRUE);
+                                                                                                  TRUE, this->src_id);
+                               if (!contract)
+                               {
+                                       contract = contracts->get_contract(contracts, this->msg_type,
+                                                                                                  TRUE, TNC_IMCID_ANY);
+                                       if (contract)
+                                       {
+                                               contract = contract->clone(contract);
+                                               contract->set_responder(contract, this->src_id);
+                                               contracts->add_contract(contracts, contract);
+                                       }
+                               }
                                if (contract)
                                {
                                        contract->get_max_size(contract, &my_max_attr_size,
@@ -432,7 +450,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
 
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         TRUE);
+                                                                                                  TRUE, this->src_id);
                                if (!contract)
                                {
                                        DBG2(DBG_IMV, "no contract for received attribute segment "
@@ -465,7 +483,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                base_attr_id = attr_cast->get_base_attr_id(attr_cast);
 
                                contract = contracts->get_contract(contracts, this->msg_type,
-                                                                                                                         FALSE);
+                                                                                                  FALSE, this->src_id);
                                if (!contract)
                                {
                                        /* TODO no contract - generate error message */
index df25e64..7db702a 100644 (file)
@@ -72,11 +72,16 @@ struct private_seg_contract_t {
        bool is_issuer;
 
        /**
-        * Issuer ID (either IMV ID or IMC ID)
+        * Issuer ID (either IMV or IMC ID)
         */
        TNC_UInt32 issuer_id;
 
        /**
+        * Responder ID (either IMC or IMV ID)
+        */
+       TNC_UInt32 responder_id;
+
+       /**
         * IMC/IMV role
         */
        bool is_imc;
@@ -290,6 +295,36 @@ METHOD(seg_contract_t, is_null, bool,
        return this->is_null;
 }
 
+METHOD(seg_contract_t, set_responder, void,
+       private_seg_contract_t *this, TNC_UInt32 responder_id)
+{
+       this->responder_id = responder_id;
+}
+
+METHOD(seg_contract_t, get_responder, TNC_UInt32,
+       private_seg_contract_t *this)
+{
+       return this->responder_id;
+}
+
+METHOD(seg_contract_t, get_issuer, TNC_UInt32,
+       private_seg_contract_t *this)
+{
+       return this->issuer_id;
+}
+
+METHOD(seg_contract_t, clone_, seg_contract_t*,
+       private_seg_contract_t *this)
+{
+       private_seg_contract_t *clone;
+
+       clone = malloc_thing(private_seg_contract_t);
+       memcpy(clone, this, sizeof(private_seg_contract_t));
+       clone->seg_envs = linked_list_create();
+
+       return &clone->public;
+}
+
 METHOD(seg_contract_t, get_info_string, void,
        private_seg_contract_t *this, char *buf, size_t len, bool request)
 {
@@ -308,7 +343,10 @@ METHOD(seg_contract_t, get_info_string, void,
        }
        else
        {
-               written = snprintf(pos, len, "received");
+               written = snprintf(pos, len, "%s %d received",
+                                                  this->is_imc ? "IMC" : "IMV",
+                                                  this->is_issuer ? this->issuer_id :
+                                                                                        this->responder_id);
        }
        if (written < 0 || written > len)
        {
@@ -318,7 +356,8 @@ METHOD(seg_contract_t, get_info_string, void,
        len -= written;
 
        written = snprintf(pos, len, " a %ssegmentation contract%s ",
-                                          this->is_null ? "null" : "", request ? "" : " response");
+                                          this->is_null ? "null" : "", request ?
+                                         (this->is_issuer ? "" : " request") : " response");
        if (written < 0 || written > len)
        {
                return;
@@ -326,10 +365,13 @@ METHOD(seg_contract_t, get_info_string, void,
        pos += written;
        len -= written;
 
-       if (!this->is_issuer && this->issuer_id != TNC_IMVID_ANY)
+       if ((!this->is_issuer && this->issuer_id != TNC_IMVID_ANY) ||
+               ( this->is_issuer && this->responder_id != TNC_IMVID_ANY))
        {
                written = snprintf(pos, len, "from %s %d ",
-                                                  this->is_imc ? "IMV" : "IMC", this->issuer_id);
+                                                  this->is_imc ? "IMV" : "IMC",
+                                                  this->is_issuer ? this->responder_id :
+                                                                                        this->issuer_id);
                if (written < 0 || written > len)
                {
                        return;
@@ -413,6 +455,10 @@ seg_contract_t *seg_contract_create(pen_type_t msg_type,
                        .add_segment = _add_segment,
                        .is_issuer = _is_issuer,
                        .is_null = _is_null,
+                       .set_responder = _set_responder,
+                       .get_responder = _get_responder,
+                       .get_issuer = _get_issuer,
+                       .clone = _clone_,
                        .get_info_string = _get_info_string,
                        .destroy = _destroy,
                },
@@ -422,6 +468,7 @@ seg_contract_t *seg_contract_create(pen_type_t msg_type,
                .seg_envs = linked_list_create(),
                .is_issuer = is_issuer,
                .issuer_id = issuer_id,
+               .responder_id = is_imc ? TNC_IMVID_ANY : TNC_IMCID_ANY,
                .is_imc = is_imc,
                .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
                                   max_seg_size  == SEG_CONTRACT_MAX_SIZE_VALUE,
index 48828c4..2a2666f 100644 (file)
@@ -118,6 +118,34 @@ struct seg_contract_t {
        bool (*is_null)(seg_contract_t *this);
 
        /**
+        * Set the responder ID
+        *
+        * @param responder             IMC or IMV ID of responder
+        */
+       void (*set_responder)(seg_contract_t *this, TNC_UInt32 responder);
+
+       /**
+        * Get the responder ID
+        *
+        * @return                              IMC or IMV ID of responder
+        */
+       TNC_UInt32 (*get_responder)(seg_contract_t *this);
+
+       /**
+        * Get the issuer ID
+        *
+        * @return                              IMC or IMV ID of issuer
+        */
+       TNC_UInt32 (*get_issuer)(seg_contract_t *this);
+
+       /**
+        * Clone a contract
+        *
+        * @return                              Cloned contract
+        */
+       seg_contract_t* (*clone)(seg_contract_t *this);
+
+       /**
         * Get an info string about the contract
         *
         * @param buf                   String buffer of at least size len
index d099436..604c511 100644 (file)
@@ -42,7 +42,8 @@ METHOD(seg_contract_manager_t, add_contract, void,
 }
 
 METHOD(seg_contract_manager_t, get_contract, seg_contract_t*,
-       private_seg_contract_manager_t *this, pen_type_t msg_type, bool is_issuer)
+       private_seg_contract_manager_t *this, pen_type_t msg_type, bool is_issuer,
+       TNC_UInt32 id)
 {
        enumerator_t *enumerator;
        seg_contract_t *contract, *found = NULL;
@@ -51,7 +52,9 @@ METHOD(seg_contract_manager_t, get_contract, seg_contract_t*,
        while (enumerator->enumerate(enumerator, &contract))
        {
                if (contract->is_issuer(contract) == is_issuer &&
-                       pen_type_equals(contract->get_msg_type(contract), msg_type))
+                       pen_type_equals(contract->get_msg_type(contract), msg_type) &&
+                       id == (is_issuer ? contract->get_responder(contract) :
+                                                          contract->get_issuer(contract)))
                {
                        found = contract;
                        break;
index 355822d..2757eca 100644 (file)
@@ -43,9 +43,11 @@ struct seg_contract_manager_t {
         *
         * @param msg_type                      PA-TNC message type governed by contract
         * @param is_issuer                     If TRUE get only issuer contracts
+        * @param id                            Match either issuer or responder ID
         */
        seg_contract_t* (*get_contract)(seg_contract_manager_t *this,
-                                                                       pen_type_t msg_type, bool is_issuer);
+                                                                       pen_type_t msg_type, bool is_issuer,
+                                                                       TNC_UInt32 id);
 
        /**
         * Destroys a seg_contract_manager_t object.