13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "att_db_util.c" 39ab2c6ae4SMatthias Ringwald 403deb3ec6SMatthias Ringwald #include <stdlib.h> 413deb3ec6SMatthias Ringwald #include <string.h> 423deb3ec6SMatthias Ringwald 43*46eb6b51SMatthias Ringwald #include "ble/att_db_util.h" 44591423b2SMatthias Ringwald #include "ble/att_db.h" 4559c6af15SMatthias Ringwald #include "ble/core.h" 46eb886013SMatthias Ringwald #include "btstack_util.h" 4716ece135SMatthias Ringwald #include "btstack_debug.h" 48aa4dd815SMatthias Ringwald #include "bluetooth.h" 493deb3ec6SMatthias Ringwald 503deb3ec6SMatthias Ringwald // ATT DB Storage 513deb3ec6SMatthias Ringwald #ifndef HAVE_MALLOC 523deb3ec6SMatthias Ringwald #ifdef MAX_ATT_DB_SIZE 533deb3ec6SMatthias Ringwald static uint8_t att_db_storage[MAX_ATT_DB_SIZE]; 543deb3ec6SMatthias Ringwald #else 553deb3ec6SMatthias Ringwald #error Neither HAVE_MALLOC] nor MAX_ATT_DB_SIZE is defined. 563deb3ec6SMatthias Ringwald #endif 573deb3ec6SMatthias Ringwald #endif 583deb3ec6SMatthias Ringwald 593deb3ec6SMatthias Ringwald static uint8_t * att_db; 603deb3ec6SMatthias Ringwald static uint16_t att_db_size; 613deb3ec6SMatthias Ringwald static uint16_t att_db_max_size; 623deb3ec6SMatthias Ringwald static uint16_t att_db_next_handle; 633deb3ec6SMatthias Ringwald 643deb3ec6SMatthias Ringwald static void att_db_util_set_end_tag(void){ 653deb3ec6SMatthias Ringwald // end tag 663deb3ec6SMatthias Ringwald att_db[att_db_size] = 0; 673deb3ec6SMatthias Ringwald att_db[att_db_size+1] = 0; 683deb3ec6SMatthias Ringwald } 693deb3ec6SMatthias Ringwald 703deb3ec6SMatthias Ringwald void att_db_util_init(void){ 713deb3ec6SMatthias Ringwald #ifdef HAVE_MALLOC 723deb3ec6SMatthias Ringwald att_db = (uint8_t*) malloc(128); 733deb3ec6SMatthias Ringwald att_db_max_size = 128; 743deb3ec6SMatthias Ringwald #else 753deb3ec6SMatthias Ringwald att_db = att_db_storage; 763deb3ec6SMatthias Ringwald att_db_max_size = sizeof(att_db_storage); 773deb3ec6SMatthias Ringwald #endif 783deb3ec6SMatthias Ringwald att_db_size = 0; 793deb3ec6SMatthias Ringwald att_db_next_handle = 1; 803deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 813deb3ec6SMatthias Ringwald } 823deb3ec6SMatthias Ringwald 833deb3ec6SMatthias Ringwald /** 843deb3ec6SMatthias Ringwald * asserts that the requested amount of bytes can be stored in the att_db 853deb3ec6SMatthias Ringwald * @returns TRUE if space is available 863deb3ec6SMatthias Ringwald */ 873deb3ec6SMatthias Ringwald static int att_db_util_assert_space(uint16_t size){ 883deb3ec6SMatthias Ringwald size += 2; // for end tag 893deb3ec6SMatthias Ringwald if (att_db_size + size <= att_db_max_size) return 1; 903deb3ec6SMatthias Ringwald #ifdef HAVE_MALLOC 913deb3ec6SMatthias Ringwald int new_size = att_db_size + att_db_size / 2; 9251261ae3SMatthias Ringwald uint8_t * new_db = (uint8_t*) realloc(att_db, new_size); 9351261ae3SMatthias Ringwald if (!new_db) { 943deb3ec6SMatthias Ringwald log_error("att_db: realloc failed"); 953deb3ec6SMatthias Ringwald return 0; 963deb3ec6SMatthias Ringwald } 9751261ae3SMatthias Ringwald att_db = new_db; 983deb3ec6SMatthias Ringwald att_db_max_size = new_size; 99658d4117SJakob Krantz att_set_db(att_db); // Update att_db with the new db 1003deb3ec6SMatthias Ringwald return 1; 1013deb3ec6SMatthias Ringwald #else 1023deb3ec6SMatthias Ringwald log_error("att_db: out of memory"); 1033deb3ec6SMatthias Ringwald return 0; 1043deb3ec6SMatthias Ringwald #endif 1053deb3ec6SMatthias Ringwald } 1063deb3ec6SMatthias Ringwald 1073deb3ec6SMatthias Ringwald // attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) 1083deb3ec6SMatthias Ringwald 1093deb3ec6SMatthias Ringwald // db endds with 0x00 0x00 1103deb3ec6SMatthias Ringwald 1113deb3ec6SMatthias Ringwald static void att_db_util_add_attribute_uuid16(uint16_t uuid16, uint16_t flags, uint8_t * data, uint16_t data_len){ 1123deb3ec6SMatthias Ringwald int size = 2 + 2 + 2 + 2 + data_len; 1133deb3ec6SMatthias Ringwald if (!att_db_util_assert_space(size)) return; 114f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, size); 1153deb3ec6SMatthias Ringwald att_db_size += 2; 116f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, flags); 1173deb3ec6SMatthias Ringwald att_db_size += 2; 118f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, att_db_next_handle); 1193deb3ec6SMatthias Ringwald att_db_size += 2; 1203deb3ec6SMatthias Ringwald att_db_next_handle++; 121f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, uuid16); 1223deb3ec6SMatthias Ringwald att_db_size += 2; 1233deb3ec6SMatthias Ringwald memcpy(&att_db[att_db_size], data, data_len); 1243deb3ec6SMatthias Ringwald att_db_size += data_len; 1253deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 1263deb3ec6SMatthias Ringwald } 1273deb3ec6SMatthias Ringwald 1283deb3ec6SMatthias Ringwald static void att_db_util_add_attribute_uuid128(uint8_t * uuid128, uint16_t flags, uint8_t * data, uint16_t data_len){ 1293deb3ec6SMatthias Ringwald int size = 2 + 2 + 2 + 16 + data_len; 1303deb3ec6SMatthias Ringwald if (!att_db_util_assert_space(size)) return; 1313deb3ec6SMatthias Ringwald flags |= ATT_PROPERTY_UUID128; 132f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, size); 1333deb3ec6SMatthias Ringwald att_db_size += 2; 134f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, flags); 1353deb3ec6SMatthias Ringwald att_db_size += 2; 136f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, att_db_next_handle); 1373deb3ec6SMatthias Ringwald att_db_size += 2; 1383deb3ec6SMatthias Ringwald att_db_next_handle++; 1399c80e4ccSMatthias Ringwald reverse_128(uuid128, &att_db[att_db_size]); 1403deb3ec6SMatthias Ringwald att_db_size += 16; 1413deb3ec6SMatthias Ringwald memcpy(&att_db[att_db_size], data, data_len); 1423deb3ec6SMatthias Ringwald att_db_size += data_len; 1433deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 1443deb3ec6SMatthias Ringwald } 1453deb3ec6SMatthias Ringwald 1463deb3ec6SMatthias Ringwald void att_db_util_add_service_uuid16(uint16_t uuid16){ 1473deb3ec6SMatthias Ringwald uint8_t buffer[2]; 148f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 0, uuid16); 1493deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 2); 1503deb3ec6SMatthias Ringwald } 1513deb3ec6SMatthias Ringwald 1523deb3ec6SMatthias Ringwald void att_db_util_add_service_uuid128(uint8_t * uuid128){ 1533deb3ec6SMatthias Ringwald uint8_t buffer[16]; 1549c80e4ccSMatthias Ringwald reverse_128(uuid128, buffer); 1553deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 16); 1563deb3ec6SMatthias Ringwald } 1573deb3ec6SMatthias Ringwald 158eb6072adSMatthias Ringwald static void att_db_util_add_client_characteristic_configuration(uint16_t properties){ 159eb6072adSMatthias Ringwald uint8_t buffer[2]; 160eb6072adSMatthias Ringwald // keep authentication flags 1618f8dd626SMatthias Ringwald uint16_t flags = (properties & 0x1ff00) | ATT_DB_PERSISTENT_WRITE_CCC | ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION | ATT_PROPERTY_READ | ATT_PROPERTY_WRITE | ATT_PROPERTY_DYNAMIC; 162eb6072adSMatthias Ringwald little_endian_store_16(buffer, 0, 0); 163eb6072adSMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, flags, buffer, 2); 164eb6072adSMatthias Ringwald } 165eb6072adSMatthias Ringwald 1663deb3ec6SMatthias Ringwald uint16_t att_db_util_add_characteristic_uuid16(uint16_t uuid16, uint16_t properties, uint8_t * data, uint16_t data_len){ 1673deb3ec6SMatthias Ringwald uint8_t buffer[5]; 1683deb3ec6SMatthias Ringwald buffer[0] = properties; 169f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 1, att_db_next_handle + 1); 170f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 3, uuid16); 1713deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); 172eb6072adSMatthias Ringwald // drop Broadcast, Notify, Indicate - not used for flags 173eb6072adSMatthias Ringwald uint16_t value_flags = properties & 0x1ffce; 1743deb3ec6SMatthias Ringwald uint16_t value_handle = att_db_next_handle; 175eb6072adSMatthias Ringwald att_db_util_add_attribute_uuid16(uuid16, value_flags, data, data_len); 1763deb3ec6SMatthias Ringwald if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ 177eb6072adSMatthias Ringwald att_db_util_add_client_characteristic_configuration(properties); 1783deb3ec6SMatthias Ringwald } 1793deb3ec6SMatthias Ringwald return value_handle; 1803deb3ec6SMatthias Ringwald } 1813deb3ec6SMatthias Ringwald 1823deb3ec6SMatthias Ringwald uint16_t att_db_util_add_characteristic_uuid128(uint8_t * uuid128, uint16_t properties, uint8_t * data, uint16_t data_len){ 1833deb3ec6SMatthias Ringwald uint8_t buffer[19]; 1843deb3ec6SMatthias Ringwald buffer[0] = properties; 185f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 1, att_db_next_handle + 1); 1869c80e4ccSMatthias Ringwald reverse_128(uuid128, &buffer[3]); 1873deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); 188eb6072adSMatthias Ringwald // drop Broadcast, Notify, Indicate - not used for flags 189eb6072adSMatthias Ringwald uint16_t value_flags = properties & 0x1ffce; 1903deb3ec6SMatthias Ringwald uint16_t value_handle = att_db_next_handle; 191eb6072adSMatthias Ringwald att_db_util_add_attribute_uuid128(uuid128, value_flags, data, data_len); 1923deb3ec6SMatthias Ringwald if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ 193eb6072adSMatthias Ringwald att_db_util_add_client_characteristic_configuration(properties); 1943deb3ec6SMatthias Ringwald } 1953deb3ec6SMatthias Ringwald return value_handle; 1963deb3ec6SMatthias Ringwald } 1973deb3ec6SMatthias Ringwald 1989f28d85dSMatthias Ringwald uint16_t att_db_util_add_descriptor_uuid16(uint16_t uuid16, uint16_t properties, uint8_t * data, uint16_t data_len){ 1999f28d85dSMatthias Ringwald uint16_t value_handle = att_db_next_handle; 2009f28d85dSMatthias Ringwald att_db_util_add_attribute_uuid16(uuid16, properties, data, data_len); 2019f28d85dSMatthias Ringwald return value_handle; 2029f28d85dSMatthias Ringwald } 2039f28d85dSMatthias Ringwald 2049f28d85dSMatthias Ringwald uint16_t att_db_util_add_descriptor_uuid128(uint8_t * uuid128, uint16_t properties, uint8_t * data, uint16_t data_len){ 2059f28d85dSMatthias Ringwald uint16_t value_handle = att_db_next_handle; 2069f28d85dSMatthias Ringwald att_db_util_add_attribute_uuid128(uuid128, properties, data, data_len); 2079f28d85dSMatthias Ringwald return value_handle; 2089f28d85dSMatthias Ringwald } 2099f28d85dSMatthias Ringwald 2103deb3ec6SMatthias Ringwald uint8_t * att_db_util_get_address(void){ 2113deb3ec6SMatthias Ringwald return att_db; 2123deb3ec6SMatthias Ringwald } 2133deb3ec6SMatthias Ringwald 2143deb3ec6SMatthias Ringwald uint16_t att_db_util_get_size(void){ 2153deb3ec6SMatthias Ringwald return att_db_size + 2; // end tag 2163deb3ec6SMatthias Ringwald } 217