| /* |
| * 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); |
| } |