int main(){ int acl_buffer_size; uint8_t acl_buffer[27]; att_set_db(profile_data); att_dump_attributes(); uint8_t uuid_1[] = { 0x00, 0x18}; acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); hexdump2(acl_buffer, acl_buffer_size); uint8_t uuid_3[] = { 0x00, 0x2a}; acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3); hexdump2(acl_buffer, acl_buffer_size); acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1); hexdump2(acl_buffer, acl_buffer_size); uint8_t uuid_4[] = { 0x00, 0x28}; acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4); hexdump2(acl_buffer, acl_buffer_size); acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff); hexdump2(acl_buffer, acl_buffer_size); acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff); hexdump2(acl_buffer, acl_buffer_size); acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff); hexdump2(acl_buffer, acl_buffer_size); acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003); hexdump2(acl_buffer, acl_buffer_size); return 0; }
// // 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; }
int main(){ uint8_t key[16]; uint8_t plaintext[16]; bzero(key, 16); bzero(plaintext, 16); uint8_t cyphertext[16]; aes128_calc_cyphertext(key, plaintext, cyphertext); hexdump2(cyphertext, 16); }
// MARK: Dispatcher uint16_t att_handle_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint8_t * response_buffer){ uint16_t response_len = 0; uint16_t response_buffer_size = att_connection->mtu; switch (request_buffer[0]){ case ATT_EXCHANGE_MTU_REQUEST: response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); break; case ATT_FIND_INFORMATION_REQUEST: response_len = handle_find_information_request(request_buffer, request_len,response_buffer, response_buffer_size); break; case ATT_FIND_BY_TYPE_VALUE_REQUEST: response_len = handle_find_by_type_value_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_READ_BY_TYPE_REQUEST: response_len = handle_read_by_type_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_READ_REQUEST: response_len = handle_read_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_READ_BLOB_REQUEST: response_len = handle_read_blob_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_READ_MULTIPLE_REQUEST: response_len = handle_read_multiple_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_READ_BY_GROUP_TYPE_REQUEST: response_len = handle_read_by_group_type_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_WRITE_REQUEST: response_len = handle_write_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_PREPARE_WRITE_REQUEST: response_len = handle_prepare_write_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_EXECUTE_WRITE_REQUEST: response_len = handle_execute_write_request(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_WRITE_COMMAND: handle_write_command(request_buffer, request_len, response_buffer, response_buffer_size); break; case ATT_SIGNED_WRITE_COMAND: handle_signed_write_command(request_buffer, request_len, response_buffer, response_buffer_size); break; default: printf("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); hexdump2(&request_buffer[9], request_len-9); break; } return response_len; }
// // MARK: ATT_FIND_BY_TYPE_VALUE // // "Only attributes with attribute handles between and including the Starting Handle parameter // and the Ending Handle parameter that match the requested attri- bute type and the attribute // value that have sufficient permissions to allow reading will be returned" -> (1) // // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID // // NOTE: doesn't handle DYNAMIC values // NOTE: only supports 16 bit UUIDs // static uint16_t handle_find_by_type_value_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){ printf("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type); hexdump2(attribute_value, attribute_len); uint16_t offset = 1; uint16_t in_group = 0; uint16_t prev_handle = 0; att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (it.handle && it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // close current tag, if within a group and a new service definition starts or we reach end of att db if (in_group && (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ printf("End of group, handle 0x%04x\n", prev_handle); bt_store_16(response_buffer, offset, prev_handle); offset += 2; in_group = 0; // check if space for another handle pair available if (offset + 4 > response_buffer_size){ break; } } // keep track of previous handle prev_handle = it.handle; // does current attribute match if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ printf("Begin of group, handle 0x%04x\n", it.handle); bt_store_16(response_buffer, offset, it.handle); offset += 2; in_group = 1; } } if (offset == 1){ return setup_error_atribute_not_found(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST, start_handle); } response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE; return offset; }
void att_dump_attributes(void){ att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (it.handle == 0) { printf("Handle: END\n"); return; } printf("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags); if (it.flags & ATT_PROPERTY_UUID128){ printUUID128(it.uuid); } else { printf("%04x", READ_BT_16(it.uuid, 0)); } printf(", value_len: %u, value: ", it.value_len); hexdump2(it.value, it.value_len); } }
// // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 // // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID // // NOTE: doesn't handle DYNAMIC values // static uint16_t handle_read_by_group_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_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); hexdump2(attribute_type, attribute_type_len); uint16_t offset = 1; uint16_t pair_len = 0; uint16_t in_group = 0; uint16_t group_start_handle = 0; uint8_t const * group_start_value = NULL; uint16_t prev_handle = 0; att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (it.handle && it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // close current tag, if within a group and a new service definition starts or we reach end of att db if (in_group && (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ // TODO: check if handle is included in start/end range // printf("End of group, handle 0x%04x, val_len: %u\n", prev_handle, pair_len - 4); bt_store_16(response_buffer, offset, group_start_handle); offset += 2; bt_store_16(response_buffer, offset, prev_handle); offset += 2; memcpy(response_buffer + offset, group_start_value, pair_len - 4); offset += pair_len - 4; in_group = 0; // check if space for another handle pair available if (offset + pair_len > response_buffer_size){ break; } } // keep track of previous handle prev_handle = it.handle; // does current attribute match // printf("compare: %04x == %04x\n", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { // check if value has same len as last one uint16_t this_pair_len = 4 + it.value_len; if (offset > 1){ if (this_pair_len != pair_len) { break; } } // printf("Begin of group, handle 0x%04x\n", it.handle); // first if (offset == 1) { pair_len = this_pair_len; response_buffer[offset] = this_pair_len; offset++; } group_start_handle = it.handle; group_start_value = it.value; in_group = 1; } } if (offset == 1){ return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST, start_handle); } response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; return offset; }