diff --git a/api/oc_core_res.c b/api/oc_core_res.c index d59d8ee24..7fa033c50 100644 --- a/api/oc_core_res.c +++ b/api/oc_core_res.c @@ -39,6 +39,15 @@ #include "util/oc_macros_internal.h" #include "util/oc_secure_string_internal.h" +#ifdef OC_HAS_FEATURE_DEVICE_ADD +#include "oc_acl.h" +#include "oc_cred.h" +#ifdef OC_SECURITY +#include "security/oc_ael_internal.h" +#include "security/oc_svr_internal.h" +#endif /* OC_SECURITY*/ +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #ifdef OC_CLOUD #include "api/cloud/oc_cloud_resource_internal.h" #endif /* OC_CLOUD */ @@ -69,6 +78,7 @@ #endif /* OC_HAS_FEATURE_PUSH */ #include +#include #include #include @@ -106,49 +116,66 @@ oc_core_init(void) } static void -oc_core_free_device_info_properties(oc_device_info_t *oc_device_info_item) +core_free_device_info_properties(oc_device_info_t *oc_device_info_item) { - if (oc_device_info_item) { - oc_free_string(&(oc_device_info_item->name)); - oc_free_string(&(oc_device_info_item->icv)); - oc_free_string(&(oc_device_info_item->dmv)); - } + oc_free_string(&(oc_device_info_item->name)); + oc_free_string(&(oc_device_info_item->icv)); + oc_free_string(&(oc_device_info_item->dmv)); } -void -oc_core_shutdown(void) +// Remove all core cesources +static void +core_resources_deinit(void) { - oc_platform_deinit(); - - uint32_t device_count = OC_ATOMIC_LOAD32(g_device_count); -#ifdef OC_DYNAMIC_ALLOCATION - if (g_oc_device_info != NULL) { -#endif /* OC_DYNAMIC_ALLOCATION */ - for (uint32_t i = 0; i < device_count; ++i) { - oc_device_info_t *oc_device_info_item = &g_oc_device_info[i]; - oc_core_free_device_info_properties(oc_device_info_item); - } #ifdef OC_DYNAMIC_ALLOCATION - free(g_oc_device_info); - g_oc_device_info = NULL; + if (g_core_resources == NULL) { + return; } #endif /* OC_DYNAMIC_ALLOCATION */ + uint32_t device_count = OC_ATOMIC_LOAD32(g_device_count); + for (size_t i = 0; + i < OC_NUM_CORE_PLATFORM_RESOURCES + + (OC_NUM_CORE_LOGICAL_DEVICE_RESOURCES * device_count); + ++i) { + oc_ri_free_resource_properties(&g_core_resources[i]); + } #ifdef OC_DYNAMIC_ALLOCATION - if (g_core_resources != NULL) { + free(g_core_resources); + g_core_resources = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_core_resources, 0, sizeof(g_core_resources)); #endif /* OC_DYNAMIC_ALLOCATION */ - for (size_t i = 0; - i < OC_NUM_CORE_PLATFORM_RESOURCES + - (OC_NUM_CORE_LOGICAL_DEVICE_RESOURCES * device_count); - ++i) { - oc_resource_t *core_resource = &g_core_resources[i]; - oc_ri_free_resource_properties(core_resource); - } +} + +// Remove all devices +static void +core_devices_deinit(void) +{ #ifdef OC_DYNAMIC_ALLOCATION - free(g_core_resources); - g_core_resources = NULL; + if (g_oc_device_info == NULL) { + return; } #endif /* OC_DYNAMIC_ALLOCATION */ + + uint32_t device_count = OC_ATOMIC_LOAD32(g_device_count); + for (uint32_t i = 0; i < device_count; ++i) { + core_free_device_info_properties(&g_oc_device_info[i]); + } +#ifdef OC_DYNAMIC_ALLOCATION + free(g_oc_device_info); + g_oc_device_info = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_oc_device_info, 0, sizeof(g_oc_device_info)); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +void +oc_core_shutdown(void) +{ + oc_platform_deinit(); + core_resources_deinit(); + core_devices_deinit(); OC_ATOMIC_STORE32(g_device_count, 0); } @@ -265,11 +292,30 @@ oc_core_get_latency(void) } static void -core_update_device_data(uint32_t device_count, oc_add_new_device_t cfg) +core_set_device_info(oc_device_info_t *info, oc_add_new_device_t cfg) +{ + assert(cfg.name != NULL); + assert(cfg.spec_version != NULL); + assert(cfg.data_model_version != NULL); + + oc_gen_uuid(&info->di); + oc_gen_uuid(&info->piid); + + oc_new_string(&info->name, cfg.name, strlen(cfg.name)); + oc_new_string(&info->icv, cfg.spec_version, strlen(cfg.spec_version)); + oc_new_string(&info->dmv, cfg.data_model_version, + strlen(cfg.data_model_version)); + info->add_device_cb = cfg.add_device_cb; + info->data = cfg.add_device_cb_data; +} + +static void +core_update_device_data(size_t max_device_index, oc_add_new_device_t cfg) { #ifdef OC_DYNAMIC_ALLOCATION - size_t new_num = OC_NUM_CORE_PLATFORM_RESOURCES + - (OC_NUM_CORE_LOGICAL_DEVICE_RESOURCES * (device_count + 1)); + size_t new_num = + OC_NUM_CORE_PLATFORM_RESOURCES + + (OC_NUM_CORE_LOGICAL_DEVICE_RESOURCES * (max_device_index + 1)); oc_resource_t *core_resources = (oc_resource_t *)realloc(g_core_resources, new_num * sizeof(oc_resource_t)); if (core_resources == NULL) { @@ -282,31 +328,23 @@ core_update_device_data(uint32_t device_count, oc_add_new_device_t cfg) g_core_resources = core_resources; oc_device_info_t *device_info = (oc_device_info_t *)realloc( - g_oc_device_info, (device_count + 1) * sizeof(oc_device_info_t)); - + g_oc_device_info, (max_device_index + 1) * sizeof(oc_device_info_t)); if (device_info == NULL) { oc_abort("Insufficient memory"); } - memset(&device_info[device_count], 0, sizeof(oc_device_info_t)); + memset(&device_info[max_device_index], 0, sizeof(oc_device_info_t)); g_oc_device_info = device_info; #endif /* OC_DYNAMIC_ALLOCATION */ - oc_gen_uuid(&g_oc_device_info[device_count].di); - oc_gen_uuid(&g_oc_device_info[device_count].piid); - - oc_new_string(&g_oc_device_info[device_count].name, cfg.name, - strlen(cfg.name)); - oc_new_string(&g_oc_device_info[device_count].icv, cfg.spec_version, - strlen(cfg.spec_version)); - oc_new_string(&g_oc_device_info[device_count].dmv, cfg.data_model_version, - strlen(cfg.data_model_version)); - g_oc_device_info[device_count].add_device_cb = cfg.add_device_cb; - g_oc_device_info[device_count].data = cfg.add_device_cb_data; + core_set_device_info(&g_oc_device_info[max_device_index], cfg); } static void -oc_create_device_resource(size_t device_count, const char *uri, const char *rt) +oc_create_device_resource(size_t device, const char *uri, const char *rt) { + assert(uri != NULL); + assert(rt != NULL); + /* Construct device resource */ int properties = OC_DISCOVERABLE; #ifdef OC_CLOUD @@ -316,27 +354,21 @@ oc_create_device_resource(size_t device_count, const char *uri, const char *rt) oc_string_view(rt, oc_strnlen(rt, OC_CHAR_ARRAY_LEN(OCF_D_RT) + 1)); if (oc_string_view_is_equal( rtv, oc_string_view(OCF_D_RT, OC_CHAR_ARRAY_LEN(OCF_D_RT)))) { - oc_core_populate_resource(OCF_D, device_count, uri, - OC_IF_R | OC_IF_BASELINE, OC_IF_R, properties, - oc_core_device_handler, /*put*/ NULL, + oc_core_populate_resource(OCF_D, device, uri, OC_IF_R | OC_IF_BASELINE, + OC_IF_R, properties, oc_core_device_handler, + /*put*/ NULL, /*post*/ NULL, /*delete*/ NULL, 1, rt); } else { - oc_core_populate_resource(OCF_D, device_count, uri, - OC_IF_R | OC_IF_BASELINE, OC_IF_R, properties, - oc_core_device_handler, /*put*/ NULL, + oc_core_populate_resource(OCF_D, device, uri, OC_IF_R | OC_IF_BASELINE, + OC_IF_R, properties, oc_core_device_handler, + /*put*/ NULL, /*post*/ NULL, /*delete*/ NULL, 2, rt, OCF_D_RT); } } -oc_device_info_t * -oc_core_add_new_device(oc_add_new_device_t cfg) +static int64_t +core_increment_device_count(void) { - assert(cfg.uri != NULL); - assert(cfg.rt != NULL); - assert(cfg.name != NULL); - assert(cfg.spec_version != NULL); - assert(cfg.data_model_version != NULL); - uint32_t device_count = OC_ATOMIC_LOAD32(g_device_count); bool exchanged = false; @@ -344,53 +376,70 @@ oc_core_add_new_device(oc_add_new_device_t cfg) #ifndef OC_DYNAMIC_ALLOCATION if (device_count == OC_MAX_NUM_DEVICES) { OC_ERR("device limit reached"); - return NULL; + return -1; } #endif /* !OC_DYNAMIC_ALLOCATION */ if ((uint64_t)device_count == (uint64_t)MIN(SIZE_MAX, UINT32_MAX)) { OC_ERR("limit of value type of g_device_count reached"); - return NULL; + return -1; } OC_ATOMIC_COMPARE_AND_SWAP32(g_device_count, device_count, device_count + 1, exchanged); } + return device_count; +} - core_update_device_data(device_count, cfg); - - oc_create_device_resource(device_count, cfg.uri, cfg.rt); +static void +oc_core_set_device_resources_at_index(uint32_t device, const char *uri, + const char *rt) +{ + oc_create_device_resource(device, uri, rt); if (oc_get_con_res_announced()) { /* Construct oic.wk.con resource for this device. */ - oc_create_con_resource(device_count); + oc_create_con_resource(device); } - oc_create_discovery_resource(device_count); + oc_create_discovery_resource(device); #ifdef OC_WKCORE - oc_create_wkcore_resource(device_count); + oc_create_wkcore_resource(device); #endif /* OC_WKCORE */ #ifdef OC_INTROSPECTION - oc_create_introspection_resource(device_count); + oc_create_introspection_resource(device); #endif /* OC_INTROSPECTION */ #ifdef OC_MNT - oc_create_maintenance_resource(device_count); + oc_create_maintenance_resource(device); #endif /* OC_MNT */ #if defined(OC_CLIENT) && defined(OC_SERVER) && defined(OC_CLOUD) - oc_create_cloudconf_resource(device_count); + oc_create_cloudconf_resource(device); #endif /* OC_CLIENT && OC_SERVER && OC_CLOUD */ #ifdef OC_HAS_FEATURE_PUSH - oc_create_pushconf_resource(device_count); - oc_create_pushreceiver_resource(device_count); + oc_create_pushconf_resource(device); + oc_create_pushreceiver_resource(device); #endif /* OC_HAS_FEATURE_PUSH */ +} - if (oc_connectivity_init(device_count, cfg.ports) < 0) { +oc_device_info_t * +oc_core_add_new_device(oc_add_new_device_t cfg) +{ + int64_t new_index = core_increment_device_count(); + if (new_index < 0) { + return NULL; + } + uint32_t device = (uint32_t)new_index; + + core_update_device_data(device, cfg); + oc_core_set_device_resources_at_index(device, cfg.uri, cfg.rt); + + if (oc_connectivity_init(device, cfg.ports) < 0) { oc_abort("error initializing connectivity for device"); } - return &g_oc_device_info[device_count]; + return &g_oc_device_info[device]; } bool @@ -408,6 +457,56 @@ oc_core_get_device_index(oc_uuid_t di, size_t *device) return false; } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +oc_device_info_t * +oc_core_add_or_update_device_at_index(oc_add_new_device_t cfg, size_t index) +{ + uint32_t device_count = OC_ATOMIC_LOAD32(g_device_count); + + if (index > device_count) { + OC_ERR("designated device index (%" PRIu32 + ") is bigger than current number of all devices", + device_count); + return NULL; + } + if (index < device_count) { + OC_ERR("cannot replace existing device (%" PRIu32 ")", device_count); + return NULL; + } + + // follow normal procedure + if (core_increment_device_count() < 0) { + return NULL; + } + ++device_count; + core_update_device_data(index, cfg); + + oc_core_set_device_resources_at_index(index, cfg.uri, cfg.rt); + +#ifdef OC_SECURITY + oc_sec_svr_create_new_device(index, true); +#endif /* OC_SECURITY */ + +#ifdef OC_SOFTWARE_UPDATE + oc_swupdate_create_at_index(index, true); +#endif /* OC_SOFTWARE_UPDATE */ + +#ifdef OC_SECURITY + oc_sec_svr_init_new_device(index); +#endif /* OC_SECURITY */ + +#ifdef OC_SOFTWARE_UPDATE + OC_DBG("oc_core_add_or_update_device_at_index(): loading swupdate(%zu)", + index); + oc_swupdate_load(index); +#endif /* OC_SOFTWARE_UPDATE */ + + return &g_oc_device_info[index]; +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + static void oc_device_bind_rt(size_t device_index, const char *rt) { diff --git a/api/oc_core_res_internal.h b/api/oc_core_res_internal.h index 84aad6bf7..5e31d8cd5 100644 --- a/api/oc_core_res_internal.h +++ b/api/oc_core_res_internal.h @@ -55,6 +55,20 @@ void oc_core_shutdown(void); */ oc_device_info_t *oc_core_add_new_device(oc_add_new_device_t cfg); +#ifdef OC_HAS_FEATURE_DEVICE_ADD +/** + * @brief Add a new device or update an existing device at the position + * designated by `index` of Device array (g_oc_device_info) + * + * @param cfg device configuration + * @param index index of `g_oc_device_info[]` + * @return oc_device_info_t* the device information + */ +oc_device_info_t *oc_core_add_or_update_device_at_index(oc_add_new_device_t cfg, + size_t index); + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** * @brief encode the interfaces with the cbor (payload) encoder * diff --git a/api/oc_push.c b/api/oc_push.c index ea0cc6a4b..6087c5502 100644 --- a/api/oc_push.c +++ b/api/oc_push.c @@ -2286,9 +2286,10 @@ oc_push_init(void) /* * clean up push related data structure - * - for push configuration Resource: they are cleaned when all app Resources - * are removed (see oc_main_shutdown()) - * - for push receivers Resource: free in this function + * - Push configuration Resource, Push Receiver Resource: + * they are cleaned when all app Resources are removed + * (see oc_ri_shutdown()) + * - for push receivers Resource: free receiver object list here */ void oc_push_free(void) diff --git a/api/oc_swupdate.c b/api/oc_swupdate.c index 0b9948895..09938cc5a 100644 --- a/api/oc_swupdate.c +++ b/api/oc_swupdate.c @@ -119,28 +119,38 @@ static struct static oc_event_callback_retval_t swupdate_update_async(void *data); static void -swupdate_init(void) +swupdate_init(size_t device_count) { #ifdef OC_DYNAMIC_ALLOCATION - g_sw = - (oc_swupdate_t *)calloc(oc_core_get_num_devices(), sizeof(oc_swupdate_t)); + g_sw = (oc_swupdate_t *)calloc(device_count, sizeof(oc_swupdate_t)); if (g_sw == NULL) { oc_abort("Insufficient memory"); } +#else /* OC_DYNAMIC_ALLOCATION */ + (void)device_count; #endif /* OC_DYNAMIC_ALLOCATION */ } +static void +swupdate_item_free(oc_swupdate_t *swu) +{ + oc_ri_remove_timed_event_callback(swu, swupdate_update_async); + oc_free_string(&swu->purl); + oc_free_string(&swu->nv); + oc_free_string(&swu->signage); +} + void oc_swupdate_free(void) { for (size_t i = 0; i < oc_core_get_num_devices(); ++i) { - oc_ri_remove_timed_event_callback(&g_sw[i], swupdate_update_async); - oc_free_string(&g_sw[i].purl); - oc_free_string(&g_sw[i].nv); - oc_free_string(&g_sw[i].signage); + swupdate_item_free(&g_sw[i]); } #ifdef OC_DYNAMIC_ALLOCATION free(g_sw); + g_sw = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_sw, 0, sizeof(g_sw)); #endif /* OC_DYNAMIC_ALLOCATION */ } @@ -347,12 +357,36 @@ swupdate_create_resource(size_t device) void oc_swupdate_create(void) { - swupdate_init(); - for (size_t i = 0; i < oc_core_get_num_devices(); ++i) { + size_t device_count = oc_core_get_num_devices(); + swupdate_init(device_count); + for (size_t i = 0; i < device_count; ++i) { swupdate_create_resource(i); } } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_swupdate_create_at_index(size_t device_index, bool need_realloc) +{ + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + if (need_realloc) { + oc_swupdate_t *sw = + (oc_swupdate_t *)realloc(g_sw, device_count * sizeof(oc_swupdate_t)); + if (sw == NULL) { + oc_abort("Insufficient memory"); + } + g_sw = sw; + } else { + swupdate_item_free(&g_sw[device_index]); + } + memset(&g_sw[device_index], 0, sizeof(oc_swupdate_t)); + swupdate_create_resource(device_index); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + const char * oc_swupdate_action_to_str(oc_swupdate_action_t action) { diff --git a/api/oc_swupdate_internal.h b/api/oc_swupdate_internal.h index c84bab359..30214242d 100644 --- a/api/oc_swupdate_internal.h +++ b/api/oc_swupdate_internal.h @@ -23,6 +23,8 @@ #include "oc_helpers.h" #include "oc_swupdate.h" #include "util/oc_compiler.h" +#include "util/oc_features.h" + #include #include @@ -68,6 +70,14 @@ typedef struct oc_swupdate_t */ void oc_swupdate_create(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD +/** + * @brief Allocate and initialize Software Update (SWU) resources and data for + * specific Device. + */ +void oc_swupdate_create_at_index(size_t device_index, bool need_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** * @brief Deallocate all SWU resource data. */ diff --git a/api/unittest/collectiontest.cpp b/api/unittest/collectiontest.cpp index 054e35a98..03c4db4dc 100644 --- a/api/unittest/collectiontest.cpp +++ b/api/unittest/collectiontest.cpp @@ -1,6 +1,7 @@ /**************************************************************************** * * Copyright (c) 2023 plgd.dev s.r.o. + * Copyright (c) 2024 ETRI * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. diff --git a/api/unittest/coreresourcetest.cpp b/api/unittest/coreresourcetest.cpp index f9a9882b1..55e202f62 100644 --- a/api/unittest/coreresourcetest.cpp +++ b/api/unittest/coreresourcetest.cpp @@ -1,6 +1,8 @@ /****************************************************************** * * Copyright 2018 GRANITE RIVER LABS All Rights Reserved. + * 2024 ETRI All Rights Reserved. + * * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -19,10 +21,12 @@ #include "api/oc_core_res_internal.h" #include "api/oc_ri_internal.h" #include "api/oc_runtime_internal.h" +#include "api/oc_swupdate_internal.h" #include "oc_api.h" #include "oc_core_res.h" #include "oc_helpers.h" #include "port/oc_network_event_handler_internal.h" +#include "security/oc_svr_internal.h" #include "tests/gtest/Device.h" #include "tests/gtest/RepPool.h" #include "util/oc_macros_internal.h" @@ -81,11 +85,28 @@ TEST_F(TestCoreResource, CoreDevice_P) cfg.rt = kDeviceType.c_str(); cfg.spec_version = kOCFSpecVersion.c_str(); cfg.data_model_version = kOCFDataModelVersion.c_str(); + +#ifdef OC_HAS_FEATURE_DEVICE_ADD + oc_device_info_t *addcoredevice = + oc_core_add_or_update_device_at_index(cfg, 0); +#else /* !OC_HAS_FEATURE_DEVICE_ADD */ oc_device_info_t *addcoredevice = oc_core_add_new_device(cfg); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + ASSERT_NE(addcoredevice, nullptr); size_t numcoredevice = oc_core_get_num_devices(); EXPECT_EQ(1, numcoredevice); + +#ifdef OC_HAS_FEATURE_DEVICE_ADD +#ifdef OC_SECURITY + oc_sec_svr_free(); +#endif /* OC_SECURITY */ +#ifdef OC_SOFTWARE_UPDATE + oc_swupdate_free(); +#endif /* OC_SOFTWARE_UPDATE */ +#else /* !OC_HAS_FEATURE_DEVICE_ADD */ oc_connectivity_shutdown(kDevice1ID); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ } static void @@ -562,3 +583,62 @@ TEST_F(TestCoreResourceWithDevice, BindDeviceResourceType_P) } #endif /* OC_DYNAMIC_ALLOCATION */ + +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +class TestCoreResourceExt : public testing::Test { +public: + void SetUp() override + { + oc_network_event_handler_mutex_init(); + oc_runtime_init(); + oc_ri_init(); + oc_core_init(); + } + + void TearDown() override + { +#ifdef OC_SECURITY + oc_sec_svr_free(); +#endif /* OC_SECURITY */ +#ifdef OC_SOFTWARE_UPDATE + oc_swupdate_free(); +#endif /* OC_SOFTWARE_UPDATE */ +#ifdef OC_HAS_FEATURE_PUSH + oc_push_free(); +#endif /* OC_HAS_FEATURE_PUSH */ + oc_core_shutdown(); + oc_ri_shutdown(); + oc_runtime_shutdown(); + oc_network_event_handler_mutex_destroy(); + } +}; + +TEST_F(TestCoreResourceExt, CoreAddNRemoveDeviceAtIndex) +{ + oc_add_new_device_t cfg{}; + cfg.name = kDeviceName.c_str(); + cfg.uri = kDeviceURI.c_str(); + cfg.rt = kDeviceType.c_str(); + cfg.spec_version = kOCFSpecVersion.c_str(); + cfg.data_model_version = kOCFDataModelVersion.c_str(); + + /* device index is outranged => should fail */ + size_t device_count = oc_core_get_num_devices(); + EXPECT_EQ(oc_core_add_or_update_device_at_index(cfg, device_count + 1), + nullptr); + + /* add new device at the end of array => should succeed */ + EXPECT_NE(oc_core_add_or_update_device_at_index(cfg, device_count), nullptr); + + /* try to overwrite new device onto existing device => should fail */ + EXPECT_EQ(oc_core_add_or_update_device_at_index(cfg, device_count), nullptr); + + /* try to find device with device id => should succeed */ + size_t device_index; + oc_core_get_device_index(oc_core_get_device_info(device_count)->di, + &device_index); + EXPECT_EQ(device_index, device_count); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ diff --git a/api/unittest/uuidtest.cpp b/api/unittest/uuidtest.cpp index d9aade5cc..6c00e2ac2 100644 --- a/api/unittest/uuidtest.cpp +++ b/api/unittest/uuidtest.cpp @@ -30,7 +30,7 @@ constexpr const char UUID2[] = "XYZabcdefghijklmnopqrstuvwxyz012"; using uuid_buffer_t = std::array; -TEST(UUID, UUIDIsNill) +TEST(UUID, IsEmptyTest_P) { oc_uuid_t uuid{}; EXPECT_TRUE(oc_uuid_is_empty(uuid)); diff --git a/include/oc_api.h b/include/oc_api.h index cd9016893..336919bc1 100644 --- a/include/oc_api.h +++ b/include/oc_api.h @@ -1245,6 +1245,7 @@ void oc_resource_set_request_handler(oc_resource_t *resource, oc_method_t method, oc_request_callback_t callback, void *user_data) OC_NONNULL(1); + #ifdef OC_OSCORE /** * @brief sets the support of the secure multicast feature diff --git a/include/oc_ri.h b/include/oc_ri.h index 7a6d44373..f8fb7a4c0 100644 --- a/include/oc_ri.h +++ b/include/oc_ri.h @@ -619,7 +619,6 @@ bool oc_ri_on_delete_resource_add_callback(oc_ri_delete_resource_cb_t cb) OC_API bool oc_ri_on_delete_resource_remove_callback(oc_ri_delete_resource_cb_t cb) OC_NONNULL(); - #endif /* OC_SERVER */ /** diff --git a/security/oc_acl.c b/security/oc_acl.c index f5694e635..46ad2b78f 100644 --- a/security/oc_acl.c +++ b/security/oc_acl.c @@ -77,6 +77,32 @@ oc_sec_acl_init(void) } } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_acl_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_acl_t *aclist = + (oc_sec_acl_t *)realloc(g_aclist, device_count * sizeof(oc_sec_acl_t)); + if (aclist == NULL) { + oc_abort("Insufficient memory"); + } + g_aclist = aclist; + for (size_t i = 0; i < device_index; ++i) { + OC_LIST_STRUCT_REINIT(&g_aclist[i], subjects); + } + } else { + oc_sec_acl_clear(device_index, NULL, NULL); + } + memset(&g_aclist[device_index], 0, sizeof(oc_sec_acl_t)); + OC_LIST_STRUCT_INIT(&g_aclist[device_index], subjects); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + oc_sec_acl_t * oc_sec_get_acl(size_t device) { @@ -1014,9 +1040,10 @@ oc_sec_acl_free(void) oc_sec_acl_clear(device, NULL, NULL); } #ifdef OC_DYNAMIC_ALLOCATION - if (g_aclist != NULL) { - free(g_aclist); - } + free(g_aclist); + g_aclist = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_aclist, 0, sizeof(g_aclist)); #endif /* OC_DYNAMIC_ALLOCATION */ } diff --git a/security/oc_acl_internal.h b/security/oc_acl_internal.h index 392fbfba3..dfcf681ae 100644 --- a/security/oc_acl_internal.h +++ b/security/oc_acl_internal.h @@ -36,6 +36,20 @@ extern "C" { #define OC_ACE_WC_ALL_PUBLIC_STR "-" void oc_sec_acl_init(void); + +#ifdef OC_HAS_FEATURE_DEVICE_ADD +/** + * @brief increase existing memory for acl for all Devices + * by the size of `oc_sec_acl_t` + * + * @param device_index index of `g_oc_device_info[]` where new Device is + * stored + * @param needs_realloc indicates whether reallocation of memory for SVR is + * needed or not + */ +void oc_sec_acl_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_acl_free(void); void oc_sec_acl_default(size_t device); bool oc_sec_encode_acl(size_t device, oc_interface_mask_t iface_mask, diff --git a/security/oc_ael.c b/security/oc_ael.c index a7904b999..908b29548 100644 --- a/security/oc_ael.c +++ b/security/oc_ael.c @@ -34,13 +34,13 @@ #ifdef OC_DYNAMIC_ALLOCATION #include "port/oc_assert.h" #include -static oc_sec_ael_t *ael; +static oc_sec_ael_t *g_ael; #else /* OC_DYNAMIC_ALLOCATION */ -static oc_sec_ael_t ael[OC_MAX_NUM_DEVICES]; +static oc_sec_ael_t g_ael[OC_MAX_NUM_DEVICES]; #endif /* !OC_DYNAMIC_ALLOCATION */ // Can set specific capacity limits to the below allocators for static builds -OC_MEMB(events_s, oc_sec_ael_event_t, 1); -OC_MEMB(aux_s, oc_sec_ael_aux_info_t, 1); +OC_MEMB(g_events_s, oc_sec_ael_event_t, 1); +OC_MEMB(g_aux_s, oc_sec_ael_aux_info_t, 1); // Theoretical maximum number of entries in the auxiliaryinfo #define AEL_AUX_INFO_MAX_ITEMS (256) @@ -75,17 +75,17 @@ oc_sec_ael_free_event(oc_sec_ael_event_t *event) (oc_sec_ael_aux_info_t *)oc_list_pop(event->aux_info); while (aux) { oc_free_string(&aux->aux_info); - oc_memb_free(&aux_s, aux); + oc_memb_free(&g_aux_s, aux); aux = (oc_sec_ael_aux_info_t *)oc_list_pop(event->aux_info); } - oc_memb_free(&events_s, event); + oc_memb_free(&g_events_s, event); } } static inline size_t oc_sec_ael_max_space(size_t device) { - const oc_sec_ael_t *a = &ael[device]; + const oc_sec_ael_t *a = &g_ael[device]; size_t res = (size_t)OC_SEC_AEL_MAX_SIZE; switch (a->unit) { case OC_SEC_AEL_UNIT_BYTE: @@ -100,9 +100,9 @@ oc_sec_ael_max_space(size_t device) static inline size_t oc_sec_ael_used_space(size_t device) { - const oc_sec_ael_t *a = &ael[device]; + const oc_sec_ael_t *a = &g_ael[device]; size_t res = 0; - switch (ael->unit) { + switch (g_ael->unit) { case OC_SEC_AEL_UNIT_BYTE: res = a->events_size; break; @@ -117,25 +117,54 @@ void oc_sec_ael_init(void) { #ifdef OC_DYNAMIC_ALLOCATION - ael = (oc_sec_ael_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_ael_t)); - if (!ael) { + g_ael = + (oc_sec_ael_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_ael_t)); + if (!g_ael) { oc_abort("Insufficient memory"); } #endif /* OC_DYNAMIC_ALLOCATION */ for (size_t device = 0; device < oc_core_get_num_devices(); device++) { - OC_LIST_STRUCT_INIT(&ael[device], events); + OC_LIST_STRUCT_INIT(&g_ael[device], events); } } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_ael_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_ael_t *ael = + (oc_sec_ael_t *)realloc(g_ael, device_count * sizeof(oc_sec_ael_t)); + if (ael == NULL) { + oc_abort("Insufficient memory"); + } + g_ael = ael; + for (size_t i = 0; i < device_index; ++i) { + OC_LIST_STRUCT_REINIT(&g_ael[i], events); + } + } else { + oc_sec_ael_reset(device_index); + } + memset(&g_ael[device_index], 0, sizeof(oc_sec_ael_t)); + OC_LIST_STRUCT_INIT(&g_ael[device_index], events); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_ael_free(void) { - for (size_t device = 0; device < oc_core_get_num_devices(); device++) { + for (size_t device = 0; device < oc_core_get_num_devices(); ++device) { oc_sec_ael_reset(device); } #ifdef OC_DYNAMIC_ALLOCATION - free(ael); - ael = NULL; + free(g_ael); + g_ael = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_ael, 0, sizeof(g_ael)); #endif /* OC_DYNAMIC_ALLOCATION */ } @@ -143,7 +172,7 @@ void oc_sec_ael_default(size_t device) { oc_sec_ael_reset(device); - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; a->categoryfilter = OC_SEC_AEL_CATEGORYFILTER_DEFAULT; a->priorityfilter = OC_SEC_AEL_PRIORITYFILTER_DEFAULT; a->maxsize = (size_t)OC_SEC_AEL_MAX_SIZE; @@ -213,7 +242,7 @@ bool oc_sec_ael_encode(size_t device, oc_interface_mask_t iface_mask, bool to_storage) { - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; char tmpstr[64]; oc_rep_start_root_object(); if (to_storage || iface_mask & OC_IF_BASELINE) { @@ -284,7 +313,7 @@ oc_sec_ael_encode(size_t device, oc_interface_mask_t iface_mask, bool oc_sec_ael_decode(size_t device, const oc_rep_t *rep, bool from_storage) { - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; const oc_rep_t *repc = rep; for (; repc; repc = repc->next) { size_t len = oc_string_len(repc->name); @@ -392,7 +421,7 @@ oc_sec_ael_decode(size_t device, const oc_rep_t *rep, bool from_storage) static void oc_sec_ael_reset(size_t device) { - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; oc_sec_ael_event_t *e = (oc_sec_ael_event_t *)oc_list_pop(a->events); while (e) { oc_sec_ael_free_event(e); @@ -407,7 +436,7 @@ oc_sec_ael_add_event(size_t device, uint8_t category, uint8_t priority, bool write_to_storage) { bool res = false; - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; if (!(a->categoryfilter & category) || (a->priorityfilter < priority)) { OC_DBG("Event category %d or priority %d not matching", category, priority); @@ -473,7 +502,7 @@ oc_sec_ael_create_event(size_t device, uint8_t category, uint8_t priority, size_t aux_size, size_t event_sz) { // allocate memory - oc_sec_ael_event_t *res = (oc_sec_ael_event_t *)oc_memb_alloc(&events_s); + oc_sec_ael_event_t *res = (oc_sec_ael_event_t *)oc_memb_alloc(&g_events_s); if (!res) { OC_ERR("Out of memory!"); return NULL; @@ -492,7 +521,7 @@ oc_sec_ael_create_event(size_t device, uint8_t category, uint8_t priority, if (aux_info && aux_size > 0) { for (size_t i = 0; i < aux_size; i++) { oc_sec_ael_aux_info_t *a_info = - (oc_sec_ael_aux_info_t *)oc_memb_alloc(&aux_s); + (oc_sec_ael_aux_info_t *)oc_memb_alloc(&g_aux_s); if (a_info) { oc_new_string(&a_info->aux_info, aux_info[i], strlen(aux_info[i])); oc_list_add(res->aux_info, a_info); @@ -500,7 +529,7 @@ oc_sec_ael_create_event(size_t device, uint8_t category, uint8_t priority, } } - oc_sec_ael_t *a = &ael[device]; + oc_sec_ael_t *a = &g_ael[device]; oc_list_add(a->events, res); return res; diff --git a/security/oc_ael_internal.h b/security/oc_ael_internal.h index 16babf4b9..1e7dff961 100644 --- a/security/oc_ael_internal.h +++ b/security/oc_ael_internal.h @@ -19,7 +19,7 @@ #ifndef OC_AEL_INTERNAL_H #define OC_AEL_INTERNAL_H -#include "oc_config.h" +#include "util/oc_features.h" #ifdef OC_SECURITY @@ -92,6 +92,11 @@ typedef struct oc_sec_ael_t } oc_sec_ael_t; void oc_sec_ael_init(void); + +#ifdef OC_HAS_FEATURE_DEVICE_ADD +void oc_sec_ael_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_ael_free(void); void oc_sec_ael_default(size_t device); diff --git a/security/oc_cred.c b/security/oc_cred.c index d8eb1bfe5..6ffd29a08 100644 --- a/security/oc_cred.c +++ b/security/oc_cred.c @@ -92,6 +92,32 @@ oc_sec_cred_init(void) } } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_cred_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_creds_t *devices = (oc_sec_creds_t *)realloc( + g_devices, device_count * sizeof(oc_sec_creds_t)); + if (devices == NULL) { + oc_abort("Insufficient memory"); + } + g_devices = devices; + for (size_t i = 0; i < device_index; ++i) { + OC_LIST_STRUCT_REINIT(&g_devices[i], creds); + } + } else { + oc_sec_cred_clear(device_index, NULL, NULL); + } + memset(&g_devices[device_index], 0, sizeof(oc_sec_creds_t)); + OC_LIST_STRUCT_INIT(&g_devices[device_index], creds); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + static oc_sec_cred_t * cred_get_by_credid(int credid, bool roles_resource, const oc_tls_peer_t *client, size_t device) @@ -309,10 +335,10 @@ oc_sec_cred_deinit(void) oc_sec_cred_clear(device, NULL, NULL); } #ifdef OC_DYNAMIC_ALLOCATION - if (g_devices != NULL) { - free(g_devices); - g_devices = NULL; - } + free(g_devices); + g_devices = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_devices, 0, sizeof(g_devices)); #endif /* OC_DYNAMIC_ALLOCATION */ } diff --git a/security/oc_cred_internal.h b/security/oc_cred_internal.h index 1b5172ba0..811b2570e 100644 --- a/security/oc_cred_internal.h +++ b/security/oc_cred_internal.h @@ -24,6 +24,7 @@ #include "oc_ri.h" #include "oc_uuid.h" #include "util/oc_compiler.h" +#include "util/oc_features.h" #include #include @@ -86,6 +87,20 @@ oc_sec_cred_t *oc_sec_cred_remove_from_device_by_credid(int credid, void oc_sec_cred_default(size_t device); void oc_sec_cred_init(void); void oc_sec_cred_deinit(void); + +#ifdef OC_HAS_FEATURE_DEVICE_ADD +/** + * @brief increase existing memory for cred for all Devices + * by the size of `oc_sec_creds_t` + * + * @param device_index index of `g_oc_device_info[]` where new Device is + * stored + * @param needs_realloc indicates whether reallocation of memory for SVR is + * needed or not + */ +void oc_sec_cred_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_encode_cred(size_t device, oc_interface_mask_t iface_mask, bool to_storage); bool oc_sec_decode_cred(const oc_rep_t *rep, oc_sec_cred_t **owner, diff --git a/security/oc_doxm.c b/security/oc_doxm.c index ca6b9d2d2..f9fff31a2 100644 --- a/security/oc_doxm.c +++ b/security/oc_doxm.c @@ -186,10 +186,10 @@ oc_sec_doxm_free(void) { oc_ownership_status_free_all_cbs(); #ifdef OC_DYNAMIC_ALLOCATION - if (g_doxm != NULL) { - free(g_doxm); - g_doxm = NULL; - } + free(g_doxm); + g_doxm = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_doxm, 0, sizeof(g_doxm)); #endif /* OC_DYNAMIC_ALLOCATION */ } @@ -206,6 +206,26 @@ oc_sec_doxm_init(void) oc_set_select_oxms_cb(NULL, NULL); } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_doxm_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_doxm_t *doxm = + (oc_sec_doxm_t *)realloc(g_doxm, device_count * sizeof(oc_sec_doxm_t)); + if (doxm == NULL) { + oc_abort("Insufficient memory"); + } + g_doxm = doxm; + } + memset(&g_doxm[device_index], 0, sizeof(oc_sec_doxm_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + static void doxm_evaluate_supported_oxms(size_t device) { diff --git a/security/oc_doxm_internal.h b/security/oc_doxm_internal.h index 55c01e112..15832c48f 100644 --- a/security/oc_doxm_internal.h +++ b/security/oc_doxm_internal.h @@ -66,6 +66,18 @@ typedef struct /** @brief Allocate and initialize global variables */ void oc_sec_doxm_init(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD +/** + * by the size of `oc_sec_doxm_t` + * + * @param device_index index of `g_oc_device_info[]` where new Device is + * stored + * @param needs_realloc indicates whether reallocation of memory for SVR is + * needed or not + */ +void oc_sec_doxm_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** @brief Deallocate global variables */ void oc_sec_doxm_free(void); diff --git a/security/oc_pstat.c b/security/oc_pstat.c index fc9e6673a..0523d7a3c 100644 --- a/security/oc_pstat.c +++ b/security/oc_pstat.c @@ -67,10 +67,8 @@ void oc_sec_pstat_free(void) { #ifdef OC_DYNAMIC_ALLOCATION - if (g_pstat != NULL) { - free(g_pstat); - g_pstat = NULL; - } + free(g_pstat); + g_pstat = NULL; #else memset(g_pstat, 0, sizeof(g_pstat)); #endif /* OC_DYNAMIC_ALLOCATION */ @@ -97,6 +95,26 @@ oc_sec_pstat_init(void) #endif /* OC_DYNAMIC_ALLOCATION */ } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_pstat_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_pstat_t *pstat = + (oc_sec_pstat_t *)realloc(g_pstat, device_count * sizeof(oc_sec_pstat_t)); + if (pstat == NULL) { + oc_abort("Insufficient memory"); + } + g_pstat = pstat; + } + memset(&g_pstat[device_index], 0, sizeof(oc_sec_pstat_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + static bool nil_uuid(const oc_uuid_t *uuid) { diff --git a/security/oc_pstat_internal.h b/security/oc_pstat_internal.h index 1b49bb51c..d1c6afc87 100644 --- a/security/oc_pstat_internal.h +++ b/security/oc_pstat_internal.h @@ -64,6 +64,20 @@ void oc_sec_pstat_init(void); /** @brief Deallocate global variables */ void oc_sec_pstat_free(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +/** + * @brief increase existing memory for pstat for all Devices + * by the size of `oc_sec_pstat_t` + * + * @param device_index index of `g_oc_device_info[]` where new Device is stored + * @param needs_realloc indicates whether reallocation of memory for SVR is + * needed or not + */ +void oc_sec_pstat_init_at_index(size_t device_index, bool needs_realloc); + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** * @brief Get pstat resource representation for given device * diff --git a/security/oc_sdi.c b/security/oc_sdi.c index 5b137c3ed..d40925b9e 100644 --- a/security/oc_sdi.c +++ b/security/oc_sdi.c @@ -55,20 +55,45 @@ oc_sec_sdi_init(void) #endif /* OC_DYNAMIC_ALLOCATION */ } +static void +sec_sdi_free(oc_sec_sdi_t *sdi) +{ + oc_free_string(&sdi->name); +} + +#ifdef OC_HAS_FEATURE_DEVICE_ADD + void -oc_sec_sdi_free(void) +oc_sec_sdi_init_at_index(size_t device_index, bool needs_realloc) { -#ifdef OC_DYNAMIC_ALLOCATION - if (g_sdi == NULL) { - return; + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_sdi_t *sdi = + (oc_sec_sdi_t *)realloc(g_sdi, device_count * sizeof(oc_sec_sdi_t)); + if (sdi == NULL) { + oc_abort("Insufficient memory"); + } + g_sdi = sdi; + } else { + sec_sdi_free(&g_sdi[device_index]); } -#endif /* OC_DYNAMIC_ALLOCATION */ + memset(&g_sdi[device_index], 0, sizeof(oc_sec_sdi_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + +void +oc_sec_sdi_free(void) +{ for (size_t device = 0; device < oc_core_get_num_devices(); ++device) { - oc_free_string(&(g_sdi[device].name)); + sec_sdi_free(&g_sdi[device]); } - #ifdef OC_DYNAMIC_ALLOCATION free(g_sdi); + g_sdi = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_sdi, 0, sizeof(g_sdi)); #endif /* OC_DYNAMIC_ALLOCATION */ } diff --git a/security/oc_sdi_internal.h b/security/oc_sdi_internal.h index 06aaa4fc6..3654254e4 100644 --- a/security/oc_sdi_internal.h +++ b/security/oc_sdi_internal.h @@ -49,6 +49,10 @@ typedef struct */ void oc_sec_sdi_init(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD +void oc_sec_sdi_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** * @brief Deallocate all sdi resource data. */ diff --git a/security/oc_sp.c b/security/oc_sp.c index b87546e4b..23a2f31c7 100644 --- a/security/oc_sp.c +++ b/security/oc_sp.c @@ -54,37 +54,74 @@ oc_pki_set_security_profile(size_t device, unsigned supported_profiles, g_sp[device] = g_sp_mfg_default[device]; } +static void +sp_default_init(size_t device) +{ + g_sp_mfg_default[device].current_profile = OC_SP_BASELINE; + g_sp_mfg_default[device].supported_profiles = OC_SP_BASELINE; + g_sp_mfg_default[device].credid = -1; +} + void oc_sec_sp_init(void) { + size_t device_count = oc_core_get_num_devices(); #ifdef OC_DYNAMIC_ALLOCATION - g_sp = (oc_sec_sp_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_sp_t)); - if (!g_sp) { + g_sp = (oc_sec_sp_t *)calloc(device_count, sizeof(oc_sec_sp_t)); + if (g_sp == NULL) { oc_abort("Insufficient memory"); } - g_sp_mfg_default = - (oc_sec_sp_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_sp_t)); - if (!g_sp_mfg_default) { + g_sp_mfg_default = (oc_sec_sp_t *)calloc(device_count, sizeof(oc_sec_sp_t)); + if (g_sp_mfg_default == NULL) { oc_abort("Insufficient memory"); } #endif /* OC_DYNAMIC_ALLOCATION */ - for (size_t device = 0; device < oc_core_get_num_devices(); ++device) { - g_sp_mfg_default[device].current_profile = OC_SP_BASELINE; - g_sp_mfg_default[device].supported_profiles = OC_SP_BASELINE; - g_sp_mfg_default[device].credid = -1; + for (size_t device = 0; device < device_count; ++device) { + sp_default_init(device); + } +} + +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_sp_init_at_index(size_t device_index, bool needs_realloc) +{ + if (needs_realloc) { + size_t device_count = oc_core_get_num_devices(); + assert(device_index == device_count - 1); + oc_sec_sp_t *sp = + (oc_sec_sp_t *)realloc(g_sp, device_count * sizeof(oc_sec_sp_t)); + if (sp == NULL) { + oc_abort("Insufficient memory"); + } + g_sp = sp; + + oc_sec_sp_t *sp_mfg_default = (oc_sec_sp_t *)realloc( + g_sp_mfg_default, device_count * sizeof(oc_sec_sp_t)); + if (sp_mfg_default == NULL) { + oc_abort("Insufficient memory"); + } + g_sp_mfg_default = sp_mfg_default; } + memset(&g_sp[device_index], 0, sizeof(oc_sec_sp_t)); + memset(&g_sp_mfg_default[device_index], 0, sizeof(oc_sec_sp_t)); + sp_default_init(device_index); } +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_sp_free(void) { #ifdef OC_DYNAMIC_ALLOCATION - if (g_sp) { - free(g_sp); - } - if (g_sp_mfg_default) { - free(g_sp_mfg_default); - } + free(g_sp); + g_sp = NULL; + + free(g_sp_mfg_default); + g_sp_mfg_default = NULL; +#else /* !OC_DYNAMIC_ALLOCATION */ + memset(g_sp, 0, sizeof(g_sp)); + memset(g_sp_mfg_default, 0, sizeof(g_sp_mfg_default)); #endif /* OC_DYNAMIC_ALLOCATION */ } diff --git a/security/oc_sp_internal.h b/security/oc_sp_internal.h index 880583d11..5526eebd2 100644 --- a/security/oc_sp_internal.h +++ b/security/oc_sp_internal.h @@ -51,6 +51,10 @@ typedef struct /** @brief Allocate and initialize global variables */ void oc_sec_sp_init(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD +void oc_sec_sp_init_at_index(size_t device_index, bool needs_realloc); +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** @brief Deallocate global variables */ void oc_sec_sp_free(void); diff --git a/security/oc_svr.c b/security/oc_svr.c index ed35991c8..5ed5938d7 100644 --- a/security/oc_svr.c +++ b/security/oc_svr.c @@ -35,6 +35,10 @@ #include "oc_svr_internal.h" #include "port/oc_log_internal.h" +#ifdef OC_HAS_FEATURE_DEVICE_ADD +#include "oc_store.h" +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_svr_create(void) { @@ -70,6 +74,69 @@ oc_sec_svr_create(void) } } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +void +oc_sec_svr_create_new_device(size_t device_index, bool needs_realloc) +{ + oc_sec_doxm_init_at_index(device_index, needs_realloc); + oc_sec_pstat_init_at_index(device_index, needs_realloc); + oc_sec_acl_init_at_index(device_index, needs_realloc); + oc_sec_cred_init_at_index(device_index, needs_realloc); + oc_sec_ael_init_at_index(device_index, needs_realloc); + oc_sec_sp_init_at_index(device_index, needs_realloc); + oc_sec_sdi_init_at_index(device_index, needs_realloc); + + oc_sec_doxm_create_resource(device_index); + oc_core_populate_resource(OCF_SEC_PSTAT, device_index, "/oic/sec/pstat", + OC_IF_RW | OC_IF_BASELINE, OC_IF_RW, + OC_DISCOVERABLE | OC_OBSERVABLE, get_pstat, 0, + post_pstat, 0, 1, "oic.r.pstat"); + oc_core_populate_resource(OCF_SEC_ACL, device_index, "/oic/sec/acl2", + OC_IF_RW | OC_IF_BASELINE, OC_IF_RW, + OC_DISCOVERABLE | OC_SECURE, get_acl, 0, post_acl, + delete_acl, 1, "oic.r.acl2"); + oc_sec_cred_create_resource(device_index); + oc_core_populate_resource(OCF_SEC_AEL, device_index, "/oic/sec/ael", + OC_IF_RW | OC_IF_BASELINE, OC_IF_RW, + OC_DISCOVERABLE | OC_SECURE, get_ael, 0, post_ael, + 0, 1, "oic.r.ael"); + + oc_sec_sp_create_resource(device_index); + oc_sec_sdi_create_resource(device_index); +#ifdef OC_PKI + oc_sec_csr_create_resource(device_index); + oc_sec_roles_create_resource(device_index); +#endif /* OC_PKI */ +} + +void +oc_sec_svr_init_new_device(size_t device_index) +{ + oc_sec_load_unique_ids(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading pstat(%zu)", device_index); + oc_sec_load_pstat(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading doxm(%zu)", device_index); + oc_sec_load_doxm(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading cred(%zu)", device_index); + oc_sec_load_cred(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading acl(%zu)", device_index); + oc_sec_load_acl(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading sp(%zu)", device_index); + oc_sec_load_sp(device_index); + OC_DBG("oc_core_add_new_device_at_index(): loading ael(%zu)", device_index); + oc_sec_load_ael(device_index); +#ifdef OC_PKI + OC_DBG("oc_core_add_new_device_at_index(): loading ECDSA keypair(%zu)", + device_index); + oc_sec_load_ecdsa_keypair(device_index); +#endif /* OC_PKI */ + OC_DBG("oc_core_add_new_device_at_index(): loading sdi(%zu)", device_index); + oc_sec_load_sdi(device_index); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + void oc_sec_svr_free(void) { diff --git a/security/oc_svr_internal.h b/security/oc_svr_internal.h index 173dc6856..a6098adfe 100644 --- a/security/oc_svr_internal.h +++ b/security/oc_svr_internal.h @@ -19,6 +19,9 @@ #ifndef OC_SVR_INTERNAL_H #define OC_SVR_INTERNAL_H +#include "util/oc_features.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -28,6 +31,30 @@ extern "C" { */ void oc_sec_svr_create(void); +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +/** + * @brief add SVR for the Device which is added dynamically. + * new Device should be added to `g_oc_device_info[]` + * before calling this function. + * + * @param device_index index of `g_oc_device_info[]` where new Device is + * stored + * @param needs_realloc indicates whether reallocation of memory for SVR is + * needed or not + */ +void oc_sec_svr_create_new_device(size_t device_index, bool needs_realloc); + +/** + * @brief update SVR with stored values, + * if there is no store data, initialize with default value. + * + * @param device_index index of Device stored in `g_oc_device_info[]` + */ +void oc_sec_svr_init_new_device(size_t device_index); + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + /** * @brief Deinitialize secure vertical resources; */ diff --git a/security/unittest/acltest.cpp b/security/unittest/acltest.cpp index a8d1b4884..2a90312fa 100644 --- a/security/unittest/acltest.cpp +++ b/security/unittest/acltest.cpp @@ -1,6 +1,7 @@ /****************************************************************** * * Copyright 2022 Daniel Adam, All Rights Reserved. + * Copyright 2024 ETRI Joo-Chul Kevin Lee, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -34,7 +35,7 @@ #include "api/oc_push_internal.h" #endif /* OC_HAS_FEATURE_PUSH */ -#include "gtest/gtest.h" +#include #include static const std::string kDeviceURI{ "/oic/d" }; @@ -219,4 +220,32 @@ TEST_F(TestAcl, oc_sec_check_acl_in_RFOTM) } #endif /* OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM */ +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsAclEntryInitialized(const oc_sec_acl_t *aclEntry) +{ + /* + * resource owner should be null + * subject list should be empty + */ + return oc_uuid_is_empty(aclEntry->rowneruuid) && + !oc_list_length(aclEntry->subjects); +} + +TEST_F(TestAcl, AclNewDevice) +{ + /* overwrite entry in the existing position */ + auto aclEntry = oc_sec_get_acl(device_id_); + oc_sec_acl_t orgAcl{}; + memcpy(&orgAcl, aclEntry, sizeof(oc_sec_acl_t)); + + oc_sec_acl_init_at_index(device_id_, false); + EXPECT_EQ(true, IsAclEntryInitialized(aclEntry)); + + memcpy(aclEntry, &orgAcl, sizeof(oc_sec_acl_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/security/unittest/credtest.cpp b/security/unittest/credtest.cpp index 3d9ad4bcf..26188f131 100644 --- a/security/unittest/credtest.cpp +++ b/security/unittest/credtest.cpp @@ -1,6 +1,7 @@ /**************************************************************************** * * Copyright (c) 2023 plgd.dev s.r.o. + * Copyright (c) 2024 ETRI Joo-Chul Kevin Lee * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -405,4 +406,38 @@ TEST_F(TestCreds, Serialize_Fail) #endif /* OC_PKI && (OC_DYNAMIC_ALLOCATION || OC_TEST) */ +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsCredsEntryInitialized(const oc_sec_creds_t *credsEntry) +{ + /* + * resource owner should be null + * subject list should be empty + */ + return oc_uuid_is_empty(credsEntry->rowneruuid) && + !oc_list_length(credsEntry->creds); +} + +/* + * oc_sec_cred_new_device(device_index, need_realloc) + */ +TEST_F(TestCreds, CredNewDevice) +{ + /* + * overwrite entry in the existing position + */ + auto credsEntry = oc_sec_get_creds(kDeviceID); + oc_sec_creds_t orgCreds{}; + + memcpy(&orgCreds, credsEntry, sizeof(oc_sec_creds_t)); + + oc_sec_cred_init_at_index(kDeviceID, false); + EXPECT_EQ(true, IsCredsEntryInitialized(credsEntry)); + + memcpy(credsEntry, &orgCreds, sizeof(oc_sec_creds_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/security/unittest/doxmtest.cpp b/security/unittest/doxmtest.cpp index 61faecaf0..1d1690057 100644 --- a/security/unittest/doxmtest.cpp +++ b/security/unittest/doxmtest.cpp @@ -1,6 +1,8 @@ /****************************************************************** * * Copyright 2023 Daniel Adam, All Rights Reserved. + * Copyright 2024 ETRI Joo-Chul Kevin Lee, All Rights Reserved. + * * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -1076,4 +1078,27 @@ TEST_F(TestDoxmWithServer, Owned_F) #endif /* OC_DYNAMIC_ALLOCATION */ } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsDoxmEntryInitialized(const oc_sec_doxm_t *doxmEntry) +{ + oc_sec_doxm_t emptyDoxm{}; + return !memcmp(doxmEntry, &emptyDoxm, sizeof(oc_sec_doxm_t)); +} + +TEST_F(TestDoxmWithServer, DoxmNewDevice) +{ + auto doxmEntry = oc_sec_get_doxm(kDeviceID); + oc_sec_doxm_t orgDoxm{}; + memcpy(&orgDoxm, doxmEntry, sizeof(oc_sec_doxm_t)); + + oc_sec_doxm_init_at_index(kDeviceID, false); + EXPECT_EQ(true, IsDoxmEntryInitialized(doxmEntry)); + + memcpy(doxmEntry, &orgDoxm, sizeof(oc_sec_doxm_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/security/unittest/pstattest.cpp b/security/unittest/pstattest.cpp index 438581024..f6719f0d2 100644 --- a/security/unittest/pstattest.cpp +++ b/security/unittest/pstattest.cpp @@ -1,6 +1,7 @@ /****************************************************************** * * Copyright 2023 Daniel Adam, All Rights Reserved. + * Copyright 2024 ETRI Joo-Chul Kevin Lee, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -218,4 +219,30 @@ TEST_F(TestPstatWithServer, DeleteRequest_Fail) error_code); } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsPstatEntryInitialized(const oc_sec_pstat_t *pstatEntry) +{ + oc_sec_pstat_t emptyPstat{}; + return !memcmp(pstatEntry, &emptyPstat, sizeof(oc_sec_pstat_t)); +} + +TEST_F(TestPstatWithServer, PstatNewDevice) +{ + /* + * overwrite entry in the existing position + */ + auto pstatEntry = oc_sec_get_pstat(kDeviceID); + oc_sec_pstat_t orgPstat; + memcpy(&orgPstat, pstatEntry, sizeof(oc_sec_pstat_t)); + oc_sec_pstat_init_at_index(kDeviceID, false); + + EXPECT_EQ(true, IsPstatEntryInitialized(pstatEntry)); + + memcpy(pstatEntry, &orgPstat, sizeof(oc_sec_pstat_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/security/unittest/sditest.cpp b/security/unittest/sditest.cpp index a8efa095c..269a5b2ed 100644 --- a/security/unittest/sditest.cpp +++ b/security/unittest/sditest.cpp @@ -1,6 +1,7 @@ /****************************************************************** * * Copyright 2023 Daniel Adam, All Rights Reserved. + * Copyright 2024 ETRI Joo-Chul Kevin Lee, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -400,4 +401,30 @@ TEST_F(TestSdiWithServer, DumpAndLoad) oc_free_string(&def.name); } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsSdiEntryInitialized(const oc_sec_sdi_t *sdiEntry) +{ + oc_sec_sdi_t emptySdi{}; + memset(&emptySdi, 0, sizeof(oc_sec_sdi_t)); + return !memcmp(sdiEntry, &emptySdi, sizeof(oc_sec_sdi_t)); +} + +TEST_F(TestSdiWithServer, SdiNewDevice) +{ + /* + * overwrite entry in the existing position + */ + auto sdiEntry = oc_sec_sdi_get(kDeviceID); + oc_sec_sdi_t orgSdi; + memcpy(&orgSdi, sdiEntry, sizeof(oc_sec_sdi_t)); + oc_sec_sdi_init_at_index(kDeviceID, false); + EXPECT_EQ(true, IsSdiEntryInitialized(sdiEntry)); + + memcpy(sdiEntry, &orgSdi, sizeof(oc_sec_sdi_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/security/unittest/sptest.cpp b/security/unittest/sptest.cpp index 86489efb6..a3e92b157 100644 --- a/security/unittest/sptest.cpp +++ b/security/unittest/sptest.cpp @@ -1,6 +1,7 @@ /****************************************************************** * * Copyright 2023 Daniel Adam, All Rights Reserved. + * Copyright 2024 ETRI Joo-Chul Kevin Lee, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"), * you may not use this file except in compliance with the License. @@ -468,4 +469,33 @@ TEST_F(TestSecurityProfileWithServer, DeleteRequest_Fail) error_code); } +#ifdef OC_HAS_FEATURE_DEVICE_ADD + +static bool +IsSpEntryInitialized(const oc_sec_sp_t *sdiEntry) +{ + return sdiEntry->current_profile == OC_SP_BASELINE && + sdiEntry->supported_profiles == OC_SP_BASELINE && + sdiEntry->credid == -1; +} + +TEST_F(TestSecurityProfile, SpNewDevice) +{ + /* + * overwrite entry in the existing position + */ + auto spEntry = oc_sec_sp_get(kDeviceID); + oc_sec_sp_t orgSp{}; + + memcpy(&orgSp, spEntry, sizeof(oc_sec_sp_t)); + oc_sec_sp_init_at_index(kDeviceID, false); + oc_sec_sp_default(kDeviceID); + + EXPECT_EQ(true, IsSpEntryInitialized(spEntry)); + + memcpy(spEntry, &orgSp, sizeof(oc_sec_sp_t)); +} + +#endif /* OC_HAS_FEATURE_DEVICE_ADD */ + #endif /* OC_SECURITY */ diff --git a/sonar-project.properties b/sonar-project.properties index e2156596d..644f51c8a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,7 +6,7 @@ sonar.organization=iotivity-lite #sonar.projectVersion=1.0 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. -#sonar.sources=. +# sonar.sources=. # TODO: Java, Python, HTML, JavaScript and CSS are disabled until a maintainer is found sonar.exclusions=apps/**,deps/**,docker/**,patches/**,tests/**,tools/**,**/*.java,**/*.py,**/*.html,**/*.js,**/*.css diff --git a/util/oc_features.h b/util/oc_features.h index 908993caa..eeb9e94ff 100644 --- a/util/oc_features.h +++ b/util/oc_features.h @@ -39,6 +39,10 @@ #define OC_HAS_FEATURE_PUSH #endif +#if defined(OC_SERVER) && defined(OC_CLIENT) && defined(OC_DYNAMIC_ALLOCATION) +#define OC_HAS_FEATURE_DEVICE_ADD +#endif + #if defined(OC_SECURITY) && defined(OC_RESOURCE_ACCESS_IN_RFOTM) #define OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM #endif