/* * Copyright (c) 2022 Samsung Electronics Co., Ltd. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the copyright owner, nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "oapv_def.h" #include "oapv_metadata.h" static oapvm_ctx_t *meta_id_to_ctx(oapvm_t id) { oapvm_ctx_t *ctx; oapv_assert_rv(id, NULL); ctx = (oapvm_ctx_t *)id; oapv_assert_rv(ctx->magic == OAPVM_MAGIC_CODE, NULL); return ctx; } #define div_255_fast(x) (((x) + (((x) + 257) >> 8)) >> 8) static inline u32 meta_get_byte_pld_type(oapv_mdp_t *mdp) { return (mdp->pld_type < 65536 ? div_255_fast(mdp->pld_type) : mdp->pld_type / 255) + 1; } static inline u32 meta_get_byte_pld_size(oapv_mdp_t *mdp) { return (mdp->pld_size < 65536 ? div_255_fast(mdp->pld_size) : mdp->pld_size / 255) + 1; } static inline u32 meta_get_byte_pld_all(oapv_mdp_t *mdp) { return meta_get_byte_pld_type(mdp) + meta_get_byte_pld_size(mdp) + mdp->pld_size; } static oapv_mdp_t **meta_mdp_find_last_with_check(oapv_md_t *md, int type, unsigned char *uuid) { oapv_mdp_t **last_mdp = &md->md_payload; while((*last_mdp) != NULL) { if((*last_mdp) == NULL) break; if((*last_mdp)->pld_type == type) { if(type == OAPV_METADATA_USER_DEFINED) { if(oapv_mcmp(uuid, (*last_mdp)->pld_data, 16) == 0) { return NULL; } } else { return NULL; } } last_mdp = &((*last_mdp)->next); } return last_mdp; } static oapv_mdp_t *meta_md_find_mdp(oapv_md_t *md, int mdt) { oapv_mdp_t *mdp = md->md_payload; while(mdp != NULL) { if(mdp->pld_type == mdt) { break; } mdp = mdp->next; } return mdp; } static int meta_md_free_mdp(oapv_mdp_t *mdp) { oapv_mfree(mdp->pld_data); return OAPV_OK; } static int meta_md_rm_mdp(oapv_md_t *md, int mdt) { oapv_mdp_t *mdp = md->md_payload; oapv_mdp_t *mdp_prev = NULL; while(mdp->pld_type != mdt && mdp->next != NULL) { mdp_prev = mdp; mdp = mdp->next; } if(mdp->pld_type == mdt) { if(mdp_prev == NULL) { md->md_payload = NULL; } else { mdp_prev->next = mdp->next; } meta_md_free_mdp(mdp); md->md_size -= meta_get_byte_pld_all(mdp); md->md_num--; return OAPV_OK; } return OAPV_ERR_NOT_FOUND; } static int meta_md_rm_usd(oapv_md_t *md, unsigned char *uuid) { oapv_mdp_t *mdp = md->md_payload; oapv_mdp_t *mdp_prev = NULL; while(mdp != NULL) { if(mdp->pld_type == OAPV_METADATA_USER_DEFINED) { if(oapv_mcmp(uuid, mdp->pld_data, 16) == 0) { if(mdp_prev == NULL) { md->md_payload = NULL; } else { mdp_prev->next = mdp->next; } oapv_assert_rv(md->md_size >= mdp->pld_size, OAPV_ERR_UNEXPECTED); meta_md_free_mdp(mdp); md->md_size -= meta_get_byte_pld_all(mdp); md->md_num--; return OAPV_OK; } } mdp_prev = mdp; mdp = mdp->next; } return OAPV_ERR_NOT_FOUND; } static oapv_mdp_t *meta_md_find_usd(oapv_md_t *md, unsigned char *uuid) { oapv_mdp_t *mdp = md->md_payload; while(mdp != NULL) { if(mdp->pld_type == OAPV_METADATA_USER_DEFINED) { oapv_md_usd_t *usd = (oapv_md_usd_t *)mdp->pld_data; if(oapv_mcmp(uuid, usd->uuid, 16) == 0) { return mdp; } } mdp = mdp->next; } return NULL; } static int meta_verify_mdp_data(int type, int size, u8 *data) { if(type == OAPV_METADATA_ITU_T_T35) { if(size == 0) { return OAPV_ERR_INVALID_ARGUMENT; } if(*data == 0xFF) { if(size == 1) { return OAPV_ERR_INVALID_ARGUMENT; } } } else if(type == OAPV_METADATA_MDCV) { if(size != 24) { return OAPV_ERR_INVALID_ARGUMENT; } } else if(type == OAPV_METADATA_CLL) { if(size != 4) { return OAPV_ERR_INVALID_ARGUMENT; } } else if(type == OAPV_METADATA_USER_DEFINED) { if(size < 16) { return OAPV_ERR_INVALID_ARGUMENT; } } else { return OAPV_OK; } return OAPV_OK; } static void meta_free_md(oapv_md_t *md) { oapv_mdp_t *mdp = md->md_payload; while(mdp != NULL) { oapv_mdp_t *tmp_mdp = mdp; mdp = mdp->next; if(tmp_mdp->pld_data != NULL) { oapv_mfree(tmp_mdp->pld_data); } oapv_mfree(tmp_mdp); } } int oapvm_set(oapvm_t mid, int group_id, int type, void *data, int size, unsigned char *uuid) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); oapv_assert_rv(md_list, OAPV_ERR_INVALID_ARGUMENT); int ret = meta_verify_mdp_data(type, size, (u8 *)data); oapv_assert_rv(OAPV_SUCCEEDED(ret), ret); int md_list_idx = 0; while(md_list_idx < md_list->num) { if(md_list->group_ids[md_list_idx] == group_id) { break; } md_list_idx++; } if(md_list_idx == md_list->num) { md_list->num++; } md_list->group_ids[md_list_idx] = group_id; oapv_mdp_t **last_ptr = meta_mdp_find_last_with_check(&md_list->md_arr[md_list_idx], type, (type == OAPV_METADATA_USER_DEFINED) ? uuid : NULL); while(last_ptr == NULL) { oapvm_rem(mid, group_id, type, uuid); last_ptr = meta_mdp_find_last_with_check(&md_list->md_arr[md_list_idx], type, (type == OAPV_METADATA_USER_DEFINED) ? uuid : NULL); } oapv_mdp_t *tmp_mdp = oapv_malloc(sizeof(oapv_mdp_t)); oapv_assert_rv(tmp_mdp != NULL, OAPV_ERR_OUT_OF_MEMORY); oapv_mset(tmp_mdp, 0, sizeof(oapv_mdp_t)); tmp_mdp->pld_size = size; tmp_mdp->pld_type = type; tmp_mdp->pld_data = data; *last_ptr = tmp_mdp; md_list->md_arr[md_list_idx].md_size += meta_get_byte_pld_all(tmp_mdp); md_list->md_arr[md_list_idx].md_num++; return OAPV_OK; } int oapvm_get(oapvm_t mid, int group_id, int type, void **data, int *size, unsigned char *uuid) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); for(int i = 0; i < md_list->num; i++) { if(group_id != md_list->group_ids[i]) { continue; } oapv_mdp_t *mdp = (type == OAPV_METADATA_USER_DEFINED) ? meta_md_find_usd(&md_list->md_arr[i], uuid) : meta_md_find_mdp(&md_list->md_arr[i], type); if(mdp != NULL) { *data = mdp->pld_data; *size = mdp->pld_size; return OAPV_OK; } } return OAPV_ERR_NOT_FOUND; } int oapvm_rem(oapvm_t mid, int group_id, int type, unsigned char *uuid) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); int md_list_idx = 0; while(md_list_idx < md_list->num) { if(md_list->group_ids[md_list_idx] == group_id) { break; } md_list_idx++; } oapv_assert_rv(md_list_idx < md_list->num, OAPV_ERR_NOT_FOUND); if(type == OAPV_METADATA_USER_DEFINED) { return meta_md_rm_usd(&md_list->md_arr[md_list_idx], uuid); } return meta_md_rm_mdp(&md_list->md_arr[md_list_idx], type); } int oapvm_set_all(oapvm_t mid, oapvm_payload_t *pld, int num_plds) { int ret; oapvm_ctx_t *md_list = meta_id_to_ctx(mid); for(int i = 0; i < num_plds; i++) { ret = meta_verify_mdp_data(pld[i].type, pld[i].data_size, (u8 *)pld[i].data); oapv_assert_g(OAPV_SUCCEEDED(ret), ERR); int md_list_idx = 0; while(md_list_idx < md_list->num) { if(md_list->group_ids[md_list_idx] == pld[i].group_id) { break; } md_list_idx++; } if(md_list_idx == md_list->num) { md_list->num++; } md_list->group_ids[md_list_idx] = pld[i].group_id; md_list->md_arr[md_list_idx].md_num++; oapv_mdp_t **last_ptr = meta_mdp_find_last_with_check(&md_list->md_arr[md_list_idx], pld[i].type, (pld[i].type == OAPV_METADATA_USER_DEFINED) ? pld[i].uuid : NULL); while(last_ptr == NULL) { oapvm_rem(mid, pld[i].group_id, pld[i].type, pld[i].uuid); last_ptr = meta_mdp_find_last_with_check(&md_list->md_arr[md_list_idx], pld[i].type, (pld[i].type == OAPV_METADATA_USER_DEFINED) ? pld[i].uuid : NULL); } oapv_mdp_t *tmp_mdp = oapv_malloc(sizeof(oapv_mdp_t)); oapv_assert_rv(tmp_mdp != NULL, OAPV_ERR_OUT_OF_MEMORY); oapv_mset(tmp_mdp, 0, sizeof(oapv_mdp_t)); tmp_mdp->pld_size = pld[i].data_size; tmp_mdp->pld_type = pld[i].type; tmp_mdp->pld_data = pld[i].data; md_list->md_arr[md_list_idx].md_size += meta_get_byte_pld_all(tmp_mdp); *last_ptr = tmp_mdp; } return OAPV_OK; ERR: return ret; } int oapvm_get_all(oapvm_t mid, oapvm_payload_t *pld, int *num_plds) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); if(pld == NULL) { int num_payload = 0; for(int i = 0; i < md_list->num; i++) { num_payload += md_list->md_arr[i].md_num; } *num_plds = num_payload; return OAPV_OK; } int p_cnt = 0; for(int i = 0; i < md_list->num; i++) { int group_id = md_list->group_ids[i]; oapv_mdp_t *mdp = md_list->md_arr[i].md_payload; while(mdp != NULL) { oapv_assert_rv(p_cnt < *num_plds, OAPV_ERR_REACHED_MAX); pld[p_cnt].group_id = group_id; pld[p_cnt].data_size = mdp->pld_size; pld[p_cnt].data = mdp->pld_data; pld[p_cnt].type = mdp->pld_type; if(pld[p_cnt].type == OAPV_METADATA_USER_DEFINED) { oapv_mcpy(pld[p_cnt].uuid, mdp->pld_data, 16); } else { oapv_mset(pld[p_cnt].uuid, 0, 16); } p_cnt++; mdp = mdp->next; } } *num_plds = p_cnt; return OAPV_OK; } void oapvm_rem_all(oapvm_t mid) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); for(int i = 0; i < md_list->num; i++) { meta_free_md(&md_list->md_arr[i]); oapv_mset(&md_list->md_arr[i], 0, sizeof(oapv_md_t)); } md_list->num = 0; } oapvm_t oapvm_create(int *err) { oapvm_ctx_t *md_list; md_list = oapv_malloc(sizeof(oapvm_ctx_t)); if(md_list == NULL) { *err = OAPV_ERR_OUT_OF_MEMORY; return NULL; } oapv_mset(md_list, 0, sizeof(oapvm_ctx_t)); md_list->magic = OAPVM_MAGIC_CODE; return md_list; } void oapvm_delete(oapvm_t mid) { oapvm_ctx_t *md_list = meta_id_to_ctx(mid); for(int i = 0; i < md_list->num; i++) { meta_free_md(&md_list->md_arr[i]); } oapv_mfree(md_list); }