1*591423b2SMatthias Ringwald /* 2*591423b2SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*591423b2SMatthias Ringwald * 4*591423b2SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*591423b2SMatthias Ringwald * modification, are permitted provided that the following conditions 6*591423b2SMatthias Ringwald * are met: 7*591423b2SMatthias Ringwald * 8*591423b2SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*591423b2SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*591423b2SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*591423b2SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*591423b2SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*591423b2SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*591423b2SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*591423b2SMatthias Ringwald * from this software without specific prior written permission. 16*591423b2SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*591423b2SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*591423b2SMatthias Ringwald * monetary gain. 19*591423b2SMatthias Ringwald * 20*591423b2SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*591423b2SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*591423b2SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*591423b2SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*591423b2SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*591423b2SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*591423b2SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*591423b2SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*591423b2SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*591423b2SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*591423b2SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*591423b2SMatthias Ringwald * SUCH DAMAGE. 32*591423b2SMatthias Ringwald * 33*591423b2SMatthias Ringwald * Please inquire about commercial licensing options at 34*591423b2SMatthias Ringwald * [email protected] 35*591423b2SMatthias Ringwald * 36*591423b2SMatthias Ringwald */ 37*591423b2SMatthias Ringwald 38*591423b2SMatthias Ringwald 39*591423b2SMatthias Ringwald #include <stdio.h> 40*591423b2SMatthias Ringwald #include <string.h> 41*591423b2SMatthias Ringwald 42*591423b2SMatthias Ringwald #include "bluetooth.h" 43*591423b2SMatthias Ringwald #include "ble/att_db.h" 44*591423b2SMatthias Ringwald #include "btstack_debug.h" 45*591423b2SMatthias Ringwald #include "btstack_util.h" 46*591423b2SMatthias Ringwald 47*591423b2SMatthias Ringwald // Buetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian 48*591423b2SMatthias Ringwald static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 49*591423b2SMatthias Ringwald 50*591423b2SMatthias Ringwald 51*591423b2SMatthias Ringwald static int is_Bluetooth_Base_UUID(uint8_t const *uuid){ 52*591423b2SMatthias Ringwald if (memcmp(&uuid[0], &bluetooth_base_uuid[0], 12)) return 0; 53*591423b2SMatthias Ringwald if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0; 54*591423b2SMatthias Ringwald return 1; 55*591423b2SMatthias Ringwald 56*591423b2SMatthias Ringwald } 57*591423b2SMatthias Ringwald 58*591423b2SMatthias Ringwald static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){ 59*591423b2SMatthias Ringwald if (uuid_len == 2) return little_endian_read_16(uuid, 0); 60*591423b2SMatthias Ringwald if (!is_Bluetooth_Base_UUID(uuid)) return 0; 61*591423b2SMatthias Ringwald return little_endian_read_16(uuid, 12); 62*591423b2SMatthias Ringwald } 63*591423b2SMatthias Ringwald 64*591423b2SMatthias Ringwald // ATT Database 65*591423b2SMatthias Ringwald static uint8_t const * att_db = NULL; 66*591423b2SMatthias Ringwald static att_read_callback_t att_read_callback = NULL; 67*591423b2SMatthias Ringwald static att_write_callback_t att_write_callback = NULL; 68*591423b2SMatthias Ringwald static uint8_t att_prepare_write_error_code = 0; 69*591423b2SMatthias Ringwald static uint16_t att_prepare_write_error_handle = 0x0000; 70*591423b2SMatthias Ringwald 71*591423b2SMatthias Ringwald // new java-style iterator 72*591423b2SMatthias Ringwald typedef struct att_iterator { 73*591423b2SMatthias Ringwald // private 74*591423b2SMatthias Ringwald uint8_t const * att_ptr; 75*591423b2SMatthias Ringwald // public 76*591423b2SMatthias Ringwald uint16_t size; 77*591423b2SMatthias Ringwald uint16_t flags; 78*591423b2SMatthias Ringwald uint16_t handle; 79*591423b2SMatthias Ringwald uint8_t const * uuid; 80*591423b2SMatthias Ringwald uint16_t value_len; 81*591423b2SMatthias Ringwald uint8_t const * value; 82*591423b2SMatthias Ringwald } att_iterator_t; 83*591423b2SMatthias Ringwald 84*591423b2SMatthias Ringwald static void att_iterator_init(att_iterator_t *it){ 85*591423b2SMatthias Ringwald it->att_ptr = att_db; 86*591423b2SMatthias Ringwald } 87*591423b2SMatthias Ringwald 88*591423b2SMatthias Ringwald static int att_iterator_has_next(att_iterator_t *it){ 89*591423b2SMatthias Ringwald return it->att_ptr != NULL; 90*591423b2SMatthias Ringwald } 91*591423b2SMatthias Ringwald 92*591423b2SMatthias Ringwald static void att_iterator_fetch_next(att_iterator_t *it){ 93*591423b2SMatthias Ringwald it->size = little_endian_read_16(it->att_ptr, 0); 94*591423b2SMatthias Ringwald if (it->size == 0){ 95*591423b2SMatthias Ringwald it->flags = 0; 96*591423b2SMatthias Ringwald it->handle = 0; 97*591423b2SMatthias Ringwald it->uuid = NULL; 98*591423b2SMatthias Ringwald it->value_len = 0; 99*591423b2SMatthias Ringwald it->value = NULL; 100*591423b2SMatthias Ringwald it->att_ptr = NULL; 101*591423b2SMatthias Ringwald return; 102*591423b2SMatthias Ringwald } 103*591423b2SMatthias Ringwald it->flags = little_endian_read_16(it->att_ptr, 2); 104*591423b2SMatthias Ringwald it->handle = little_endian_read_16(it->att_ptr, 4); 105*591423b2SMatthias Ringwald it->uuid = &it->att_ptr[6]; 106*591423b2SMatthias Ringwald // handle 128 bit UUIDs 107*591423b2SMatthias Ringwald if (it->flags & ATT_PROPERTY_UUID128){ 108*591423b2SMatthias Ringwald it->value_len = it->size - 22; 109*591423b2SMatthias Ringwald it->value = &it->att_ptr[22]; 110*591423b2SMatthias Ringwald } else { 111*591423b2SMatthias Ringwald it->value_len = it->size - 8; 112*591423b2SMatthias Ringwald it->value = &it->att_ptr[8]; 113*591423b2SMatthias Ringwald } 114*591423b2SMatthias Ringwald // advance AFTER setting values 115*591423b2SMatthias Ringwald it->att_ptr += it->size; 116*591423b2SMatthias Ringwald } 117*591423b2SMatthias Ringwald 118*591423b2SMatthias Ringwald static int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){ 119*591423b2SMatthias Ringwald if (it->handle == 0) return 0; 120*591423b2SMatthias Ringwald if (it->flags & ATT_PROPERTY_UUID128){ 121*591423b2SMatthias Ringwald if (!is_Bluetooth_Base_UUID(it->uuid)) return 0; 122*591423b2SMatthias Ringwald return little_endian_read_16(it->uuid, 12) == uuid; 123*591423b2SMatthias Ringwald } 124*591423b2SMatthias Ringwald return little_endian_read_16(it->uuid, 0) == uuid; 125*591423b2SMatthias Ringwald } 126*591423b2SMatthias Ringwald 127*591423b2SMatthias Ringwald static int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){ 128*591423b2SMatthias Ringwald if (it->handle == 0) return 0; 129*591423b2SMatthias Ringwald // input: UUID16 130*591423b2SMatthias Ringwald if (uuid_len == 2) { 131*591423b2SMatthias Ringwald return att_iterator_match_uuid16(it, little_endian_read_16(uuid, 0)); 132*591423b2SMatthias Ringwald } 133*591423b2SMatthias Ringwald // input and db: UUID128 134*591423b2SMatthias Ringwald if (it->flags & ATT_PROPERTY_UUID128){ 135*591423b2SMatthias Ringwald return memcmp(it->uuid, uuid, 16) == 0; 136*591423b2SMatthias Ringwald } 137*591423b2SMatthias Ringwald // input: UUID128, db: UUID16 138*591423b2SMatthias Ringwald if (!is_Bluetooth_Base_UUID(uuid)) return 0; 139*591423b2SMatthias Ringwald return little_endian_read_16(uuid, 12) == little_endian_read_16(it->uuid, 0); 140*591423b2SMatthias Ringwald } 141*591423b2SMatthias Ringwald 142*591423b2SMatthias Ringwald 143*591423b2SMatthias Ringwald static int att_find_handle(att_iterator_t *it, uint16_t handle){ 144*591423b2SMatthias Ringwald if (handle == 0) return 0; 145*591423b2SMatthias Ringwald att_iterator_init(it); 146*591423b2SMatthias Ringwald while (att_iterator_has_next(it)){ 147*591423b2SMatthias Ringwald att_iterator_fetch_next(it); 148*591423b2SMatthias Ringwald if (it->handle != handle) continue; 149*591423b2SMatthias Ringwald return 1; 150*591423b2SMatthias Ringwald } 151*591423b2SMatthias Ringwald return 0; 152*591423b2SMatthias Ringwald } 153*591423b2SMatthias Ringwald 154*591423b2SMatthias Ringwald // experimental client API 155*591423b2SMatthias Ringwald uint16_t att_uuid_for_handle(uint16_t handle){ 156*591423b2SMatthias Ringwald att_iterator_t it; 157*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 158*591423b2SMatthias Ringwald if (!ok) return 0; 159*591423b2SMatthias Ringwald if (it.flags & ATT_PROPERTY_UUID128) return 0; 160*591423b2SMatthias Ringwald return little_endian_read_16(it.uuid, 0); 161*591423b2SMatthias Ringwald } 162*591423b2SMatthias Ringwald // end of client API 163*591423b2SMatthias Ringwald 164*591423b2SMatthias Ringwald static void att_update_value_len(att_iterator_t *it, uint16_t con_handle){ 165*591423b2SMatthias Ringwald if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0 || !att_read_callback) return; 166*591423b2SMatthias Ringwald it->value_len = (*att_read_callback)(con_handle, it->handle, 0, NULL, 0); 167*591423b2SMatthias Ringwald return; 168*591423b2SMatthias Ringwald } 169*591423b2SMatthias Ringwald 170*591423b2SMatthias Ringwald // copy attribute value from offset into buffer with given size 171*591423b2SMatthias Ringwald static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size, uint16_t con_handle){ 172*591423b2SMatthias Ringwald 173*591423b2SMatthias Ringwald // DYNAMIC 174*591423b2SMatthias Ringwald if ((it->flags & ATT_PROPERTY_DYNAMIC) && att_read_callback) { 175*591423b2SMatthias Ringwald return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size); 176*591423b2SMatthias Ringwald } 177*591423b2SMatthias Ringwald 178*591423b2SMatthias Ringwald // STATIC 179*591423b2SMatthias Ringwald uint16_t bytes_to_copy = it->value_len - offset; 180*591423b2SMatthias Ringwald if (bytes_to_copy > buffer_size){ 181*591423b2SMatthias Ringwald bytes_to_copy = buffer_size; 182*591423b2SMatthias Ringwald } 183*591423b2SMatthias Ringwald memcpy(buffer, it->value, bytes_to_copy); 184*591423b2SMatthias Ringwald return bytes_to_copy; 185*591423b2SMatthias Ringwald } 186*591423b2SMatthias Ringwald 187*591423b2SMatthias Ringwald void att_set_db(uint8_t const * db){ 188*591423b2SMatthias Ringwald att_db = db; 189*591423b2SMatthias Ringwald } 190*591423b2SMatthias Ringwald 191*591423b2SMatthias Ringwald void att_set_read_callback(att_read_callback_t callback){ 192*591423b2SMatthias Ringwald att_read_callback = callback; 193*591423b2SMatthias Ringwald } 194*591423b2SMatthias Ringwald 195*591423b2SMatthias Ringwald void att_set_write_callback(att_write_callback_t callback){ 196*591423b2SMatthias Ringwald att_write_callback = callback; 197*591423b2SMatthias Ringwald } 198*591423b2SMatthias Ringwald 199*591423b2SMatthias Ringwald void att_dump_attributes(void){ 200*591423b2SMatthias Ringwald att_iterator_t it; 201*591423b2SMatthias Ringwald att_iterator_init(&it); 202*591423b2SMatthias Ringwald uint8_t uuid128[16]; 203*591423b2SMatthias Ringwald while (att_iterator_has_next(&it)){ 204*591423b2SMatthias Ringwald att_iterator_fetch_next(&it); 205*591423b2SMatthias Ringwald if (it.handle == 0) { 206*591423b2SMatthias Ringwald log_info("Handle: END"); 207*591423b2SMatthias Ringwald return; 208*591423b2SMatthias Ringwald } 209*591423b2SMatthias Ringwald log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags); 210*591423b2SMatthias Ringwald if (it.flags & ATT_PROPERTY_UUID128){ 211*591423b2SMatthias Ringwald reverse_128(it.uuid, uuid128); 212*591423b2SMatthias Ringwald log_info("%s", uuid128_to_str(uuid128)); 213*591423b2SMatthias Ringwald } else { 214*591423b2SMatthias Ringwald log_info("%04x", little_endian_read_16(it.uuid, 0)); 215*591423b2SMatthias Ringwald } 216*591423b2SMatthias Ringwald log_info(", value_len: %u, value: ", it.value_len); 217*591423b2SMatthias Ringwald log_info_hexdump(it.value, it.value_len); 218*591423b2SMatthias Ringwald } 219*591423b2SMatthias Ringwald } 220*591423b2SMatthias Ringwald 221*591423b2SMatthias Ringwald static void att_prepare_write_reset(void){ 222*591423b2SMatthias Ringwald att_prepare_write_error_code = 0; 223*591423b2SMatthias Ringwald att_prepare_write_error_handle = 0x0000; 224*591423b2SMatthias Ringwald } 225*591423b2SMatthias Ringwald 226*591423b2SMatthias Ringwald static void att_prepare_write_update_errors(uint8_t error_code, uint16_t handle){ 227*591423b2SMatthias Ringwald // first ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH has highest priority 228*591423b2SMatthias Ringwald if (error_code == ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH && error_code != att_prepare_write_error_code){ 229*591423b2SMatthias Ringwald att_prepare_write_error_code = error_code; 230*591423b2SMatthias Ringwald att_prepare_write_error_handle = handle; 231*591423b2SMatthias Ringwald return; 232*591423b2SMatthias Ringwald } 233*591423b2SMatthias Ringwald // first ATT_ERROR_INVALID_OFFSET is next 234*591423b2SMatthias Ringwald if (error_code == ATT_ERROR_INVALID_OFFSET && att_prepare_write_error_code == 0){ 235*591423b2SMatthias Ringwald att_prepare_write_error_code = error_code; 236*591423b2SMatthias Ringwald att_prepare_write_error_handle = handle; 237*591423b2SMatthias Ringwald return; 238*591423b2SMatthias Ringwald } 239*591423b2SMatthias Ringwald } 240*591423b2SMatthias Ringwald 241*591423b2SMatthias Ringwald static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){ 242*591423b2SMatthias Ringwald response_buffer[0] = ATT_ERROR_RESPONSE; 243*591423b2SMatthias Ringwald response_buffer[1] = request; 244*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, 2, handle); 245*591423b2SMatthias Ringwald response_buffer[4] = error_code; 246*591423b2SMatthias Ringwald return 5; 247*591423b2SMatthias Ringwald } 248*591423b2SMatthias Ringwald 249*591423b2SMatthias Ringwald static inline uint16_t setup_error_read_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 250*591423b2SMatthias Ringwald return setup_error(response_buffer, request, start_handle, ATT_ERROR_READ_NOT_PERMITTED); 251*591423b2SMatthias Ringwald } 252*591423b2SMatthias Ringwald 253*591423b2SMatthias Ringwald static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 254*591423b2SMatthias Ringwald return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED); 255*591423b2SMatthias Ringwald } 256*591423b2SMatthias Ringwald 257*591423b2SMatthias Ringwald static inline uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 258*591423b2SMatthias Ringwald return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND); 259*591423b2SMatthias Ringwald } 260*591423b2SMatthias Ringwald 261*591423b2SMatthias Ringwald static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 262*591423b2SMatthias Ringwald return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_HANDLE); 263*591423b2SMatthias Ringwald } 264*591423b2SMatthias Ringwald 265*591423b2SMatthias Ringwald static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 266*591423b2SMatthias Ringwald return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET); 267*591423b2SMatthias Ringwald } 268*591423b2SMatthias Ringwald 269*591423b2SMatthias Ringwald static uint8_t att_validate_security(att_connection_t * att_connection, att_iterator_t * it){ 270*591423b2SMatthias Ringwald int required_encryption_size = it->flags >> 12; 271*591423b2SMatthias Ringwald if (required_encryption_size) required_encryption_size++; // store -1 to fit into 4 bit 272*591423b2SMatthias Ringwald log_info("att_validate_security. flags 0x%04x - req enc size %u, authorized %u, authenticated %u, encryption_key_size %u", 273*591423b2SMatthias Ringwald it->flags, required_encryption_size, att_connection->authorized, att_connection->authenticated, att_connection->encryption_key_size); 274*591423b2SMatthias Ringwald if ((it->flags & ATT_PROPERTY_AUTHENTICATION_REQUIRED) && att_connection->authenticated == 0) { 275*591423b2SMatthias Ringwald return ATT_ERROR_INSUFFICIENT_AUTHENTICATION; 276*591423b2SMatthias Ringwald } 277*591423b2SMatthias Ringwald if ((it->flags & ATT_PROPERTY_AUTHORIZATION_REQUIRED) && att_connection->authorized == 0) { 278*591423b2SMatthias Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 279*591423b2SMatthias Ringwald } 280*591423b2SMatthias Ringwald if (required_encryption_size > 0 && att_connection->encryption_key_size == 0){ 281*591423b2SMatthias Ringwald return ATT_ERROR_INSUFFICIENT_ENCRYPTION; 282*591423b2SMatthias Ringwald } 283*591423b2SMatthias Ringwald if (required_encryption_size > att_connection->encryption_key_size){ 284*591423b2SMatthias Ringwald return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE; 285*591423b2SMatthias Ringwald } 286*591423b2SMatthias Ringwald return 0; 287*591423b2SMatthias Ringwald } 288*591423b2SMatthias Ringwald 289*591423b2SMatthias Ringwald // 290*591423b2SMatthias Ringwald // MARK: ATT_EXCHANGE_MTU_REQUEST 291*591423b2SMatthias Ringwald // 292*591423b2SMatthias Ringwald static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 293*591423b2SMatthias Ringwald uint8_t * response_buffer){ 294*591423b2SMatthias Ringwald 295*591423b2SMatthias Ringwald uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1); 296*591423b2SMatthias Ringwald 297*591423b2SMatthias Ringwald // find min(local max mtu, remote mtu) and use as mtu for this connection 298*591423b2SMatthias Ringwald if (client_rx_mtu < att_connection->max_mtu){ 299*591423b2SMatthias Ringwald att_connection->mtu = client_rx_mtu; 300*591423b2SMatthias Ringwald } else { 301*591423b2SMatthias Ringwald att_connection->mtu = att_connection->max_mtu; 302*591423b2SMatthias Ringwald } 303*591423b2SMatthias Ringwald 304*591423b2SMatthias Ringwald response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE; 305*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, 1, att_connection->mtu); 306*591423b2SMatthias Ringwald return 3; 307*591423b2SMatthias Ringwald } 308*591423b2SMatthias Ringwald 309*591423b2SMatthias Ringwald 310*591423b2SMatthias Ringwald // 311*591423b2SMatthias Ringwald // MARK: ATT_FIND_INFORMATION_REQUEST 312*591423b2SMatthias Ringwald // 313*591423b2SMatthias Ringwald // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 314*591423b2SMatthias Ringwald // 315*591423b2SMatthias Ringwald static uint16_t handle_find_information_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 316*591423b2SMatthias Ringwald uint16_t start_handle, uint16_t end_handle){ 317*591423b2SMatthias Ringwald 318*591423b2SMatthias Ringwald log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X", start_handle, end_handle); 319*591423b2SMatthias Ringwald uint8_t request_type = ATT_FIND_INFORMATION_REQUEST; 320*591423b2SMatthias Ringwald 321*591423b2SMatthias Ringwald if (start_handle > end_handle || start_handle == 0){ 322*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, start_handle); 323*591423b2SMatthias Ringwald } 324*591423b2SMatthias Ringwald 325*591423b2SMatthias Ringwald uint16_t offset = 1; 326*591423b2SMatthias Ringwald uint16_t uuid_len = 0; 327*591423b2SMatthias Ringwald 328*591423b2SMatthias Ringwald att_iterator_t it; 329*591423b2SMatthias Ringwald att_iterator_init(&it); 330*591423b2SMatthias Ringwald while (att_iterator_has_next(&it)){ 331*591423b2SMatthias Ringwald att_iterator_fetch_next(&it); 332*591423b2SMatthias Ringwald if (!it.handle) break; 333*591423b2SMatthias Ringwald if (it.handle > end_handle) break; 334*591423b2SMatthias Ringwald if (it.handle < start_handle) continue; 335*591423b2SMatthias Ringwald 336*591423b2SMatthias Ringwald // log_info("Handle 0x%04x", it.handle); 337*591423b2SMatthias Ringwald 338*591423b2SMatthias Ringwald uint16_t this_uuid_len = (it.flags & ATT_PROPERTY_UUID128) ? 16 : 2; 339*591423b2SMatthias Ringwald 340*591423b2SMatthias Ringwald // check if value has same len as last one if not first result 341*591423b2SMatthias Ringwald if (offset > 1){ 342*591423b2SMatthias Ringwald if (this_uuid_len != uuid_len) { 343*591423b2SMatthias Ringwald break; 344*591423b2SMatthias Ringwald } 345*591423b2SMatthias Ringwald } 346*591423b2SMatthias Ringwald 347*591423b2SMatthias Ringwald // first 348*591423b2SMatthias Ringwald if (offset == 1) { 349*591423b2SMatthias Ringwald uuid_len = this_uuid_len; 350*591423b2SMatthias Ringwald // set format field 351*591423b2SMatthias Ringwald response_buffer[offset] = (it.flags & ATT_PROPERTY_UUID128) ? 0x02 : 0x01; 352*591423b2SMatthias Ringwald offset++; 353*591423b2SMatthias Ringwald } 354*591423b2SMatthias Ringwald 355*591423b2SMatthias Ringwald // space? 356*591423b2SMatthias Ringwald if (offset + 2 + uuid_len > response_buffer_size) break; 357*591423b2SMatthias Ringwald 358*591423b2SMatthias Ringwald // store 359*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, it.handle); 360*591423b2SMatthias Ringwald offset += 2; 361*591423b2SMatthias Ringwald 362*591423b2SMatthias Ringwald memcpy(response_buffer + offset, it.uuid, uuid_len); 363*591423b2SMatthias Ringwald offset += uuid_len; 364*591423b2SMatthias Ringwald } 365*591423b2SMatthias Ringwald 366*591423b2SMatthias Ringwald if (offset == 1){ 367*591423b2SMatthias Ringwald return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 368*591423b2SMatthias Ringwald } 369*591423b2SMatthias Ringwald 370*591423b2SMatthias Ringwald response_buffer[0] = ATT_FIND_INFORMATION_REPLY; 371*591423b2SMatthias Ringwald return offset; 372*591423b2SMatthias Ringwald } 373*591423b2SMatthias Ringwald 374*591423b2SMatthias Ringwald static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 375*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 376*591423b2SMatthias Ringwald return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3)); 377*591423b2SMatthias Ringwald } 378*591423b2SMatthias Ringwald 379*591423b2SMatthias Ringwald // 380*591423b2SMatthias Ringwald // MARK: ATT_FIND_BY_TYPE_VALUE 381*591423b2SMatthias Ringwald // 382*591423b2SMatthias Ringwald // "Only attributes with attribute handles between and including the Starting Handle parameter 383*591423b2SMatthias Ringwald // and the Ending Handle parameter that match the requested attri- bute type and the attribute 384*591423b2SMatthias Ringwald // value that have sufficient permissions to allow reading will be returned" -> (1) 385*591423b2SMatthias Ringwald // 386*591423b2SMatthias Ringwald // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 387*591423b2SMatthias Ringwald // 388*591423b2SMatthias Ringwald // NOTE: doesn't handle DYNAMIC values 389*591423b2SMatthias Ringwald // NOTE: only supports 16 bit UUIDs 390*591423b2SMatthias Ringwald // 391*591423b2SMatthias Ringwald static uint16_t handle_find_by_type_value_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 392*591423b2SMatthias Ringwald uint16_t start_handle, uint16_t end_handle, 393*591423b2SMatthias Ringwald uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){ 394*591423b2SMatthias Ringwald 395*591423b2SMatthias Ringwald log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type); 396*591423b2SMatthias Ringwald log_info_hexdump(attribute_value, attribute_len); 397*591423b2SMatthias Ringwald uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST; 398*591423b2SMatthias Ringwald 399*591423b2SMatthias Ringwald if (start_handle > end_handle || start_handle == 0){ 400*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, start_handle); 401*591423b2SMatthias Ringwald } 402*591423b2SMatthias Ringwald 403*591423b2SMatthias Ringwald uint16_t offset = 1; 404*591423b2SMatthias Ringwald uint16_t in_group = 0; 405*591423b2SMatthias Ringwald uint16_t prev_handle = 0; 406*591423b2SMatthias Ringwald 407*591423b2SMatthias Ringwald att_iterator_t it; 408*591423b2SMatthias Ringwald att_iterator_init(&it); 409*591423b2SMatthias Ringwald while (att_iterator_has_next(&it)){ 410*591423b2SMatthias Ringwald att_iterator_fetch_next(&it); 411*591423b2SMatthias Ringwald 412*591423b2SMatthias Ringwald if (it.handle && it.handle < start_handle) continue; 413*591423b2SMatthias Ringwald if (it.handle > end_handle) break; // (1) 414*591423b2SMatthias Ringwald 415*591423b2SMatthias Ringwald // close current tag, if within a group and a new service definition starts or we reach end of att db 416*591423b2SMatthias Ringwald if (in_group && 417*591423b2SMatthias Ringwald (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 418*591423b2SMatthias Ringwald 419*591423b2SMatthias Ringwald log_info("End of group, handle 0x%04x", prev_handle); 420*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, prev_handle); 421*591423b2SMatthias Ringwald offset += 2; 422*591423b2SMatthias Ringwald in_group = 0; 423*591423b2SMatthias Ringwald 424*591423b2SMatthias Ringwald // check if space for another handle pair available 425*591423b2SMatthias Ringwald if (offset + 4 > response_buffer_size){ 426*591423b2SMatthias Ringwald break; 427*591423b2SMatthias Ringwald } 428*591423b2SMatthias Ringwald } 429*591423b2SMatthias Ringwald 430*591423b2SMatthias Ringwald // keep track of previous handle 431*591423b2SMatthias Ringwald prev_handle = it.handle; 432*591423b2SMatthias Ringwald 433*591423b2SMatthias Ringwald // does current attribute match 434*591423b2SMatthias Ringwald if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ 435*591423b2SMatthias Ringwald log_info("Begin of group, handle 0x%04x", it.handle); 436*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, it.handle); 437*591423b2SMatthias Ringwald offset += 2; 438*591423b2SMatthias Ringwald in_group = 1; 439*591423b2SMatthias Ringwald } 440*591423b2SMatthias Ringwald } 441*591423b2SMatthias Ringwald 442*591423b2SMatthias Ringwald if (offset == 1){ 443*591423b2SMatthias Ringwald return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 444*591423b2SMatthias Ringwald } 445*591423b2SMatthias Ringwald 446*591423b2SMatthias Ringwald response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE; 447*591423b2SMatthias Ringwald return offset; 448*591423b2SMatthias Ringwald } 449*591423b2SMatthias Ringwald 450*591423b2SMatthias Ringwald static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 451*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 452*591423b2SMatthias Ringwald int attribute_len = request_len - 7; 453*591423b2SMatthias Ringwald return handle_find_by_type_value_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), 454*591423b2SMatthias Ringwald little_endian_read_16(request_buffer, 3), little_endian_read_16(request_buffer, 5), attribute_len, &request_buffer[7]); 455*591423b2SMatthias Ringwald } 456*591423b2SMatthias Ringwald 457*591423b2SMatthias Ringwald // 458*591423b2SMatthias Ringwald // MARK: ATT_READ_BY_TYPE_REQUEST 459*591423b2SMatthias Ringwald // 460*591423b2SMatthias Ringwald static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 461*591423b2SMatthias Ringwald uint16_t start_handle, uint16_t end_handle, 462*591423b2SMatthias Ringwald uint16_t attribute_type_len, uint8_t * attribute_type){ 463*591423b2SMatthias Ringwald 464*591423b2SMatthias Ringwald log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); 465*591423b2SMatthias Ringwald log_info_hexdump(attribute_type, attribute_type_len); 466*591423b2SMatthias Ringwald uint8_t request_type = ATT_READ_BY_TYPE_REQUEST; 467*591423b2SMatthias Ringwald 468*591423b2SMatthias Ringwald if (start_handle > end_handle || start_handle == 0){ 469*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, start_handle); 470*591423b2SMatthias Ringwald } 471*591423b2SMatthias Ringwald 472*591423b2SMatthias Ringwald uint16_t offset = 1; 473*591423b2SMatthias Ringwald uint16_t pair_len = 0; 474*591423b2SMatthias Ringwald 475*591423b2SMatthias Ringwald att_iterator_t it; 476*591423b2SMatthias Ringwald att_iterator_init(&it); 477*591423b2SMatthias Ringwald uint8_t error_code = 0; 478*591423b2SMatthias Ringwald uint16_t first_matching_but_unreadable_handle = 0; 479*591423b2SMatthias Ringwald 480*591423b2SMatthias Ringwald while (att_iterator_has_next(&it)){ 481*591423b2SMatthias Ringwald att_iterator_fetch_next(&it); 482*591423b2SMatthias Ringwald 483*591423b2SMatthias Ringwald if (!it.handle) break; 484*591423b2SMatthias Ringwald if (it.handle < start_handle) continue; 485*591423b2SMatthias Ringwald if (it.handle > end_handle) break; // (1) 486*591423b2SMatthias Ringwald 487*591423b2SMatthias Ringwald // does current attribute match 488*591423b2SMatthias Ringwald if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; 489*591423b2SMatthias Ringwald 490*591423b2SMatthias Ringwald // skip handles that cannot be read but rembember that there has been at least one 491*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_READ) == 0) { 492*591423b2SMatthias Ringwald if (first_matching_but_unreadable_handle == 0) { 493*591423b2SMatthias Ringwald first_matching_but_unreadable_handle = it.handle; 494*591423b2SMatthias Ringwald } 495*591423b2SMatthias Ringwald continue; 496*591423b2SMatthias Ringwald } 497*591423b2SMatthias Ringwald 498*591423b2SMatthias Ringwald // check security requirements 499*591423b2SMatthias Ringwald error_code = att_validate_security(att_connection, &it); 500*591423b2SMatthias Ringwald if (error_code) break; 501*591423b2SMatthias Ringwald 502*591423b2SMatthias Ringwald att_update_value_len(&it, att_connection->con_handle); 503*591423b2SMatthias Ringwald 504*591423b2SMatthias Ringwald // check if value has same len as last one 505*591423b2SMatthias Ringwald uint16_t this_pair_len = 2 + it.value_len; 506*591423b2SMatthias Ringwald if (offset > 1){ 507*591423b2SMatthias Ringwald if (pair_len != this_pair_len) { 508*591423b2SMatthias Ringwald break; 509*591423b2SMatthias Ringwald } 510*591423b2SMatthias Ringwald } 511*591423b2SMatthias Ringwald 512*591423b2SMatthias Ringwald // first 513*591423b2SMatthias Ringwald if (offset == 1) { 514*591423b2SMatthias Ringwald pair_len = this_pair_len; 515*591423b2SMatthias Ringwald response_buffer[offset] = pair_len; 516*591423b2SMatthias Ringwald offset++; 517*591423b2SMatthias Ringwald } 518*591423b2SMatthias Ringwald 519*591423b2SMatthias Ringwald // space? 520*591423b2SMatthias Ringwald if (offset + pair_len > response_buffer_size) { 521*591423b2SMatthias Ringwald if (offset > 2) break; 522*591423b2SMatthias Ringwald it.value_len = response_buffer_size - 4; 523*591423b2SMatthias Ringwald response_buffer[1] = 2 + it.value_len; 524*591423b2SMatthias Ringwald } 525*591423b2SMatthias Ringwald 526*591423b2SMatthias Ringwald // store 527*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, it.handle); 528*591423b2SMatthias Ringwald offset += 2; 529*591423b2SMatthias Ringwald uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 530*591423b2SMatthias Ringwald offset += bytes_copied; 531*591423b2SMatthias Ringwald } 532*591423b2SMatthias Ringwald 533*591423b2SMatthias Ringwald // at least one attribute could be read 534*591423b2SMatthias Ringwald if (offset > 1){ 535*591423b2SMatthias Ringwald response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; 536*591423b2SMatthias Ringwald return offset; 537*591423b2SMatthias Ringwald } 538*591423b2SMatthias Ringwald 539*591423b2SMatthias Ringwald // first attribute had an error 540*591423b2SMatthias Ringwald if (error_code){ 541*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, start_handle, error_code); 542*591423b2SMatthias Ringwald } 543*591423b2SMatthias Ringwald 544*591423b2SMatthias Ringwald // no other errors, but all found attributes had been non-readable 545*591423b2SMatthias Ringwald if (first_matching_but_unreadable_handle){ 546*591423b2SMatthias Ringwald return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); 547*591423b2SMatthias Ringwald } 548*591423b2SMatthias Ringwald 549*591423b2SMatthias Ringwald // attribute not found 550*591423b2SMatthias Ringwald return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 551*591423b2SMatthias Ringwald } 552*591423b2SMatthias Ringwald 553*591423b2SMatthias Ringwald static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 554*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 555*591423b2SMatthias Ringwald int attribute_type_len; 556*591423b2SMatthias Ringwald if (request_len <= 7){ 557*591423b2SMatthias Ringwald attribute_type_len = 2; 558*591423b2SMatthias Ringwald } else { 559*591423b2SMatthias Ringwald attribute_type_len = 16; 560*591423b2SMatthias Ringwald } 561*591423b2SMatthias Ringwald return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 562*591423b2SMatthias Ringwald } 563*591423b2SMatthias Ringwald 564*591423b2SMatthias Ringwald // 565*591423b2SMatthias Ringwald // MARK: ATT_READ_BY_TYPE_REQUEST 566*591423b2SMatthias Ringwald // 567*591423b2SMatthias Ringwald static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ 568*591423b2SMatthias Ringwald 569*591423b2SMatthias Ringwald log_info("ATT_READ_REQUEST: handle %04x", handle); 570*591423b2SMatthias Ringwald uint8_t request_type = ATT_READ_REQUEST; 571*591423b2SMatthias Ringwald 572*591423b2SMatthias Ringwald att_iterator_t it; 573*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 574*591423b2SMatthias Ringwald if (!ok){ 575*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 576*591423b2SMatthias Ringwald } 577*591423b2SMatthias Ringwald 578*591423b2SMatthias Ringwald // check if handle can be read 579*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_READ) == 0) { 580*591423b2SMatthias Ringwald return setup_error_read_not_permitted(response_buffer, request_type, handle); 581*591423b2SMatthias Ringwald } 582*591423b2SMatthias Ringwald 583*591423b2SMatthias Ringwald // check security requirements 584*591423b2SMatthias Ringwald uint8_t error_code = att_validate_security(att_connection, &it); 585*591423b2SMatthias Ringwald if (error_code) { 586*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 587*591423b2SMatthias Ringwald } 588*591423b2SMatthias Ringwald 589*591423b2SMatthias Ringwald att_update_value_len(&it, att_connection->con_handle); 590*591423b2SMatthias Ringwald 591*591423b2SMatthias Ringwald uint16_t offset = 1; 592*591423b2SMatthias Ringwald // limit data 593*591423b2SMatthias Ringwald if (offset + it.value_len > response_buffer_size) { 594*591423b2SMatthias Ringwald it.value_len = response_buffer_size - 1; 595*591423b2SMatthias Ringwald } 596*591423b2SMatthias Ringwald 597*591423b2SMatthias Ringwald // store 598*591423b2SMatthias Ringwald uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 599*591423b2SMatthias Ringwald offset += bytes_copied; 600*591423b2SMatthias Ringwald 601*591423b2SMatthias Ringwald response_buffer[0] = ATT_READ_RESPONSE; 602*591423b2SMatthias Ringwald return offset; 603*591423b2SMatthias Ringwald } 604*591423b2SMatthias Ringwald 605*591423b2SMatthias Ringwald static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 606*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 607*591423b2SMatthias Ringwald return handle_read_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1)); 608*591423b2SMatthias Ringwald } 609*591423b2SMatthias Ringwald 610*591423b2SMatthias Ringwald // 611*591423b2SMatthias Ringwald // MARK: ATT_READ_BLOB_REQUEST 0x0c 612*591423b2SMatthias Ringwald // 613*591423b2SMatthias Ringwald static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){ 614*591423b2SMatthias Ringwald log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); 615*591423b2SMatthias Ringwald uint8_t request_type = ATT_READ_BLOB_REQUEST; 616*591423b2SMatthias Ringwald 617*591423b2SMatthias Ringwald att_iterator_t it; 618*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 619*591423b2SMatthias Ringwald if (!ok){ 620*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 621*591423b2SMatthias Ringwald } 622*591423b2SMatthias Ringwald 623*591423b2SMatthias Ringwald // check if handle can be read 624*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_READ) == 0) { 625*591423b2SMatthias Ringwald return setup_error_read_not_permitted(response_buffer, request_type, handle); 626*591423b2SMatthias Ringwald } 627*591423b2SMatthias Ringwald 628*591423b2SMatthias Ringwald // check security requirements 629*591423b2SMatthias Ringwald uint8_t error_code = att_validate_security(att_connection, &it); 630*591423b2SMatthias Ringwald if (error_code) { 631*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 632*591423b2SMatthias Ringwald } 633*591423b2SMatthias Ringwald 634*591423b2SMatthias Ringwald att_update_value_len(&it, att_connection->con_handle); 635*591423b2SMatthias Ringwald 636*591423b2SMatthias Ringwald if (value_offset > it.value_len){ 637*591423b2SMatthias Ringwald return setup_error_invalid_offset(response_buffer, request_type, handle); 638*591423b2SMatthias Ringwald } 639*591423b2SMatthias Ringwald 640*591423b2SMatthias Ringwald // limit data 641*591423b2SMatthias Ringwald uint16_t offset = 1; 642*591423b2SMatthias Ringwald if (offset + it.value_len - value_offset > response_buffer_size) { 643*591423b2SMatthias Ringwald it.value_len = response_buffer_size - 1 + value_offset; 644*591423b2SMatthias Ringwald } 645*591423b2SMatthias Ringwald 646*591423b2SMatthias Ringwald // store 647*591423b2SMatthias Ringwald uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle); 648*591423b2SMatthias Ringwald offset += bytes_copied; 649*591423b2SMatthias Ringwald 650*591423b2SMatthias Ringwald response_buffer[0] = ATT_READ_BLOB_RESPONSE; 651*591423b2SMatthias Ringwald return offset; 652*591423b2SMatthias Ringwald } 653*591423b2SMatthias Ringwald 654*591423b2SMatthias Ringwald static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 655*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 656*591423b2SMatthias Ringwald return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3)); 657*591423b2SMatthias Ringwald } 658*591423b2SMatthias Ringwald 659*591423b2SMatthias Ringwald // 660*591423b2SMatthias Ringwald // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e 661*591423b2SMatthias Ringwald // 662*591423b2SMatthias Ringwald static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint8_t * handles){ 663*591423b2SMatthias Ringwald log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles); 664*591423b2SMatthias Ringwald uint8_t request_type = ATT_READ_MULTIPLE_REQUEST; 665*591423b2SMatthias Ringwald 666*591423b2SMatthias Ringwald // TODO: figure out which error to respond with 667*591423b2SMatthias Ringwald // if (num_handles < 2){ 668*591423b2SMatthias Ringwald // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); 669*591423b2SMatthias Ringwald // } 670*591423b2SMatthias Ringwald 671*591423b2SMatthias Ringwald uint16_t offset = 1; 672*591423b2SMatthias Ringwald 673*591423b2SMatthias Ringwald int i; 674*591423b2SMatthias Ringwald uint8_t error_code = 0; 675*591423b2SMatthias Ringwald uint16_t handle = 0; 676*591423b2SMatthias Ringwald for (i=0;i<num_handles;i++){ 677*591423b2SMatthias Ringwald handle = little_endian_read_16(handles, i << 1); 678*591423b2SMatthias Ringwald 679*591423b2SMatthias Ringwald if (handle == 0){ 680*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 681*591423b2SMatthias Ringwald } 682*591423b2SMatthias Ringwald 683*591423b2SMatthias Ringwald att_iterator_t it; 684*591423b2SMatthias Ringwald 685*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 686*591423b2SMatthias Ringwald if (!ok){ 687*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 688*591423b2SMatthias Ringwald } 689*591423b2SMatthias Ringwald 690*591423b2SMatthias Ringwald // check if handle can be read 691*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_READ) == 0) { 692*591423b2SMatthias Ringwald error_code = ATT_ERROR_READ_NOT_PERMITTED; 693*591423b2SMatthias Ringwald break; 694*591423b2SMatthias Ringwald } 695*591423b2SMatthias Ringwald 696*591423b2SMatthias Ringwald // check security requirements 697*591423b2SMatthias Ringwald error_code = att_validate_security(att_connection, &it); 698*591423b2SMatthias Ringwald if (error_code) break; 699*591423b2SMatthias Ringwald 700*591423b2SMatthias Ringwald att_update_value_len(&it, att_connection->con_handle); 701*591423b2SMatthias Ringwald 702*591423b2SMatthias Ringwald // limit data 703*591423b2SMatthias Ringwald if (offset + it.value_len > response_buffer_size) { 704*591423b2SMatthias Ringwald it.value_len = response_buffer_size - 1; 705*591423b2SMatthias Ringwald } 706*591423b2SMatthias Ringwald 707*591423b2SMatthias Ringwald // store 708*591423b2SMatthias Ringwald uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 709*591423b2SMatthias Ringwald offset += bytes_copied; 710*591423b2SMatthias Ringwald } 711*591423b2SMatthias Ringwald 712*591423b2SMatthias Ringwald if (error_code){ 713*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 714*591423b2SMatthias Ringwald } 715*591423b2SMatthias Ringwald 716*591423b2SMatthias Ringwald response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; 717*591423b2SMatthias Ringwald return offset; 718*591423b2SMatthias Ringwald } 719*591423b2SMatthias Ringwald static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 720*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 721*591423b2SMatthias Ringwald int num_handles = (request_len - 1) >> 1; 722*591423b2SMatthias Ringwald return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]); 723*591423b2SMatthias Ringwald } 724*591423b2SMatthias Ringwald 725*591423b2SMatthias Ringwald // 726*591423b2SMatthias Ringwald // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 727*591423b2SMatthias Ringwald // 728*591423b2SMatthias Ringwald // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 729*591423b2SMatthias Ringwald // Core v4.0, vol 3, part g, 2.5.3 730*591423b2SMatthias Ringwald // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request. 731*591423b2SMatthias Ringwald // The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request." 732*591423b2SMatthias Ringwald // 733*591423b2SMatthias Ringwald // NOTE: doesn't handle DYNAMIC values 734*591423b2SMatthias Ringwald // 735*591423b2SMatthias Ringwald // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected 736*591423b2SMatthias Ringwald // Core 4.0, vol 3, part g, 8.1 737*591423b2SMatthias Ringwald // "The list of services and characteristics that a device supports is not considered private or 738*591423b2SMatthias Ringwald // confidential information, and therefore the Service and Characteristic Discovery procedures 739*591423b2SMatthias Ringwald // shall always be permitted. " 740*591423b2SMatthias Ringwald // 741*591423b2SMatthias Ringwald static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 742*591423b2SMatthias Ringwald uint16_t start_handle, uint16_t end_handle, 743*591423b2SMatthias Ringwald uint16_t attribute_type_len, uint8_t * attribute_type){ 744*591423b2SMatthias Ringwald 745*591423b2SMatthias Ringwald log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); 746*591423b2SMatthias Ringwald log_info_hexdump(attribute_type, attribute_type_len); 747*591423b2SMatthias Ringwald uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST; 748*591423b2SMatthias Ringwald 749*591423b2SMatthias Ringwald if (start_handle > end_handle || start_handle == 0){ 750*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, start_handle); 751*591423b2SMatthias Ringwald } 752*591423b2SMatthias Ringwald 753*591423b2SMatthias Ringwald // assert UUID is primary or secondary service uuid 754*591423b2SMatthias Ringwald uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); 755*591423b2SMatthias Ringwald if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){ 756*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); 757*591423b2SMatthias Ringwald } 758*591423b2SMatthias Ringwald 759*591423b2SMatthias Ringwald uint16_t offset = 1; 760*591423b2SMatthias Ringwald uint16_t pair_len = 0; 761*591423b2SMatthias Ringwald uint16_t in_group = 0; 762*591423b2SMatthias Ringwald uint16_t group_start_handle = 0; 763*591423b2SMatthias Ringwald uint8_t const * group_start_value = NULL; 764*591423b2SMatthias Ringwald uint16_t prev_handle = 0; 765*591423b2SMatthias Ringwald 766*591423b2SMatthias Ringwald att_iterator_t it; 767*591423b2SMatthias Ringwald att_iterator_init(&it); 768*591423b2SMatthias Ringwald while (att_iterator_has_next(&it)){ 769*591423b2SMatthias Ringwald att_iterator_fetch_next(&it); 770*591423b2SMatthias Ringwald 771*591423b2SMatthias Ringwald if (it.handle && it.handle < start_handle) continue; 772*591423b2SMatthias Ringwald if (it.handle > end_handle) break; // (1) 773*591423b2SMatthias Ringwald 774*591423b2SMatthias Ringwald // log_info("Handle 0x%04x", it.handle); 775*591423b2SMatthias Ringwald 776*591423b2SMatthias Ringwald // close current tag, if within a group and a new service definition starts or we reach end of att db 777*591423b2SMatthias Ringwald if (in_group && 778*591423b2SMatthias Ringwald (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 779*591423b2SMatthias Ringwald // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4); 780*591423b2SMatthias Ringwald 781*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, group_start_handle); 782*591423b2SMatthias Ringwald offset += 2; 783*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, offset, prev_handle); 784*591423b2SMatthias Ringwald offset += 2; 785*591423b2SMatthias Ringwald memcpy(response_buffer + offset, group_start_value, pair_len - 4); 786*591423b2SMatthias Ringwald offset += pair_len - 4; 787*591423b2SMatthias Ringwald in_group = 0; 788*591423b2SMatthias Ringwald 789*591423b2SMatthias Ringwald // check if space for another handle pair available 790*591423b2SMatthias Ringwald if (offset + pair_len > response_buffer_size){ 791*591423b2SMatthias Ringwald break; 792*591423b2SMatthias Ringwald } 793*591423b2SMatthias Ringwald } 794*591423b2SMatthias Ringwald 795*591423b2SMatthias Ringwald // keep track of previous handle 796*591423b2SMatthias Ringwald prev_handle = it.handle; 797*591423b2SMatthias Ringwald 798*591423b2SMatthias Ringwald // does current attribute match 799*591423b2SMatthias Ringwald // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); 800*591423b2SMatthias Ringwald if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { 801*591423b2SMatthias Ringwald 802*591423b2SMatthias Ringwald // check if value has same len as last one 803*591423b2SMatthias Ringwald uint16_t this_pair_len = 4 + it.value_len; 804*591423b2SMatthias Ringwald if (offset > 1){ 805*591423b2SMatthias Ringwald if (this_pair_len != pair_len) { 806*591423b2SMatthias Ringwald break; 807*591423b2SMatthias Ringwald } 808*591423b2SMatthias Ringwald } 809*591423b2SMatthias Ringwald 810*591423b2SMatthias Ringwald // log_info("Begin of group, handle 0x%04x", it.handle); 811*591423b2SMatthias Ringwald 812*591423b2SMatthias Ringwald // first 813*591423b2SMatthias Ringwald if (offset == 1) { 814*591423b2SMatthias Ringwald pair_len = this_pair_len; 815*591423b2SMatthias Ringwald response_buffer[offset] = this_pair_len; 816*591423b2SMatthias Ringwald offset++; 817*591423b2SMatthias Ringwald } 818*591423b2SMatthias Ringwald 819*591423b2SMatthias Ringwald group_start_handle = it.handle; 820*591423b2SMatthias Ringwald group_start_value = it.value; 821*591423b2SMatthias Ringwald in_group = 1; 822*591423b2SMatthias Ringwald } 823*591423b2SMatthias Ringwald } 824*591423b2SMatthias Ringwald 825*591423b2SMatthias Ringwald if (offset == 1){ 826*591423b2SMatthias Ringwald return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 827*591423b2SMatthias Ringwald } 828*591423b2SMatthias Ringwald 829*591423b2SMatthias Ringwald response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; 830*591423b2SMatthias Ringwald return offset; 831*591423b2SMatthias Ringwald } 832*591423b2SMatthias Ringwald static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 833*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 834*591423b2SMatthias Ringwald int attribute_type_len; 835*591423b2SMatthias Ringwald if (request_len <= 7){ 836*591423b2SMatthias Ringwald attribute_type_len = 2; 837*591423b2SMatthias Ringwald } else { 838*591423b2SMatthias Ringwald attribute_type_len = 16; 839*591423b2SMatthias Ringwald } 840*591423b2SMatthias Ringwald return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 841*591423b2SMatthias Ringwald } 842*591423b2SMatthias Ringwald 843*591423b2SMatthias Ringwald // 844*591423b2SMatthias Ringwald // MARK: ATT_WRITE_REQUEST 0x12 845*591423b2SMatthias Ringwald static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 846*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 847*591423b2SMatthias Ringwald 848*591423b2SMatthias Ringwald uint8_t request_type = ATT_WRITE_REQUEST; 849*591423b2SMatthias Ringwald 850*591423b2SMatthias Ringwald uint16_t handle = little_endian_read_16(request_buffer, 1); 851*591423b2SMatthias Ringwald att_iterator_t it; 852*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 853*591423b2SMatthias Ringwald if (!ok) { 854*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 855*591423b2SMatthias Ringwald } 856*591423b2SMatthias Ringwald if (!att_write_callback) { 857*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 858*591423b2SMatthias Ringwald } 859*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 860*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 861*591423b2SMatthias Ringwald } 862*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 863*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 864*591423b2SMatthias Ringwald } 865*591423b2SMatthias Ringwald // check security requirements 866*591423b2SMatthias Ringwald uint8_t error_code = att_validate_security(att_connection, &it); 867*591423b2SMatthias Ringwald if (error_code) { 868*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 869*591423b2SMatthias Ringwald } 870*591423b2SMatthias Ringwald error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 871*591423b2SMatthias Ringwald if (error_code) { 872*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 873*591423b2SMatthias Ringwald } 874*591423b2SMatthias Ringwald response_buffer[0] = ATT_WRITE_RESPONSE; 875*591423b2SMatthias Ringwald return 1; 876*591423b2SMatthias Ringwald } 877*591423b2SMatthias Ringwald 878*591423b2SMatthias Ringwald // 879*591423b2SMatthias Ringwald // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 880*591423b2SMatthias Ringwald static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 881*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 882*591423b2SMatthias Ringwald 883*591423b2SMatthias Ringwald uint8_t request_type = ATT_PREPARE_WRITE_REQUEST; 884*591423b2SMatthias Ringwald 885*591423b2SMatthias Ringwald uint16_t handle = little_endian_read_16(request_buffer, 1); 886*591423b2SMatthias Ringwald uint16_t offset = little_endian_read_16(request_buffer, 3); 887*591423b2SMatthias Ringwald if (!att_write_callback) { 888*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 889*591423b2SMatthias Ringwald } 890*591423b2SMatthias Ringwald att_iterator_t it; 891*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 892*591423b2SMatthias Ringwald if (!ok) { 893*591423b2SMatthias Ringwald return setup_error_invalid_handle(response_buffer, request_type, handle); 894*591423b2SMatthias Ringwald } 895*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 896*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 897*591423b2SMatthias Ringwald } 898*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 899*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, handle); 900*591423b2SMatthias Ringwald } 901*591423b2SMatthias Ringwald // check security requirements 902*591423b2SMatthias Ringwald uint8_t error_code = att_validate_security(att_connection, &it); 903*591423b2SMatthias Ringwald if (error_code) { 904*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 905*591423b2SMatthias Ringwald } 906*591423b2SMatthias Ringwald 907*591423b2SMatthias Ringwald error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5); 908*591423b2SMatthias Ringwald switch (error_code){ 909*591423b2SMatthias Ringwald case 0: 910*591423b2SMatthias Ringwald break; 911*591423b2SMatthias Ringwald case ATT_ERROR_INVALID_OFFSET: 912*591423b2SMatthias Ringwald case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: 913*591423b2SMatthias Ringwald // postpone to execute write request 914*591423b2SMatthias Ringwald att_prepare_write_update_errors(error_code, handle); 915*591423b2SMatthias Ringwald break; 916*591423b2SMatthias Ringwald default: 917*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 918*591423b2SMatthias Ringwald } 919*591423b2SMatthias Ringwald 920*591423b2SMatthias Ringwald // response: echo request 921*591423b2SMatthias Ringwald memcpy(response_buffer, request_buffer, request_len); 922*591423b2SMatthias Ringwald response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; 923*591423b2SMatthias Ringwald return request_len; 924*591423b2SMatthias Ringwald } 925*591423b2SMatthias Ringwald 926*591423b2SMatthias Ringwald /* 927*591423b2SMatthias Ringwald * @brief transcation queue of prepared writes, e.g., after disconnect 928*591423b2SMatthias Ringwald */ 929*591423b2SMatthias Ringwald void att_clear_transaction_queue(att_connection_t * att_connection){ 930*591423b2SMatthias Ringwald if (!att_write_callback) return; 931*591423b2SMatthias Ringwald (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0); 932*591423b2SMatthias Ringwald } 933*591423b2SMatthias Ringwald 934*591423b2SMatthias Ringwald // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 935*591423b2SMatthias Ringwald // NOTE: security has been verified by handle_prepare_write_request 936*591423b2SMatthias Ringwald static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 937*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 938*591423b2SMatthias Ringwald 939*591423b2SMatthias Ringwald uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST; 940*591423b2SMatthias Ringwald 941*591423b2SMatthias Ringwald if (!att_write_callback) { 942*591423b2SMatthias Ringwald return setup_error_write_not_permitted(response_buffer, request_type, 0); 943*591423b2SMatthias Ringwald } 944*591423b2SMatthias Ringwald if (request_buffer[1]) { 945*591423b2SMatthias Ringwald // deliver queued errors 946*591423b2SMatthias Ringwald if (att_prepare_write_error_code){ 947*591423b2SMatthias Ringwald att_clear_transaction_queue(att_connection); 948*591423b2SMatthias Ringwald uint8_t error_code = att_prepare_write_error_code; 949*591423b2SMatthias Ringwald uint16_t handle = att_prepare_write_error_handle; 950*591423b2SMatthias Ringwald att_prepare_write_reset(); 951*591423b2SMatthias Ringwald return setup_error(response_buffer, request_type, handle, error_code); 952*591423b2SMatthias Ringwald } 953*591423b2SMatthias Ringwald (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0); 954*591423b2SMatthias Ringwald } else { 955*591423b2SMatthias Ringwald att_clear_transaction_queue(att_connection); 956*591423b2SMatthias Ringwald } 957*591423b2SMatthias Ringwald response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; 958*591423b2SMatthias Ringwald return 1; 959*591423b2SMatthias Ringwald } 960*591423b2SMatthias Ringwald 961*591423b2SMatthias Ringwald // MARK: ATT_WRITE_COMMAND 0x52 962*591423b2SMatthias Ringwald // Core 4.0, vol 3, part F, 3.4.5.3 963*591423b2SMatthias Ringwald // "No Error Response or Write Response shall be sent in response to this command" 964*591423b2SMatthias Ringwald static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 965*591423b2SMatthias Ringwald uint8_t * response_buffer, uint16_t response_buffer_size){ 966*591423b2SMatthias Ringwald 967*591423b2SMatthias Ringwald if (!att_write_callback) return; 968*591423b2SMatthias Ringwald uint16_t handle = little_endian_read_16(request_buffer, 1); 969*591423b2SMatthias Ringwald att_iterator_t it; 970*591423b2SMatthias Ringwald int ok = att_find_handle(&it, handle); 971*591423b2SMatthias Ringwald if (!ok) return; 972*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return; 973*591423b2SMatthias Ringwald if ((it.flags & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) == 0) return; 974*591423b2SMatthias Ringwald if (att_validate_security(att_connection, &it)) return; 975*591423b2SMatthias Ringwald (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 976*591423b2SMatthias Ringwald } 977*591423b2SMatthias Ringwald 978*591423b2SMatthias Ringwald // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION 979*591423b2SMatthias Ringwald static uint16_t prepare_handle_value(att_connection_t * att_connection, 980*591423b2SMatthias Ringwald uint16_t handle, 981*591423b2SMatthias Ringwald uint8_t *value, 982*591423b2SMatthias Ringwald uint16_t value_len, 983*591423b2SMatthias Ringwald uint8_t * response_buffer){ 984*591423b2SMatthias Ringwald little_endian_store_16(response_buffer, 1, handle); 985*591423b2SMatthias Ringwald if (value_len > att_connection->mtu - 3){ 986*591423b2SMatthias Ringwald value_len = att_connection->mtu - 3; 987*591423b2SMatthias Ringwald } 988*591423b2SMatthias Ringwald memcpy(&response_buffer[3], value, value_len); 989*591423b2SMatthias Ringwald return value_len + 3; 990*591423b2SMatthias Ringwald } 991*591423b2SMatthias Ringwald 992*591423b2SMatthias Ringwald // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b 993*591423b2SMatthias Ringwald uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection, 994*591423b2SMatthias Ringwald uint16_t handle, 995*591423b2SMatthias Ringwald uint8_t *value, 996*591423b2SMatthias Ringwald uint16_t value_len, 997*591423b2SMatthias Ringwald uint8_t * response_buffer){ 998*591423b2SMatthias Ringwald 999*591423b2SMatthias Ringwald response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION; 1000*591423b2SMatthias Ringwald return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1001*591423b2SMatthias Ringwald } 1002*591423b2SMatthias Ringwald 1003*591423b2SMatthias Ringwald // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d 1004*591423b2SMatthias Ringwald uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection, 1005*591423b2SMatthias Ringwald uint16_t handle, 1006*591423b2SMatthias Ringwald uint8_t *value, 1007*591423b2SMatthias Ringwald uint16_t value_len, 1008*591423b2SMatthias Ringwald uint8_t * response_buffer){ 1009*591423b2SMatthias Ringwald 1010*591423b2SMatthias Ringwald response_buffer[0] = ATT_HANDLE_VALUE_INDICATION; 1011*591423b2SMatthias Ringwald return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1012*591423b2SMatthias Ringwald } 1013*591423b2SMatthias Ringwald 1014*591423b2SMatthias Ringwald // MARK: Dispatcher 1015*591423b2SMatthias Ringwald uint16_t att_handle_request(att_connection_t * att_connection, 1016*591423b2SMatthias Ringwald uint8_t * request_buffer, 1017*591423b2SMatthias Ringwald uint16_t request_len, 1018*591423b2SMatthias Ringwald uint8_t * response_buffer){ 1019*591423b2SMatthias Ringwald uint16_t response_len = 0; 1020*591423b2SMatthias Ringwald uint16_t response_buffer_size = att_connection->mtu; 1021*591423b2SMatthias Ringwald 1022*591423b2SMatthias Ringwald switch (request_buffer[0]){ 1023*591423b2SMatthias Ringwald case ATT_EXCHANGE_MTU_REQUEST: 1024*591423b2SMatthias Ringwald response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); 1025*591423b2SMatthias Ringwald break; 1026*591423b2SMatthias Ringwald case ATT_FIND_INFORMATION_REQUEST: 1027*591423b2SMatthias Ringwald response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size); 1028*591423b2SMatthias Ringwald break; 1029*591423b2SMatthias Ringwald case ATT_FIND_BY_TYPE_VALUE_REQUEST: 1030*591423b2SMatthias Ringwald response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1031*591423b2SMatthias Ringwald break; 1032*591423b2SMatthias Ringwald case ATT_READ_BY_TYPE_REQUEST: 1033*591423b2SMatthias Ringwald response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1034*591423b2SMatthias Ringwald break; 1035*591423b2SMatthias Ringwald case ATT_READ_REQUEST: 1036*591423b2SMatthias Ringwald response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1037*591423b2SMatthias Ringwald break; 1038*591423b2SMatthias Ringwald case ATT_READ_BLOB_REQUEST: 1039*591423b2SMatthias Ringwald response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1040*591423b2SMatthias Ringwald break; 1041*591423b2SMatthias Ringwald case ATT_READ_MULTIPLE_REQUEST: 1042*591423b2SMatthias Ringwald response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1043*591423b2SMatthias Ringwald break; 1044*591423b2SMatthias Ringwald case ATT_READ_BY_GROUP_TYPE_REQUEST: 1045*591423b2SMatthias Ringwald response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1046*591423b2SMatthias Ringwald break; 1047*591423b2SMatthias Ringwald case ATT_WRITE_REQUEST: 1048*591423b2SMatthias Ringwald response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1049*591423b2SMatthias Ringwald break; 1050*591423b2SMatthias Ringwald case ATT_PREPARE_WRITE_REQUEST: 1051*591423b2SMatthias Ringwald response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1052*591423b2SMatthias Ringwald break; 1053*591423b2SMatthias Ringwald case ATT_EXECUTE_WRITE_REQUEST: 1054*591423b2SMatthias Ringwald response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1055*591423b2SMatthias Ringwald break; 1056*591423b2SMatthias Ringwald case ATT_WRITE_COMMAND: 1057*591423b2SMatthias Ringwald handle_write_command(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1058*591423b2SMatthias Ringwald break; 1059*591423b2SMatthias Ringwald case ATT_SIGNED_WRITE_COMMAND: 1060*591423b2SMatthias Ringwald log_info("handle_signed_write_command preprocessed by att_server.c"); 1061*591423b2SMatthias Ringwald break; 1062*591423b2SMatthias Ringwald default: 1063*591423b2SMatthias Ringwald log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); 1064*591423b2SMatthias Ringwald log_info_hexdump(&request_buffer[9], request_len-9); 1065*591423b2SMatthias Ringwald break; 1066*591423b2SMatthias Ringwald } 1067*591423b2SMatthias Ringwald return response_len; 1068*591423b2SMatthias Ringwald } 1069*591423b2SMatthias Ringwald 1070*591423b2SMatthias Ringwald #if 0 1071*591423b2SMatthias Ringwald 1072*591423b2SMatthias Ringwald // test profile 1073*591423b2SMatthias Ringwald #include "profile.h" 1074*591423b2SMatthias Ringwald 1075*591423b2SMatthias Ringwald int main(void){ 1076*591423b2SMatthias Ringwald int acl_buffer_size; 1077*591423b2SMatthias Ringwald uint8_t acl_buffer[27]; 1078*591423b2SMatthias Ringwald att_set_db(profile_data); 1079*591423b2SMatthias Ringwald att_dump_attributes(); 1080*591423b2SMatthias Ringwald 1081*591423b2SMatthias Ringwald uint8_t uuid_1[] = { 0x00, 0x18}; 1082*591423b2SMatthias Ringwald acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); 1083*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1084*591423b2SMatthias Ringwald 1085*591423b2SMatthias Ringwald uint8_t uuid_3[] = { 0x00, 0x2a}; 1086*591423b2SMatthias Ringwald acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3); 1087*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1088*591423b2SMatthias Ringwald 1089*591423b2SMatthias Ringwald acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); 1090*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1091*591423b2SMatthias Ringwald 1092*591423b2SMatthias Ringwald uint8_t uuid_4[] = { 0x00, 0x28}; 1093*591423b2SMatthias Ringwald acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4); 1094*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1095*591423b2SMatthias Ringwald 1096*591423b2SMatthias Ringwald acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff); 1097*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1098*591423b2SMatthias Ringwald acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff); 1099*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1100*591423b2SMatthias Ringwald acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff); 1101*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1102*591423b2SMatthias Ringwald 1103*591423b2SMatthias Ringwald acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003); 1104*591423b2SMatthias Ringwald log_info_hexdump(acl_buffer, acl_buffer_size); 1105*591423b2SMatthias Ringwald 1106*591423b2SMatthias Ringwald return 0; 1107*591423b2SMatthias Ringwald } 1108*591423b2SMatthias Ringwald #endif 1109