BLE demo for mbed Ported RunningElectronics's SBDBT firmware for BLE. It can communicate with iOS
Dependencies: FatFileSystem mbed
Fork of BTstack by
att.c
00001 /* 00002 * Copyright (C) 2011-2012 by Matthias Ringwald 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 4. Any redistribution, use, or modification is done solely for 00017 * personal benefit and not for any commercial purpose or for 00018 * monetary gain. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 00021 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00023 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 00024 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00025 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00026 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00027 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00028 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00029 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00030 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00031 * SUCH DAMAGE. 00032 * 00033 * Please inquire about commercial licensing options at btstack@ringwald.ch 00034 * 00035 */ 00036 00037 #include <stdio.h> 00038 #include <string.h> 00039 00040 #include "att.h" 00041 #include "debug.h" 00042 00043 // from src/utils. 00044 #define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8)) 00045 00046 // Buetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian 00047 static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 00048 00049 static void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){ 00050 buffer[pos++] = value; 00051 buffer[pos++] = value >> 8; 00052 } 00053 00054 static void hexdump2(void const *data, int size){ 00055 int i; 00056 for (i=0; i<size;i++){ 00057 log_info("%02X ", ((uint8_t *)data)[i]); 00058 } 00059 log_info("\n"); 00060 } 00061 00062 static void printUUID128(const uint8_t * uuid){ 00063 int i; 00064 for (i=15; i >= 0 ; i--){ 00065 log_info("%02X", uuid[i]); 00066 switch (i){ 00067 case 4: 00068 case 6: 00069 case 8: 00070 case 10: 00071 log_info("-"); 00072 break; 00073 default: 00074 break; 00075 } 00076 } 00077 } 00078 00079 static int is_Bluetooth_Base_UUID(uint8_t const *uuid){ 00080 if (memcmp(&uuid[0], &bluetooth_base_uuid[0], 12)) return 0; 00081 if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0; 00082 return 1; 00083 00084 } 00085 00086 // ATT Database 00087 static uint8_t const * att_db = NULL; 00088 static att_read_callback_t att_read_callback = NULL; 00089 static att_write_callback_t att_write_callback = NULL; 00090 00091 // new java-style iterator 00092 typedef struct att_iterator { 00093 // private 00094 uint8_t const * att_ptr; 00095 // public 00096 uint16_t size; 00097 uint16_t flags; 00098 uint16_t handle; 00099 uint8_t const * uuid; 00100 uint16_t value_len; 00101 uint8_t const * value; 00102 } att_iterator_t; 00103 00104 void att_iterator_init(att_iterator_t *it){ 00105 it->att_ptr = att_db; 00106 } 00107 00108 int att_iterator_has_next(att_iterator_t *it){ 00109 return it->att_ptr != NULL; 00110 } 00111 00112 void att_iterator_fetch_next(att_iterator_t *it){ 00113 it->size = READ_BT_16(it->att_ptr, 0); 00114 if (it->size == 0){ 00115 it->flags = 0; 00116 it->handle = 0; 00117 it->uuid = NULL; 00118 it->value_len = 0; 00119 it->value = NULL; 00120 it->att_ptr = NULL; 00121 return; 00122 } 00123 it->flags = READ_BT_16(it->att_ptr, 2); 00124 it->handle = READ_BT_16(it->att_ptr, 4); 00125 it->uuid = &it->att_ptr[6]; 00126 // handle 128 bit UUIDs 00127 if (it->flags & ATT_PROPERTY_UUID128){ 00128 it->value_len = it->size - 22; 00129 it->value = &it->att_ptr[22]; 00130 } else { 00131 it->value_len = it->size - 8; 00132 it->value = &it->att_ptr[8]; 00133 } 00134 // advance AFTER setting values 00135 it->att_ptr += it->size; 00136 } 00137 00138 int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){ 00139 if (it->handle == 0) return 0; 00140 if (it->flags & ATT_PROPERTY_UUID128){ 00141 if (!is_Bluetooth_Base_UUID(it->uuid)) return 0; 00142 return READ_BT_16(it->uuid, 12) == uuid; 00143 } 00144 return READ_BT_16(it->uuid, 0) == uuid; 00145 } 00146 00147 int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){ 00148 if (it->handle == 0) return 0; 00149 // input: UUID16 00150 if (uuid_len == 2) { 00151 return att_iterator_match_uuid16(it, READ_BT_16(uuid, 0)); 00152 } 00153 // input and db: UUID128 00154 if (it->flags & ATT_PROPERTY_UUID128){ 00155 return memcmp(it->uuid, uuid, 16) == 0; 00156 } 00157 // input: UUID128, db: UUID16 00158 if (!is_Bluetooth_Base_UUID(uuid)) return 0; 00159 return READ_BT_16(uuid, 12) == READ_BT_16(it->uuid, 0); 00160 } 00161 00162 00163 int att_find_handle(att_iterator_t *it, uint16_t handle){ 00164 att_iterator_init(it); 00165 while (att_iterator_has_next(it)){ 00166 att_iterator_fetch_next(it); 00167 if (it->handle != handle) continue; 00168 return 1; 00169 } 00170 return 0; 00171 } 00172 00173 static void att_update_value_len(att_iterator_t *it){ 00174 if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0 || !att_read_callback) return; 00175 it->value_len = (*att_read_callback)(it->handle, 0, NULL, 0); 00176 return; 00177 } 00178 00179 static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 00180 00181 // DYNAMIC 00182 if ((it->flags & ATT_PROPERTY_DYNAMIC) && att_read_callback) { 00183 return (*att_read_callback)(it->handle, offset, buffer, buffer_size); 00184 } 00185 00186 // STATIC 00187 uint16_t bytes_to_copy = it->value_len; 00188 if (bytes_to_copy > buffer_size){ 00189 bytes_to_copy = buffer_size; 00190 } 00191 memcpy(buffer, it->value, bytes_to_copy); 00192 return bytes_to_copy; 00193 } 00194 00195 void att_set_db(uint8_t const * db){ 00196 att_db = db; 00197 } 00198 00199 void att_set_read_callback(att_read_callback_t callback){ 00200 att_read_callback = callback; 00201 } 00202 00203 void att_set_write_callback(att_write_callback_t callback){ 00204 att_write_callback = callback; 00205 } 00206 00207 void att_dump_attributes(void){ 00208 att_iterator_t it; 00209 att_iterator_init(&it); 00210 while (att_iterator_has_next(&it)){ 00211 att_iterator_fetch_next(&it); 00212 if (it.handle == 0) { 00213 log_info("Handle: END\n"); 00214 return; 00215 } 00216 log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags); 00217 if (it.flags & ATT_PROPERTY_UUID128){ 00218 printUUID128(it.uuid); 00219 } else { 00220 log_info("%04x", READ_BT_16(it.uuid, 0)); 00221 } 00222 log_info(", value_len: %u, value: ", it.value_len); 00223 hexdump2(it.value, it.value_len); 00224 } 00225 } 00226 00227 static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){ 00228 response_buffer[0] = ATT_ERROR_RESPONSE; 00229 response_buffer[1] = request; 00230 bt_store_16(response_buffer, 2, handle); 00231 response_buffer[4] = error_code; 00232 return 5; 00233 } 00234 00235 static uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 00236 return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND); 00237 } 00238 00239 static uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 00240 return setup_error(response_buffer, request, handle, ATT_ERROR_ATTRIBUTE_INVALID); 00241 } 00242 00243 static uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 00244 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET); 00245 } 00246 00247 // 00248 // MARK: ATT_EXCHANGE_MTU_REQUEST 00249 // 00250 static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 00251 uint8_t * response_buffer){ 00252 00253 uint16_t client_rx_mtu = READ_BT_16(request_buffer, 1); 00254 if (client_rx_mtu < att_connection->mtu){ 00255 att_connection->mtu = client_rx_mtu; 00256 } 00257 00258 response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE; 00259 bt_store_16(response_buffer, 1, att_connection->mtu); 00260 return 3; 00261 } 00262 00263 00264 // 00265 // MARK: ATT_FIND_INFORMATION_REQUEST 00266 // 00267 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 00268 // 00269 static uint16_t handle_find_information_request2(uint8_t * response_buffer, uint16_t response_buffer_size, 00270 uint16_t start_handle, uint16_t end_handle){ 00271 00272 log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X\n", start_handle, end_handle); 00273 00274 uint16_t offset = 1; 00275 uint16_t pair_len = 0; 00276 00277 att_iterator_t it; 00278 att_iterator_init(&it); 00279 while (att_iterator_has_next(&it)){ 00280 att_iterator_fetch_next(&it); 00281 if (!it.handle) break; 00282 if (it.handle > end_handle) break; 00283 if (it.handle < start_handle) continue; 00284 00285 att_update_value_len(&it); 00286 00287 // log_debug("Handle 0x%04x\n", it.handle); 00288 00289 // check if value has same len as last one 00290 uint16_t this_pair_len = 2 + it.value_len; 00291 if (offset > 1){ 00292 if (pair_len != this_pair_len) { 00293 break; 00294 } 00295 } 00296 00297 // first 00298 if (offset == 1) { 00299 pair_len = this_pair_len; 00300 if (it.value_len == 2) { 00301 response_buffer[offset] = 0x01; // format 00302 } else { 00303 response_buffer[offset] = 0x02; 00304 } 00305 offset++; 00306 } 00307 00308 // space? 00309 if (offset + pair_len > response_buffer_size) { 00310 if (offset > 2) break; 00311 it.value_len = response_buffer_size - 4; 00312 } 00313 00314 // store 00315 bt_store_16(response_buffer, offset, it.handle); 00316 offset += 2; 00317 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); 00318 offset += bytes_copied; 00319 } 00320 00321 if (offset == 1){ 00322 return setup_error_atribute_not_found(response_buffer, ATT_FIND_INFORMATION_REQUEST, start_handle); 00323 } 00324 00325 response_buffer[0] = ATT_FIND_INFORMATION_REPLY; 00326 return offset; 00327 } 00328 00329 static uint16_t handle_find_information_request(uint8_t * request_buffer, uint16_t request_len, 00330 uint8_t * response_buffer, uint16_t response_buffer_size){ 00331 return handle_find_information_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3)); 00332 } 00333 00334 // 00335 // MARK: ATT_FIND_BY_TYPE_VALUE 00336 // 00337 // "Only attributes with attribute handles between and including the Starting Handle parameter 00338 // and the Ending Handle parameter that match the requested attri- bute type and the attribute 00339 // value that have sufficient permissions to allow reading will be returned" -> (1) 00340 // 00341 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 00342 // 00343 // NOTE: doesn't handle DYNAMIC values 00344 // NOTE: only supports 16 bit UUIDs 00345 // 00346 static uint16_t handle_find_by_type_value_request2(uint8_t * response_buffer, uint16_t response_buffer_size, 00347 uint16_t start_handle, uint16_t end_handle, 00348 uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){ 00349 00350 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type); 00351 hexdump2(attribute_value, attribute_len); 00352 00353 uint16_t offset = 1; 00354 uint16_t in_group = 0; 00355 uint16_t prev_handle = 0; 00356 00357 att_iterator_t it; 00358 att_iterator_init(&it); 00359 while (att_iterator_has_next(&it)){ 00360 att_iterator_fetch_next(&it); 00361 00362 if (it.handle && it.handle < start_handle) continue; 00363 if (it.handle > end_handle) break; // (1) 00364 00365 // close current tag, if within a group and a new service definition starts or we reach end of att db 00366 if (in_group && 00367 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 00368 00369 log_info("End of group, handle 0x%04x\n", prev_handle); 00370 bt_store_16(response_buffer, offset, prev_handle); 00371 offset += 2; 00372 in_group = 0; 00373 00374 // check if space for another handle pair available 00375 if (offset + 4 > response_buffer_size){ 00376 break; 00377 } 00378 } 00379 00380 // keep track of previous handle 00381 prev_handle = it.handle; 00382 00383 // does current attribute match 00384 if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ 00385 log_info("Begin of group, handle 0x%04x\n", it.handle); 00386 bt_store_16(response_buffer, offset, it.handle); 00387 offset += 2; 00388 in_group = 1; 00389 } 00390 } 00391 00392 if (offset == 1){ 00393 return setup_error_atribute_not_found(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST, start_handle); 00394 } 00395 00396 response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE; 00397 return offset; 00398 } 00399 00400 static uint16_t handle_find_by_type_value_request(uint8_t * request_buffer, uint16_t request_len, 00401 uint8_t * response_buffer, uint16_t response_buffer_size){ 00402 int attribute_len = request_len - 7; 00403 return handle_find_by_type_value_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), 00404 READ_BT_16(request_buffer, 3), READ_BT_16(request_buffer, 5), attribute_len, &request_buffer[7]); 00405 } 00406 00407 // 00408 // MARK: ATT_READ_BY_TYPE_REQUEST 00409 // 00410 static uint16_t handle_read_by_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size, 00411 uint16_t start_handle, uint16_t end_handle, 00412 uint16_t attribute_type_len, uint8_t * attribute_type){ 00413 00414 log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); 00415 hexdump2(attribute_type, attribute_type_len); 00416 00417 uint16_t offset = 1; 00418 uint16_t pair_len = 0; 00419 00420 att_iterator_t it; 00421 att_iterator_init(&it); 00422 while (att_iterator_has_next(&it)){ 00423 att_iterator_fetch_next(&it); 00424 00425 if (!it.handle) break; 00426 if (it.handle < start_handle) continue; 00427 if (it.handle > end_handle) break; // (1) 00428 00429 // does current attribute match 00430 if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; 00431 00432 att_update_value_len(&it); 00433 00434 // check if value has same len as last one 00435 uint16_t this_pair_len = 2 + it.value_len; 00436 if (offset > 1){ 00437 if (pair_len != this_pair_len) { 00438 break; 00439 } 00440 } 00441 00442 // first 00443 if (offset == 1) { 00444 pair_len = this_pair_len; 00445 response_buffer[offset] = pair_len; 00446 offset++; 00447 } 00448 00449 // space? 00450 if (offset + pair_len > response_buffer_size) { 00451 if (offset > 2) break; 00452 it.value_len = response_buffer_size - 4; 00453 } 00454 00455 // store 00456 bt_store_16(response_buffer, offset, it.handle); 00457 offset += 2; 00458 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); 00459 offset += bytes_copied; 00460 } 00461 00462 if (offset == 1){ 00463 return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_TYPE_REQUEST, start_handle); 00464 } 00465 00466 response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; 00467 return offset; 00468 } 00469 00470 static uint16_t handle_read_by_type_request(uint8_t * request_buffer, uint16_t request_len, 00471 uint8_t * response_buffer, uint16_t response_buffer_size){ 00472 int attribute_type_len; 00473 if (request_len <= 7){ 00474 attribute_type_len = 2; 00475 } else { 00476 attribute_type_len = 16; 00477 } 00478 return handle_read_by_type_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 00479 } 00480 00481 // 00482 // MARK: ATT_READ_BY_TYPE_REQUEST 00483 // 00484 static uint16_t handle_read_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ 00485 00486 log_info("ATT_READ_REQUEST: handle %04x\n", handle); 00487 00488 att_iterator_t it; 00489 int ok = att_find_handle(&it, handle); 00490 if (!ok){ 00491 return setup_error_atribute_not_found(response_buffer, ATT_READ_REQUEST, handle); 00492 } 00493 00494 att_update_value_len(&it); 00495 00496 uint16_t offset = 1; 00497 // limit data 00498 if (offset + it.value_len > response_buffer_size) { 00499 it.value_len = response_buffer_size - 1; 00500 } 00501 00502 // store 00503 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); 00504 offset += bytes_copied; 00505 00506 response_buffer[0] = ATT_READ_RESPONSE; 00507 return offset; 00508 } 00509 00510 static uint16_t handle_read_request(uint8_t * request_buffer, uint16_t request_len, 00511 uint8_t * response_buffer, uint16_t response_buffer_size){ 00512 return handle_read_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1)); 00513 } 00514 00515 // 00516 // MARK: ATT_READ_BLOB_REQUEST 0x0c 00517 // 00518 static uint16_t handle_read_blob_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){ 00519 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u\n", handle, value_offset); 00520 00521 att_iterator_t it; 00522 int ok = att_find_handle(&it, handle); 00523 if (!ok){ 00524 return setup_error_atribute_not_found(response_buffer, ATT_READ_BLOB_REQUEST, handle); 00525 } 00526 00527 att_update_value_len(&it); 00528 00529 if (value_offset >= it.value_len){ 00530 return setup_error_invalid_offset(response_buffer, ATT_READ_BLOB_REQUEST, handle); 00531 } 00532 00533 // limit data 00534 uint16_t offset = 1; 00535 if (offset + it.value_len - value_offset > response_buffer_size) { 00536 it.value_len = response_buffer_size - 1 + value_offset; 00537 } 00538 00539 // store 00540 uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset); 00541 offset += bytes_copied; 00542 00543 response_buffer[0] = ATT_READ_BLOB_RESPONSE; 00544 return offset; 00545 } 00546 00547 uint16_t handle_read_blob_request(uint8_t * request_buffer, uint16_t request_len, 00548 uint8_t * response_buffer, uint16_t response_buffer_size){ 00549 return handle_read_blob_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3)); 00550 } 00551 00552 // 00553 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e 00554 // 00555 static uint16_t handle_read_multiple_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint16_t * handles){ 00556 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u\n", num_handles); 00557 00558 uint16_t offset = 1; 00559 00560 int i; 00561 for (i=0;i<num_handles;i++){ 00562 uint16_t handle = handles[i]; 00563 00564 if (handle == 0){ 00565 return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle); 00566 } 00567 00568 att_iterator_t it; 00569 00570 int ok = att_find_handle(&it, handle); 00571 if (!ok){ 00572 return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle); 00573 } 00574 00575 att_update_value_len(&it); 00576 00577 // limit data 00578 if (offset + it.value_len > response_buffer_size) { 00579 it.value_len = response_buffer_size - 1; 00580 } 00581 00582 // store 00583 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); 00584 offset += bytes_copied; 00585 } 00586 00587 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; 00588 return offset; 00589 } 00590 uint16_t handle_read_multiple_request(uint8_t * request_buffer, uint16_t request_len, 00591 uint8_t * response_buffer, uint16_t response_buffer_size){ 00592 int num_handles = (request_len - 1) >> 1; 00593 return handle_read_multiple_request2(response_buffer, response_buffer_size, num_handles, (uint16_t*) &request_buffer[1]); 00594 } 00595 00596 // 00597 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 00598 // 00599 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 00600 // 00601 // NOTE: doesn't handle DYNAMIC values 00602 // 00603 static uint16_t handle_read_by_group_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size, 00604 uint16_t start_handle, uint16_t end_handle, 00605 uint16_t attribute_type_len, uint8_t * attribute_type){ 00606 00607 log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); 00608 hexdump2(attribute_type, attribute_type_len); 00609 00610 uint16_t offset = 1; 00611 uint16_t pair_len = 0; 00612 uint16_t in_group = 0; 00613 uint16_t group_start_handle = 0; 00614 uint8_t const * group_start_value = NULL; 00615 uint16_t prev_handle = 0; 00616 00617 att_iterator_t it; 00618 att_iterator_init(&it); 00619 while (att_iterator_has_next(&it)){ 00620 att_iterator_fetch_next(&it); 00621 00622 if (it.handle && it.handle < start_handle) continue; 00623 if (it.handle > end_handle) break; // (1) 00624 00625 // close current tag, if within a group and a new service definition starts or we reach end of att db 00626 if (in_group && 00627 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 00628 // TODO: check if handle is included in start/end range 00629 // log_debug("End of group, handle 0x%04x, val_len: %u\n", prev_handle, pair_len - 4); 00630 00631 bt_store_16(response_buffer, offset, group_start_handle); 00632 offset += 2; 00633 bt_store_16(response_buffer, offset, prev_handle); 00634 offset += 2; 00635 memcpy(response_buffer + offset, group_start_value, pair_len - 4); 00636 offset += pair_len - 4; 00637 in_group = 0; 00638 00639 // check if space for another handle pair available 00640 if (offset + pair_len > response_buffer_size){ 00641 break; 00642 } 00643 } 00644 00645 // keep track of previous handle 00646 prev_handle = it.handle; 00647 00648 // does current attribute match 00649 // log_debug("compare: %04x == %04x\n", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); 00650 if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { 00651 00652 // check if value has same len as last one 00653 uint16_t this_pair_len = 4 + it.value_len; 00654 if (offset > 1){ 00655 if (this_pair_len != pair_len) { 00656 break; 00657 } 00658 } 00659 00660 // log_debug("Begin of group, handle 0x%04x\n", it.handle); 00661 00662 // first 00663 if (offset == 1) { 00664 pair_len = this_pair_len; 00665 response_buffer[offset] = this_pair_len; 00666 offset++; 00667 } 00668 00669 group_start_handle = it.handle; 00670 group_start_value = it.value; 00671 in_group = 1; 00672 } 00673 } 00674 00675 if (offset == 1){ 00676 return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST, start_handle); 00677 } 00678 00679 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; 00680 return offset; 00681 } 00682 uint16_t handle_read_by_group_type_request(uint8_t * request_buffer, uint16_t request_len, 00683 uint8_t * response_buffer, uint16_t response_buffer_size){ 00684 int attribute_type_len; 00685 if (request_len <= 7){ 00686 attribute_type_len = 2; 00687 } else { 00688 attribute_type_len = 16; 00689 } 00690 return handle_read_by_group_type_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 00691 } 00692 00693 // 00694 // MARK: ATT_WRITE_REQUEST 0x12 00695 static uint16_t handle_write_request(uint8_t * request_buffer, uint16_t request_len, 00696 uint8_t * response_buffer, uint16_t response_buffer_size){ 00697 uint16_t handle = READ_BT_16(request_buffer, 1); 00698 if (!att_write_callback) { 00699 // TODO: Use "Write Not Permitted" 00700 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); 00701 } 00702 att_iterator_t it; 00703 int ok = att_find_handle(&it, handle); 00704 if (!ok) { 00705 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); 00706 } 00707 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 00708 // TODO: Use "Write Not Permitted" 00709 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); 00710 } 00711 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL); 00712 response_buffer[0] = ATT_WRITE_RESPONSE; 00713 return 1; 00714 } 00715 00716 // 00717 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 00718 static uint16_t handle_prepare_write_request(uint8_t * request_buffer, uint16_t request_len, 00719 uint8_t * response_buffer, uint16_t response_buffer_size){ 00720 uint16_t handle = READ_BT_16(request_buffer, 1); 00721 if (!att_write_callback) { 00722 // TODO: Use "Write Not Permitted" 00723 return setup_error_atribute_not_found(response_buffer, ATT_PREPARE_WRITE_REQUEST, handle); 00724 } 00725 att_iterator_t it; 00726 int ok = att_find_handle(&it, handle); 00727 if (!ok) { 00728 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); 00729 } 00730 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 00731 // TODO: Use "Write Not Permitted" 00732 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); 00733 } 00734 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, 0, request_buffer + 3, request_len - 3, NULL); 00735 00736 // response: echo request 00737 memcpy(response_buffer, request_buffer, request_len); 00738 response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; 00739 return request_len; 00740 } 00741 00742 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 00743 static uint16_t handle_execute_write_request(uint8_t * request_buffer, uint16_t request_len, 00744 uint8_t * response_buffer, uint16_t response_buffer_size){ 00745 if (!att_write_callback) { 00746 // TODO: Use "Write Not Permitted" 00747 return setup_error_atribute_not_found(response_buffer, ATT_EXECUTE_WRITE_REQUEST, 0); 00748 } 00749 if (request_buffer[1]) { 00750 (*att_write_callback)(0, ATT_TRANSACTION_MODE_EXECUTE, 0, request_buffer + 3, request_len - 3, NULL); 00751 } else { 00752 (*att_write_callback)(0, ATT_TRANSACTION_MODE_CANCEL, 0, request_buffer + 3, request_len - 3, NULL); 00753 } 00754 response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; 00755 return 1; 00756 } 00757 00758 // MARK: ATT_WRITE_COMMAND 0x52 00759 static void handle_write_command(uint8_t * request_buffer, uint16_t request_len, 00760 uint8_t * response_buffer, uint16_t response_buffer_size){ 00761 if (!att_write_callback) return; 00762 uint16_t handle = READ_BT_16(request_buffer, 1); 00763 att_iterator_t it; 00764 int ok = att_find_handle(&it, handle); 00765 if (!ok) return; 00766 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return; 00767 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL); 00768 } 00769 00770 // MARK: ATT_SIGNED_WRITE_COMAND 0xD2 00771 static void handle_signed_write_command(uint8_t * request_buffer, uint16_t request_len, 00772 uint8_t * response_buffer, uint16_t response_buffer_size){ 00773 00774 if (request_len < 15) return; 00775 if (!att_write_callback) return; 00776 uint16_t handle = READ_BT_16(request_buffer, 1); 00777 att_iterator_t it; 00778 int ok = att_find_handle(&it, handle); 00779 if (!ok) return; 00780 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return; 00781 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3 - 12, (signature_t *) request_buffer + request_len - 12); 00782 } 00783 00784 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION 00785 static uint16_t prepare_handle_value(att_connection_t * att_connection, 00786 uint16_t handle, 00787 uint8_t *value, 00788 uint16_t value_len, 00789 uint8_t * response_buffer){ 00790 bt_store_16(response_buffer, 1, handle); 00791 if (value_len > att_connection->mtu - 3){ 00792 value_len = att_connection->mtu - 3; 00793 } 00794 memcpy(&response_buffer[3], value, value_len); 00795 return value_len + 3; 00796 } 00797 00798 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b 00799 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection, 00800 uint16_t handle, 00801 uint8_t *value, 00802 uint16_t value_len, 00803 uint8_t * response_buffer){ 00804 00805 response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION; 00806 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 00807 } 00808 00809 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d 00810 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection, 00811 uint16_t handle, 00812 uint8_t *value, 00813 uint16_t value_len, 00814 uint8_t * response_buffer){ 00815 00816 response_buffer[0] = ATT_HANDLE_VALUE_INDICATION; 00817 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 00818 } 00819 00820 // MARK: Dispatcher 00821 uint16_t att_handle_request(att_connection_t * att_connection, 00822 uint8_t * request_buffer, 00823 uint16_t request_len, 00824 uint8_t * response_buffer){ 00825 uint16_t response_len = 0; 00826 uint16_t response_buffer_size = att_connection->mtu; 00827 00828 switch (request_buffer[0]){ 00829 case ATT_EXCHANGE_MTU_REQUEST: 00830 response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); 00831 break; 00832 case ATT_FIND_INFORMATION_REQUEST: 00833 response_len = handle_find_information_request(request_buffer, request_len,response_buffer, response_buffer_size); 00834 break; 00835 case ATT_FIND_BY_TYPE_VALUE_REQUEST: 00836 response_len = handle_find_by_type_value_request(request_buffer, request_len, response_buffer, response_buffer_size); 00837 break; 00838 case ATT_READ_BY_TYPE_REQUEST: 00839 response_len = handle_read_by_type_request(request_buffer, request_len, response_buffer, response_buffer_size); 00840 break; 00841 case ATT_READ_REQUEST: 00842 response_len = handle_read_request(request_buffer, request_len, response_buffer, response_buffer_size); 00843 break; 00844 case ATT_READ_BLOB_REQUEST: 00845 response_len = handle_read_blob_request(request_buffer, request_len, response_buffer, response_buffer_size); 00846 break; 00847 case ATT_READ_MULTIPLE_REQUEST: 00848 response_len = handle_read_multiple_request(request_buffer, request_len, response_buffer, response_buffer_size); 00849 break; 00850 case ATT_READ_BY_GROUP_TYPE_REQUEST: 00851 response_len = handle_read_by_group_type_request(request_buffer, request_len, response_buffer, response_buffer_size); 00852 break; 00853 case ATT_WRITE_REQUEST: 00854 response_len = handle_write_request(request_buffer, request_len, response_buffer, response_buffer_size); 00855 break; 00856 case ATT_PREPARE_WRITE_REQUEST: 00857 response_len = handle_prepare_write_request(request_buffer, request_len, response_buffer, response_buffer_size); 00858 break; 00859 case ATT_EXECUTE_WRITE_REQUEST: 00860 response_len = handle_execute_write_request(request_buffer, request_len, response_buffer, response_buffer_size); 00861 break; 00862 case ATT_WRITE_COMMAND: 00863 handle_write_command(request_buffer, request_len, response_buffer, response_buffer_size); 00864 break; 00865 case ATT_SIGNED_WRITE_COMAND: 00866 handle_signed_write_command(request_buffer, request_len, response_buffer, response_buffer_size); 00867 break; 00868 default: 00869 log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); 00870 hexdump2(&request_buffer[9], request_len-9); 00871 break; 00872 } 00873 return response_len; 00874 } 00875 00876 #if 0 00877 00878 // test profile 00879 #include "profile.h" 00880 00881 int main(){ 00882 int acl_buffer_size; 00883 uint8_t acl_buffer[27]; 00884 att_set_db(profile_data); 00885 att_dump_attributes(); 00886 00887 uint8_t uuid_1[] = { 0x00, 0x18}; 00888 acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); 00889 hexdump2(acl_buffer, acl_buffer_size); 00890 00891 uint8_t uuid_3[] = { 0x00, 0x2a}; 00892 acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3); 00893 hexdump2(acl_buffer, acl_buffer_size); 00894 00895 acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); 00896 hexdump2(acl_buffer, acl_buffer_size); 00897 00898 uint8_t uuid_4[] = { 0x00, 0x28}; 00899 acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4); 00900 hexdump2(acl_buffer, acl_buffer_size); 00901 00902 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff); 00903 hexdump2(acl_buffer, acl_buffer_size); 00904 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff); 00905 hexdump2(acl_buffer, acl_buffer_size); 00906 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff); 00907 hexdump2(acl_buffer, acl_buffer_size); 00908 00909 acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003); 00910 hexdump2(acl_buffer, acl_buffer_size); 00911 00912 return 0; 00913 } 00914 #endif
Generated on Thu Jul 14 2022 15:03:48 by 1.7.2