1 /* 2 * Copyright (C) 2021 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 21 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #define BTSTACK_FILE__ "btstack_tlv_memory.c" 33 34 #include <stdint.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include "btstack_linked_list.h" 38 #include "btstack_tlv.h" 39 #include "btstack_util.h" 40 #include "btstack_debug.h" 41 42 #include "mock_btstack_tlv.h" 43 44 #define MAX_TLV_VALUE_SIZE 200 45 #define DUMMY_SIZE 4 46 typedef struct tlv_entry { 47 void * next; 48 uint32_t tag; 49 uint32_t len; 50 uint8_t value[DUMMY_SIZE]; // dummy size 51 } tlv_entry_t; 52 53 static tlv_entry_t * mock_btstack_tlv_find_entry(mock_btstack_tlv_t * self, uint32_t tag){ 54 btstack_linked_list_iterator_t it; 55 btstack_linked_list_iterator_init(&it, &self->entry_list); 56 while (btstack_linked_list_iterator_has_next(&it)){ 57 tlv_entry_t * entry = (tlv_entry_t*) btstack_linked_list_iterator_next(&it); 58 if (entry->tag != tag) continue; 59 return entry; 60 } 61 return NULL; 62 } 63 64 /** 65 * Get Value for Tag 66 * @param tag 67 * @param buffer 68 * @param buffer_size 69 * @return size of value 70 */ 71 static int mock_btstack_tlv_get_tag(void * context, uint32_t tag, uint8_t * buffer, uint32_t buffer_size){ 72 mock_btstack_tlv_t * self = (mock_btstack_tlv_t *) context; 73 tlv_entry_t * entry = mock_btstack_tlv_find_entry(self, tag); 74 // not found 75 if (!entry) return 0; 76 // return len if buffer = NULL 77 if (!buffer) return entry->len; 78 // otherwise copy data into buffer 79 uint16_t bytes_to_copy = btstack_min(buffer_size, entry->len); 80 memcpy(buffer, &entry->value[0], bytes_to_copy); 81 return bytes_to_copy; 82 } 83 84 /** 85 * Store Tag 86 * @param tag 87 * @param data 88 * @param data_size 89 */ 90 static int mock_btstack_tlv_store_tag(void * context, uint32_t tag, const uint8_t * data, uint32_t data_size){ 91 mock_btstack_tlv_t * self = (mock_btstack_tlv_t *) context; 92 93 // enforce arbitrary max value size 94 btstack_assert(data_size <= MAX_TLV_VALUE_SIZE); 95 96 // remove old entry 97 tlv_entry_t * old_entry = mock_btstack_tlv_find_entry(self, tag); 98 if (old_entry){ 99 btstack_linked_list_remove(&self->entry_list, (btstack_linked_item_t *) old_entry); 100 free(old_entry); 101 } 102 103 // create new entry 104 uint32_t entry_size = sizeof(tlv_entry_t) - DUMMY_SIZE + data_size; 105 tlv_entry_t * new_entry = (tlv_entry_t *) malloc(entry_size); 106 if (!new_entry) return 0; 107 memset(new_entry, 0, entry_size); 108 new_entry->tag = tag; 109 new_entry->len = data_size; 110 memcpy(&new_entry->value[0], data, data_size); 111 112 // append new entry 113 btstack_linked_list_add(&self->entry_list, (btstack_linked_item_t *) new_entry); 114 return 0; 115 } 116 117 /** 118 * Delete Tag 119 * @param tag 120 */ 121 static void mock_btstack_tlv_delete_tag(void * context, uint32_t tag){ 122 mock_btstack_tlv_t * self = (mock_btstack_tlv_t *) context; 123 btstack_linked_list_iterator_t it; 124 btstack_linked_list_iterator_init(&it, &self->entry_list); 125 while (btstack_linked_list_iterator_has_next(&it)){ 126 tlv_entry_t * entry = (tlv_entry_t*) btstack_linked_list_iterator_next(&it); 127 if (entry->tag != tag) continue; 128 btstack_linked_list_iterator_remove(&it); 129 free(entry); 130 return; 131 } 132 } 133 134 static const btstack_tlv_t mock_btstack_tlv = { 135 /* int (*get_tag)(..); */ &mock_btstack_tlv_get_tag, 136 /* int (*store_tag)(..); */ &mock_btstack_tlv_store_tag, 137 /* void (*delete_tag)(v..); */ &mock_btstack_tlv_delete_tag, 138 }; 139 140 /** 141 * Init Tag Length Value Store 142 */ 143 const btstack_tlv_t * mock_btstack_tlv_init_instance(mock_btstack_tlv_t * self){ 144 memset(self, 0, sizeof(mock_btstack_tlv_t)); 145 return &mock_btstack_tlv; 146 } 147 148 /** 149 * Free TLV entries 150 * @param self 151 */ 152 void mock_btstack_tlv_deinit(mock_btstack_tlv_t * self){ 153 // free all entries 154 btstack_linked_list_iterator_t it; 155 btstack_linked_list_iterator_init(&it, &self->entry_list); 156 while (btstack_linked_list_iterator_has_next(&it)){ 157 tlv_entry_t * entry = (tlv_entry_t*) btstack_linked_list_iterator_next(&it); 158 btstack_linked_list_iterator_remove(&it); 159 free(entry); 160 } 161 } 162