diff --git a/src/charon-tkm/src/tkm/tkm_id_manager.c b/src/charon-tkm/src/tkm/tkm_id_manager.c index b07409d19..2d28c3c45 100644 --- a/src/charon-tkm/src/tkm/tkm_id_manager.c +++ b/src/charon-tkm/src/tkm/tkm_id_manager.c @@ -103,6 +103,33 @@ METHOD(tkm_id_manager_t, acquire_id, int, return id; } +METHOD(tkm_id_manager_t, acquire_ref, bool, + private_tkm_id_manager_t * const this, const tkm_context_kind_t kind, + const int ref_id) +{ + const int idx = ref_id - 1; + + if (!is_valid_kind(kind)) + { + DBG1(DBG_LIB, "tried to acquire reference for invalid context kind '%d'", + kind); + return FALSE; + } + + if (ref_id < 1 || (uint64_t)ref_id > this->limits[kind]) + { + DBG1(DBG_LIB, "tried to acquire reference for context id %d out of " + "bounds (max %llu)", ref_id, this->limits[kind]); + return FALSE; + } + + this->locks[kind]->write_lock(this->locks[kind]); + this->ctxids[kind][idx]++; + this->locks[kind]->unlock(this->locks[kind]); + + return TRUE; +} + METHOD(tkm_id_manager_t, release_id, bool, private_tkm_id_manager_t * const this, const tkm_context_kind_t kind, const int id) @@ -150,6 +177,7 @@ tkm_id_manager_t *tkm_id_manager_create(const tkm_limits_t limits) INIT(this, .public = { .acquire_id = _acquire_id, + .acquire_ref = _acquire_ref, .release_id = _release_id, .destroy = _destroy, }, diff --git a/src/charon-tkm/src/tkm/tkm_id_manager.h b/src/charon-tkm/src/tkm/tkm_id_manager.h index 0fc9ff8ef..ec7b07f7e 100644 --- a/src/charon-tkm/src/tkm/tkm_id_manager.h +++ b/src/charon-tkm/src/tkm/tkm_id_manager.h @@ -73,6 +73,18 @@ struct tkm_id_manager_t { int (*acquire_id)(tkm_id_manager_t * const this, const tkm_context_kind_t kind); + /** + * Acquire reference to given context id for a specific context kind. + * + * @param kind kind of context id + * @param ref_id id to acquire a reference for + * @return TRUE if reference could be acquired, + * FALSE otherwise + */ + bool (*acquire_ref)(tkm_id_manager_t * const this, + const tkm_context_kind_t kind, + const int ref_id); + /** * Release a previously acquired context id. * diff --git a/src/charon-tkm/tests/id_manager_tests.c b/src/charon-tkm/tests/id_manager_tests.c index 8157496ca..392379aa9 100644 --- a/src/charon-tkm/tests/id_manager_tests.c +++ b/src/charon-tkm/tests/id_manager_tests.c @@ -84,6 +84,71 @@ START_TEST(test_acquire_id_same) } END_TEST +START_TEST(test_acquire_ref) +{ + int i, id = 0; + bool acquired = false; + tkm_id_manager_t *idmgr = tkm_id_manager_create(limits); + + for (i = 0; i < TKM_CTX_MAX; i++) + { + id = idmgr->acquire_id(idmgr, i); + acquired = idmgr->acquire_ref(idmgr, i, id); + fail_unless(acquired, "Error acquiring reference context kind %d", i); + + /* Reset test variable */ + acquired = false; + } + + idmgr->destroy(idmgr); +} +END_TEST + +START_TEST(test_acquire_ref_invalid_kind) +{ + bool acquired; + tkm_id_manager_t *idmgr = tkm_id_manager_create(limits); + + acquired = idmgr->acquire_ref(idmgr, TKM_CTX_MAX, 1); + fail_if(acquired, "Acquired reference for invalid context kind %d", TKM_CTX_MAX); + + /* Reset test variable */ + acquired = 0; + + acquired = idmgr->acquire_ref(idmgr, -1, 1); + fail_if(acquired, "Acquired reference for invalid context kind %d", -1); + + idmgr->destroy(idmgr); +} +END_TEST + +START_TEST(test_acquire_ref_invalid_id) +{ + int i; + bool acquired; + tkm_id_manager_t *idmgr = tkm_id_manager_create(limits); + + for (i = 0; i < TKM_CTX_MAX; i++) + { + acquired = idmgr->acquire_ref(idmgr, i, -1); + fail_if(acquired, + "Acquired reference for negative id of context kind %d", i); + + /* Reset test variable */ + acquired = false; + + acquired = idmgr->acquire_ref(idmgr, i, limits[i] + 1); + fail_if(acquired, + "Acquired reference exceeding limit of context kind %d", i); + + /* Reset test variable */ + acquired = false; + } + + idmgr->destroy(idmgr); +} +END_TEST + START_TEST(test_release_id) { int i, id = 0; @@ -150,6 +215,9 @@ Suite *make_id_manager_tests() tcase_add_test(tc, test_acquire_id); tcase_add_test(tc, test_acquire_id_invalid_kind); tcase_add_test(tc, test_acquire_id_same); + tcase_add_test(tc, test_acquire_ref); + tcase_add_test(tc, test_acquire_ref_invalid_kind); + tcase_add_test(tc, test_acquire_ref_invalid_id); suite_add_tcase(s, tc); tc = tcase_create("release");