diff --git a/test/pts/ble_peripheral_test.gatt b/test/pts/ble_peripheral_test.gatt deleted file mode 100644 index 051343054..000000000 --- a/test/pts/ble_peripheral_test.gatt +++ /dev/null @@ -1,12 +0,0 @@ -PRIMARY_SERVICE, GAP_SERVICE -CHARACTERISTIC, GAP_DEVICE_NAME, READ | WRITE | DYNAMIC -CHARACTERISTIC, GAP_PERIPHERAL_PRIVACY_FLAG, READ | WRITE | DYNAMIC -CHARACTERISTIC, GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS, READ, FF FF FF 00 03 FF FF -CHARACTERISTIC, GAP_APPEARANCE, READ | WRITE | DYNAMIC -CHARACTERISTIC, GAP_RECONNECTION_ADDRESS, READ | WRITE | DYNAMIC - -PRIMARY_SERVICE, GATT_SERVICE -CHARACTERISTIC, GATT_SERVICE_CHANGED, READ - -PRIMARY_SERVICE, FFF0 -CHARACTERISTIC, FFF1, READ | WRITE | AUTHENTICATED_SIGNED_WRITE | AUTHENTICATION_REQUIRED, "A" diff --git a/test/pts/ble_peripheral_test.c b/test/pts/gatt_server_test.c similarity index 80% rename from test/pts/ble_peripheral_test.c rename to test/pts/gatt_server_test.c index 450821a93..2bdfbd507 100644 --- a/test/pts/ble_peripheral_test.c +++ b/test/pts/gatt_server_test.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "btstack_config.h" @@ -53,6 +54,7 @@ #include "ble/att_server.h" #include "ble/le_device_db.h" #include "ble/sm.h" +#include "bluetooth_gatt.h" #include "btstack_debug.h" #include "btstack_event.h" #include "btstack_memory.h" @@ -62,11 +64,17 @@ #include "hci_dump.h" #include "l2cap.h" #include "btstack_stdin.h" - + +#ifdef ENABLE_GATT_OVER_CLASSIC +#include "classic/gatt_sdp.h" +#include "classic/sdp_util.h" +static uint8_t gatt_service_buffer[70]; +#endif + #define HEARTBEAT_PERIOD_MS 1000 // test profile -#include "ble_peripheral_test.h" +#include "gatt_server_test.h" ///------ static int gap_advertisements = 0; @@ -104,8 +112,13 @@ static uint8_t counter = 0; static int update_client = 0; static int client_configuration = 0; static uint16_t client_configuration_handle; +static hci_con_handle_t handle = HCI_CON_HANDLE_INVALID; -static uint16_t handle = 0; +static bool dynamic_db; +static uint8_t gatt_database_hash[16]; +static btstack_crypto_aes128_cmac_t gatt_aes_cmac_context; + +static btstack_packet_callback_registration_t sm_event_callback_registration; static void app_run(void); static void show_usage(void); @@ -189,12 +202,15 @@ static advertisement_t advertisements[] = { static int advertisement_index = 2; +// signed write +static uint8_t signed_write_characteristic_value; + // att write queue engine -static const char default_value_long[] = "abcdefghijklmnopqrstuvwxyz"; +static const char default_value_long[] = "0123456789abcdef0123456789abcdef0123456789abcdef!!"; static const char default_value_short[] = "a"; -#define ATT_VALUE_MAX_LEN 26 +#define ATT_VALUE_MAX_LEN 50 typedef struct { uint16_t handle; @@ -232,13 +248,6 @@ static int att_write_queue_for_handle(uint16_t aHandle){ return -1; } -static void att_attributes_init(void){ - int i; - for (i=0;i= 0); + printf("Setup Attribute %04x, len %u, value: %s\n", attribute_handle, len, value); + btstack_assert(len <= ATT_VALUE_MAX_LEN); + att_attributes[index].handle = attribute_handle; + att_attributes[index].len = len; + memcpy(att_attributes[index].value, value, len); +} + +static void att_attributes_init(void){ + int i; + for (i=0;i att_attributes[attributes_index].len) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; att_attributes[attributes_index].len = buffer_size; memcpy(att_attributes[attributes_index].value, buffer, buffer_size); + // commit changes + att_write_update_attribute(con_handle, attribute_handle, buffer, buffer_size); break; case ATT_TRANSACTION_MODE_ACTIVE: writes_index = att_write_queue_for_handle(attribute_handle); if (writes_index < 0) return ATT_ERROR_PREPARE_QUEUE_FULL; if (offset > att_write_queues[writes_index].len) return ATT_ERROR_INVALID_OFFSET; if (buffer_size + offset > ATT_VALUE_MAX_LEN) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; + // check offset for known attributes + switch (attribute_handle){ + case ATT_CHARACTERISTIC_GAP_APPEARANCE_01_VALUE_HANDLE: + if (offset > 1) return ATT_ERROR_INVALID_OFFSET; + if (offset + buffer_size > 2) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; + break; + default: + break; + } att_write_queues[writes_index].len = buffer_size + offset; memcpy(&(att_write_queues[writes_index].value[offset]), buffer, buffer_size); break; @@ -456,6 +549,8 @@ static int att_write_callback(hci_con_handle_t con_handle, uint16_t attribute_ha } att_attributes[attributes_index].len = att_write_queues[writes_index].len; memcpy(att_attributes[attributes_index].value, att_write_queues[writes_index].value, att_write_queues[writes_index].len); + // commit changes + att_write_update_attribute(con_handle, attribute_handle, buffer, buffer_size); } att_write_queue_init(); break; @@ -491,6 +586,7 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t * break; case HCI_EVENT_DISCONNECTION_COMPLETE: + handle = HCI_CON_HANDLE_INVALID; att_attributes_init(); att_write_queue_init(); break; @@ -575,6 +671,8 @@ void show_usage(void){ printf("o/O - OOB data off/on ('%s')\n", sm_oob_data); printf("m/M - MITM protection off\n"); printf("k/k - encryption key range [7..16]/[16..16]\n"); + printf("n - setup dynamic test db\n"); + printf("N - add Characteristic to test db\n"); printf("---\n"); printf("Ctrl-c - exit\n"); printf("---\n"); @@ -635,6 +733,11 @@ static void update_auth_req(void){ sm_set_authentication_requirements(auth_req); } +static void gatt_hash_calculated(void * arg){ + printf("GATT Hash calculated: "); + printf_hexdump(gatt_database_hash, 16); +} + static void stdin_process(char c){ // passkey input @@ -847,12 +950,25 @@ static void stdin_process(char c){ 1000 // max ce length ); break; + case 'n': + printf("Switch to dynamic database\n"); + dynamic_db = true; + att_set_db(att_db_util_get_address()); + att_db_util_add_service_uuid16(ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE); + att_db_util_add_characteristic_uuid16(0x2b2a, ATT_PROPERTY_READ | ATT_PROPERTY_DYNAMIC, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0); + att_db_util_hash_calc(&gatt_aes_cmac_context, gatt_database_hash, &gatt_hash_calculated, NULL); + break; + case 'N': + printf("Adding Characteristic to dynamic database\n"); + att_db_util_add_service_uuid16(0xfff0); + att_db_util_add_characteristic_uuid16(0xfff1, ATT_PROPERTY_READ | ATT_PROPERTY_DYNAMIC, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0); + att_db_util_hash_calc(&gatt_aes_cmac_context, gatt_database_hash, &gatt_hash_calculated, NULL); + break; default: show_usage(); break; } - return; } static int get_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data){ @@ -879,7 +995,19 @@ int btstack_main(int argc, const char * argv[]){ // setup SM: Display only sm_init(); sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); - sm_set_authentication_requirements( SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION); + sm_set_authentication_requirements( SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION); + + // register for SM events + sm_event_callback_registration.callback = &app_packet_handler; + sm_add_event_handler(&sm_event_callback_registration); + +#ifdef ENABLE_GATT_OVER_CLASSIC + // configure Classic GAP + gap_set_local_name("GATT Counter BR/EDR 00:00:00:00:00:00"); + gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); + gap_set_security_level(LEVEL_0); + gap_discoverable_control(1); +#endif // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); @@ -887,7 +1015,17 @@ int btstack_main(int argc, const char * argv[]){ att_attributes_init(); att_server_register_packet_handler(app_packet_handler); - att_dump_attributes(); + // prepare for dynamic db construction + att_db_util_init(); + +#ifdef ENABLE_GATT_OVER_CLASSIC + // init SDP, create record for GATT and register with SDP + sdp_init(); + memset(gatt_service_buffer, 0, sizeof(gatt_service_buffer)); + gatt_create_sdp_record(gatt_service_buffer, 0x10001, ATT_SERVICE_GATT_SERVICE_START_HANDLE, ATT_SERVICE_GATT_SERVICE_END_HANDLE); + sdp_register_service(gatt_service_buffer); + printf("SDP service record size: %u\n", de_get_len(gatt_service_buffer)); +#endif btstack_stdin_setup(stdin_process); @@ -906,6 +1044,13 @@ int btstack_main(int argc, const char * argv[]){ btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); btstack_run_loop_add_timer(&heartbeat); + // report gatt service handle range for SDP tests + uint16_t start_handle = 0; + uint16_t end_handle = 0xffff; + int service_found = gatt_server_get_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE, &start_handle, &end_handle); + btstack_assert(service_found != 0); + printf("GATT Service range: 0x%04x - 0x%04x\n", start_handle, end_handle); + // turn on! hci_power_control(HCI_POWER_ON); diff --git a/test/pts/gatt_server_test.gatt b/test/pts/gatt_server_test.gatt new file mode 100644 index 000000000..3eeffe683 --- /dev/null +++ b/test/pts/gatt_server_test.gatt @@ -0,0 +1,70 @@ +PRIMARY_SERVICE, GAP_SERVICE +CHARACTERISTIC, GAP_DEVICE_NAME, READ | WRITE | DYNAMIC +CHARACTERISTIC, GAP_PERIPHERAL_PRIVACY_FLAG, READ | WRITE | DYNAMIC +CHARACTERISTIC, GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS, READ, FF FF FF 00 03 FF FF +CHARACTERISTIC, GAP_APPEARANCE, READ | WRITE | DYNAMIC +CHARACTERISTIC, GAP_RECONNECTION_ADDRESS, READ | WRITE | DYNAMIC + +PRIMARY_SERVICE, GATT_SERVICE +CHARACTERISTIC, GATT_DATABASE_HASH, READ, + +PRIMARY_SERVICE, FFF0 + +// GATT/SR/GAC/BV-01-C expects characteristic value of MTU-1 +CHARACTERISTIC, FFF1, READ | NOTIFY | INDICATE | DYNAMIC + +// GATT/SR/GAR/BI-01-C, GATT/SR/GAR/BI-06-C expects Characteristic where Read is not permitted +CHARACTERISTIC, FFF2, DYNAMIC + +// GATT/SR/GAR/BI-03-C, GATT/SR/GAR/BI-09-C expects Insufficient Authorization +CHARACTERISTIC, FFF3, READ | AUTHORIZATION_REQUIRED, "A" + +// GATT/SR/GAR/BI-04-C, GATT/SR/GAR/BI-10-C expects Insufficient Authentication +CHARACTERISTIC, FFF4, READ | AUTHENTICATION_REQUIRED, "A" + +// GATT/SR/GAR/BI-05-C, GATT/SR/GAR/BI-11-C expects Insufficient Encryption Key Size +CHARACTERISTIC, FFF5, READ | ENCRYPTION_KEY_SIZE_16, "A" + +// GATT/SR/GAR/BV-04-C - Read Long Characteristic +CHARACTERISTIC, FFF6, READ, "GGGGGGGGG00000000001111111111222222222223333333333" + +// GATT/SR/GAR/BV-07-C, GATT/SR/GAW/BV-09-C - Read/Write Long Characteristic Descriptor +CHARACTERISTIC, FFF7, READ, "A" +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC, + +// GATT/SR/GAR/BI-34-C - Read Characteristic Value only permitted via BR/EDR +CHARACTERISTIC, FFF8, READ | DYNAMIC + +// GATT/SR/GAR/BI-34-C - Read Characteristic Value only permitted via LE +CHARACTERISTIC, FFF9, READ | DYNAMIC + +// GATT/SR/GAW/BV-01-C expects a READ + Write Without Response +CHARACTERISTIC, FFFA, READ | WRITE_WITHOUT_RESPONSE | DYNAMIC + +// GATT/SR/GAW/BV-02-C expects a READ + Signed Write +CHARACTERISTIC, FFFB, READ | AUTHENTICATED_SIGNED_WRITE | DYNAMIC + +// GATT/SR/GAW/BI-04-C expects Insufficient Authorization +CHARACTERISTIC, FFFC, READ | WRITE | AUTHORIZATION_REQUIRED | DYNAMIC + +// GATT/SR/GAW/BI-05-C expects Insufficient Authentication +CHARACTERISTIC, FFFD, READ | WRITE | AUTHENTICATION_REQUIRED | DYNAMIC + +// GATT/SR/GAW/BI-06-C expects Insufficient Encryption Key Size +CHARACTERISTIC, FFFE, READ | WRITE | ENCRYPTION_KEY_SIZE_16 | DYNAMIC + +// GATT/SR/GAW/BV-05-C - Write Long Characteristic Value +CHARACTERISTIC, FFFF, READ | WRITE | DYNAMIC +CHARACTERISTIC, FEFF, READ | WRITE | DYNAMIC + +// GATT/SR/GPA/BV-11-C, GATT/SR/GPA/BV-12-C expects Characteristic Aggregate +CHARACTERISTIC, FEFE, READ | WRITE | DYNAMIC +CHARACTERISTIC_FORMAT, FORMAT-1, 01, 00, 0000, 00, 0000 +CHARACTERISTIC_FORMAT, FORMAT-2, 02, 00, 0000, 00, 0000 +CHARACTERISTIC_FORMAT, FORMAT-3, 03, 00, 0000, 00, 0000 +CHARACTERISTIC_FORMAT, FORMAT-4, 03, 00, 0000, 00, 0000 +CHARACTERISTIC_AGGREGATE_FORMAT, FORMAT-1, FORMAT-2 +CHARACTERISTIC_AGGREGATE_FORMAT, FORMAT-2, FORMAT-3 +CHARACTERISTIC_AGGREGATE_FORMAT, FORMAT-3, FORMAT-4 +CHARACTERISTIC_AGGREGATE_FORMAT, FORMAT-1, FORMAT-3 +CHARACTERISTIC_AGGREGATE_FORMAT, FORMAT-2, FORMAT-4 diff --git a/test/pts/gatt_server_test.md b/test/pts/gatt_server_test.md new file mode 100644 index 000000000..6c6bbcb3c --- /dev/null +++ b/test/pts/gatt_server_test.md @@ -0,0 +1,96 @@ +# GATT Sever Test + +If GATT over BR/EDR is selected, tests will be performed for both + +## TODO: +- Check if we should return an empty read blob response when reading at offset = len (value) - instead of returning an invalid offset error + - "If the attribute value has a fixed length that is less than or equal to (ATT_MTU - 1) octets in length, then an ATT_ERROR_RSP PDU may be sent with the error code Attribute Not Long." + - On "Read Blob returned an error", clock on 'cancel test' to let it continue + +## IXIT: + +## Test cases +- GATT/SR/GAC/BV-01: A (test repeats twice with MTU 23 and 512) +- GATT/SR/GAD/BV-01-C: A (PTS asks if we as server received the response, just OK) +- GATT/SR/GAD/BV-02-C: A (PTS asks if we as server received the response, just OK) +- GATT/SR/GAD/BV-03-C: A +- GATT/SR/GAD/BV-04-C: A (PTS asks if we as server received the response, just OK) +- GATT/SR/GAD/BV-05-C: A +- GATT/SR/GAD/BV-06-C: A +- GATT/SR/GAD/BV-07-C: (ok) +- GATT/SR/GAD/BV-08-C: (ok) + +- GATT/SR/GAR/BV-01-C: (ok) +- GATT/SR/GAR/BI-01-C: (ok) +- GATT/SR/GAR/BI-02-C: "1111" (invalid handle) +- GATT/SR/GAR/BI-03-C: A (ok) +- GATT/SR/GAR/BI-04-C: A (press cancel test in pts to let it continue) +- GATT/SR/GAR/BI-05-C: A +- GATT/SR/GAR/BV-03-C: A +- GATT/SR/GAR/BI-06-C: A, "FFF2", "0013", "FFF2", "0013" +- GATT/SR/GAR/BI-07-C: A, "FFFF" +- GATT/SR/GAR/BI-08-C: A, +- GATT/SR/GAR/BI-09-C: A, "FFF3", "0013" +- GATT/SR/GAR/BI-10-C: A, "FFF4", "0017" +- GATT/SR/GAR/BI-11-C: A, "FFF5", "0019" +- GATT/SR/GAR/BV-04-C: A +- GATT/SR/GAR/BI-12-C: A, "0013", " 0013" +- GATT/SR/GAR/BI-13-C: A +- GATT/SR/GAR/BI-14-C: A, "1111", "1111" (invalid handle) +- GATT/SR/GAR/BI-15-C: A +- GATT/SR/GAR/BI-16-C: A +- GATT/SR/GAR/BI-17-C: A +- GATT/SR/GAR/BV-05-C: A +- GATT/SR/GAR/BI-18-C: A, "0013","0013" +- GATT/SR/GAR/BI-19-C: A, "1111", "1111" +- GATT/SR/GAR/BI-20-C: A +- GATT/SR/GAR/BI-21-C: A +- GATT/SR/GAR/BI-22-C: A +- GATT/SR/GAR/BV-06-C: A +- GATT/SR/GAR/BV-07-C: A +- GATT/SR/GAR/BV-08-C: A +- GATT/SR/GAR/BI-34-C: A, "0021" +- GATT/SR/GAR/BI-35-C: A, "0023" + +- GATT/SR/GAW/BV-01: A +- GATT/SR/GAW/BV-02: A, B +- GATT/SR/GAW/BI-01: A, B +- GATT/SR/GAW/BV-03: A +- GATT/SR/GAW/BI-02: A, "1111", "1111" +- GATT/SR/GAW/BI-03: A +- GATT/SR/GAW/BI-04: A +- GATT/SR/GAW/BI-05: A +- GATT/SR/GAW/BI-06: A +- GATT/SR/GAW/BV-05: A, L +- GATT/SR/GAW/BI-07: A, "1111", "1111" +- GATT/SR/GAW/BI-08: A, "0011", "0011" +- GATT/SR/GAW/BI-09: A +- GATT/SR/GAW/BI-11: A +- GATT/SR/GAW/BI-12: A +- GATT/SR/GAW/BI-13: A +- GATT/SR/GAW/BV-06: A +- GATT/SR/GAW/BV-10: A, L +- GATT/SR/GAW/BV-11: A, L +- GATT/SR/GAW/BV-07: A, L +- GATT/SR/GAW/BV-08: A, L +- GATT/SR/GAW/BV-09: A +- GATT/SR/GAW/BI-32-C: A, "0009", "0009" (ATT_CHARACTERISTIC_GAP_APPEARANCE_01_VALUE_HANDLE) +- GATT/SR/GAW/BI-33-C: A, "0009", "0009" (ATT_CHARACTERISTIC_GAP_APPEARANCE_01_VALUE_HANDLE) + +- GATT/SR/GAN/BV-01-C: A + +- GATT/SR/GAI/BV-01-C: A + +- GATT/SR/GAS/BV-02-C: n, N, A, N +- GATT/SR/GAS/BV-04-C: -- should not be needed/enabled if Client Supported Features Characteristic 4/26 is not supported +- GATT/SR/GAS/BV-05-C: -- should not be needed/enabled if Client Supported Features Characteristic 4/26 is not supported +- GATT/SR/GAS/BV-06-C: -- should not be needed/enabled if Client Supported Features Characteristic 4/26 is not supported +- GATT/SR/GAS/BV-07-C: -- should not be needed/enabled if Client Supported Features Characteristic 4/26 is not supported + +- GATT/SR/GAT/BV-01-C: A (wait 30 seconds) + +- GATT/SR/GPA/BV-11-C: A + GATT/SR/GPA/BV-12-C: A + +- GATT/SR/UNS/BI-01-C: AA +- GATT/SR/UNS/BI-02-C: A (PST waits rather long to check that no response is sent)