// // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e // static uint16_t handle_read_multiple_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint16_t * handles){ printf("ATT_READ_MULTIPLE_REQUEST: num handles %u\n", num_handles); uint16_t offset = 1; int i; for (i=0;i<num_handles;i++){ uint16_t handle = handles[i]; if (handle == 0){ return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle); } att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle); } att_update_value_len(&it); // limit data if (offset + it.value_len > response_buffer_size) { it.value_len = response_buffer_size - 1; } // store uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); offset += bytes_copied; } response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; return offset; }
// // MARK: ATT_READ_BLOB_REQUEST 0x0c // static uint16_t handle_read_blob_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){ printf("ATT_READ_BLOB_REQUEST: handle %04x, offset %u\n", handle, value_offset); att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_atribute_not_found(response_buffer, ATT_READ_BLOB_REQUEST, handle); } att_update_value_len(&it); if (value_offset >= it.value_len){ return setup_error_invalid_offset(response_buffer, ATT_READ_BLOB_REQUEST, handle); } // limit data uint16_t offset = 1; if (offset + it.value_len - value_offset > response_buffer_size) { it.value_len = response_buffer_size - 1 + value_offset; } // store uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset); offset += bytes_copied; response_buffer[0] = ATT_READ_BLOB_RESPONSE; return offset; }
// // MARK: ATT_READ_BY_TYPE_REQUEST // static uint16_t handle_read_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ printf("ATT_READ_REQUEST: handle %04x\n", handle); att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_atribute_not_found(response_buffer, ATT_READ_REQUEST, handle); } att_update_value_len(&it); uint16_t offset = 1; // limit data if (offset + it.value_len > response_buffer_size) { it.value_len = response_buffer_size - 1; } // store uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); offset += bytes_copied; response_buffer[0] = ATT_READ_RESPONSE; return offset; }
// // MARK: ATT_READ_BY_TYPE_REQUEST // static uint16_t handle_read_by_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type_len, uint8_t * attribute_type){ printf("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); hexdump2(attribute_type, attribute_type_len); uint16_t offset = 1; uint16_t pair_len = 0; att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (!it.handle) break; if (it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // does current attribute match if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; att_update_value_len(&it); // check if value has same len as last one uint16_t this_pair_len = 2 + it.value_len; if (offset > 1){ if (pair_len != this_pair_len) { break; } } // first if (offset == 1) { pair_len = this_pair_len; response_buffer[offset] = pair_len; offset++; } // space? if (offset + pair_len > response_buffer_size) { if (offset > 2) break; it.value_len = response_buffer_size - 4; } // store bt_store_16(response_buffer, offset, it.handle); offset += 2; uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); offset += bytes_copied; } if (offset == 1){ return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_TYPE_REQUEST, start_handle); } response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; return offset; }
// // MARK: ATT_FIND_INFORMATION_REQUEST // // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID // static uint16_t handle_find_information_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle){ printf("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X\n", start_handle, end_handle); uint16_t offset = 1; uint16_t pair_len = 0; att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (!it.handle) break; if (it.handle > end_handle) break; if (it.handle < start_handle) continue; att_update_value_len(&it); // printf("Handle 0x%04x\n", it.handle); // check if value has same len as last one uint16_t this_pair_len = 2 + it.value_len; if (offset > 1){ if (pair_len != this_pair_len) { break; } } // first if (offset == 1) { pair_len = this_pair_len; if (it.value_len == 2) { response_buffer[offset] = 0x01; // format } else { response_buffer[offset] = 0x02; } offset++; } // space? if (offset + pair_len > response_buffer_size) { if (offset > 2) break; it.value_len = response_buffer_size - 4; } // store bt_store_16(response_buffer, offset, it.handle); offset += 2; uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len); offset += bytes_copied; } if (offset == 1){ return setup_error_atribute_not_found(response_buffer, ATT_FIND_INFORMATION_REQUEST, start_handle); } response_buffer[0] = ATT_FIND_INFORMATION_REPLY; return offset; }
// // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e // 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){ log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles); uint8_t request_type = ATT_READ_MULTIPLE_REQUEST; // TODO: figure out which error to respond with // if (num_handles < 2){ // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); // } uint16_t offset = 1; int i; uint8_t error_code = 0; uint16_t handle = 0; for (i=0;i<num_handles;i++){ handle = READ_BT_16(handles, i << 1); if (handle == 0){ return setup_error_invalid_handle(response_buffer, request_type, handle); } att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_invalid_handle(response_buffer, request_type, handle); } // check if handle can be read if ((it.flags & ATT_PROPERTY_READ) == 0) { error_code = ATT_ERROR_READ_NOT_PERMITTED; break; } // check security requirements error_code = att_validate_security(att_connection, &it); if (error_code) break; att_update_value_len(&it, att_connection->con_handle); // limit data if (offset + it.value_len > response_buffer_size) { it.value_len = response_buffer_size - 1; } // store uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); offset += bytes_copied; } if (error_code){ return setup_error(response_buffer, request_type, handle, error_code); } response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; return offset; }
// // MARK: ATT_READ_BLOB_REQUEST 0x0c // 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){ log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); uint8_t request_type = ATT_READ_BLOB_REQUEST; att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_invalid_handle(response_buffer, request_type, handle); } // check if handle can be read if ((it.flags & ATT_PROPERTY_READ) == 0) { return setup_error_read_not_permitted(response_buffer, request_type, handle); } // check security requirements uint8_t error_code = att_validate_security(att_connection, &it); if (error_code) { return setup_error(response_buffer, request_type, handle, error_code); } att_update_value_len(&it, att_connection->con_handle); if (value_offset > it.value_len){ return setup_error_invalid_offset(response_buffer, request_type, handle); } // limit data uint16_t offset = 1; if (offset + it.value_len - value_offset > response_buffer_size) { it.value_len = response_buffer_size - 1 + value_offset; } // store uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle); offset += bytes_copied; response_buffer[0] = ATT_READ_BLOB_RESPONSE; return offset; }
// // MARK: ATT_READ_BY_TYPE_REQUEST // static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type_len, uint8_t * attribute_type){ log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); hexdump(attribute_type, attribute_type_len); uint8_t request_type = ATT_READ_BY_TYPE_REQUEST; if (start_handle > end_handle || start_handle == 0){ return setup_error_invalid_handle(response_buffer, request_type, start_handle); } uint16_t offset = 1; uint16_t pair_len = 0; att_iterator_t it; att_iterator_init(&it); uint8_t error_code = 0; uint16_t first_matching_but_unreadable_handle = 0; while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (!it.handle) break; if (it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // does current attribute match if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; // skip handles that cannot be read but rembember that there has been at least one if ((it.flags & ATT_PROPERTY_READ) == 0) { if (first_matching_but_unreadable_handle == 0) { first_matching_but_unreadable_handle = it.handle; } continue; } // check security requirements error_code = att_validate_security(att_connection, &it); if (error_code) break; att_update_value_len(&it, att_connection->con_handle); // check if value has same len as last one uint16_t this_pair_len = 2 + it.value_len; if (offset > 1){ if (pair_len != this_pair_len) { break; } } // first if (offset == 1) { pair_len = this_pair_len; response_buffer[offset] = pair_len; offset++; } // space? if (offset + pair_len > response_buffer_size) { if (offset > 2) break; it.value_len = response_buffer_size - 4; response_buffer[1] = 2 + it.value_len; } // store bt_store_16(response_buffer, offset, it.handle); offset += 2; uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); offset += bytes_copied; } // at least one attribute could be read if (offset > 1){ response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; return offset; } // first attribute had an error if (error_code){ return setup_error(response_buffer, request_type, start_handle, error_code); } // no other errors, but all found attributes had been non-readable if (first_matching_but_unreadable_handle){ return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); } // attribute not found return setup_error_atribute_not_found(response_buffer, request_type, start_handle); }