From f64240626f876d0d26743bd7cf86aea807821076 Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Thu, 19 Jun 2014 22:20:43 +0000 Subject: [PATCH] gatt client: implemented signed write --- ble/gatt_client.c | 48 +++++++++++++++++++++++++++++++++++ ble/gatt_client.h | 8 +++++- example/libusb/Makefile | 8 +++--- test/gatt_client/le_central.c | 46 +++++++++++++++++++++++++-------- test/gatt_client/mock.c | 28 ++++++++++---------- 5 files changed, 109 insertions(+), 29 deletions(-) diff --git a/ble/gatt_client.c b/ble/gatt_client.c index df7b6c1d7..7c8cf082b 100644 --- a/ble/gatt_client.c +++ b/ble/gatt_client.c @@ -52,6 +52,7 @@ #include "l2cap.h" #include "att.h" #include "att_dispatch.h" +#include "sm.h" #ifdef HAVE_UART_CC2564 #include "bt_control_cc256x.h" @@ -173,6 +174,19 @@ static void att_read_blob_request(uint16_t request_type, uint16_t peripheral_han l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5); } +// precondition: can_send_packet_now == TRUE +static void att_signed_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value, uint32_t sign_counter, uint8_t sgn[8]){ + l2cap_reserve_packet_buffer(); + uint8_t * request = l2cap_get_outgoing_buffer(); + request[0] = request_type; + bt_store_16(request, 1, attribute_handle); + memcpy(&request[3], value, value_length); + bt_store_32(request, 3 + value_length, sign_counter); + memcpy(&request[3+value_length+4], sgn, 8); + + l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3 + value_length + 12); +} + // precondition: can_send_packet_now == TRUE static void att_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value){ l2cap_reserve_packet_buffer(); @@ -718,6 +732,7 @@ static void gatt_client_run(){ peripheral->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT; send_gatt_execute_write_request(peripheral); break; + default: break; } @@ -1010,7 +1025,40 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, gatt_client_run(); } +static void att_signed_write_handle_cmac_result(uint8_t hash[8]){ + linked_list_iterator_t it; + linked_list_iterator_init(&it, &gatt_client_connections); + while (linked_list_iterator_has_next(&it)){ + gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it); + if (peripheral->gatt_client_state == P_W4_CMAC){ + peripheral->gatt_client_state = P_READY; + memcpy(peripheral->cmac, hash, 8); + att_signed_write_request(ATT_SIGNED_WRITE_COMMAND, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, peripheral->sign_counter, peripheral->cmac); + return; + } + } +} + + +le_command_status_t gatt_client_signed_write(gatt_client_t * peripheral, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sign_counter){ + if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; + if (!sm_cmac_ready()) { + printf("ATT Signed Write, sm_cmac engine not ready. Abort\n"); + return BLE_PERIPHERAL_IN_WRONG_STATE; + } + + peripheral->attribute_handle = handle; + peripheral->attribute_length = message_len; + peripheral->attribute_value = message; + peripheral->gatt_client_state = P_W4_CMAC; + peripheral->sign_counter = sign_counter; + memcpy(peripheral->csrk, csrk, 16); + + sm_cmac_start(peripheral->csrk, peripheral->attribute_length, peripheral->attribute_value, att_signed_write_handle_cmac_result); + gatt_client_run(); + return BLE_PERIPHERAL_OK; +} le_command_status_t gatt_client_discover_primary_services(gatt_client_t *peripheral){ if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; diff --git a/ble/gatt_client.h b/ble/gatt_client.h index fd2499b08..2382472e4 100644 --- a/ble/gatt_client.h +++ b/ble/gatt_client.h @@ -98,7 +98,9 @@ typedef enum { P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR, P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT, P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR, - P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT + P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT, + + P_W4_CMAC } gatt_client_state_t; @@ -145,6 +147,9 @@ typedef struct gatt_client{ uint8_t filter_with_uuid; uint8_t send_confirmation; + sm_key_t csrk; + uint32_t sign_counter; + uint8_t cmac[8]; } gatt_client_t; typedef struct le_event { @@ -282,6 +287,7 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor(gatt_client le_command_status_t gatt_client_write_client_characteristic_configuration(gatt_client_t *context, le_characteristic_t * characteristic, uint16_t configuration); +le_command_status_t gatt_client_signed_write(gatt_client_t * context, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sgn_counter); // { read/write/subscribe/unsubscribe confirm/result} // { type, le_peripheral *, characteristic handle, int len, uint8_t data[]?} diff --git a/example/libusb/Makefile b/example/libusb/Makefile index 777d4cc4e..fb7e772ad 100644 --- a/example/libusb/Makefile +++ b/example/libusb/Makefile @@ -130,11 +130,11 @@ ble_peripheral_uart: ${CORE_OBJ} ${COMMON_OBJ} ${CSR_OBJ} ${ATT_OBJ} ${SM_REAL_O ble_peripheral_sm_minimal: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_MINIMAL_OBJ} ble_peripheral.c profile.h ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_MINIMAL_OBJ} ble_peripheral.c ${CFLAGS} ${LDFLAGS} -o $@ -ble_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ble_client.c - ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ble_client.c ${CFLAGS} ${LDFLAGS} -o $@ +ble_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL} ble_client.c + ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL} ble_client.c ${CFLAGS} ${LDFLAGS} -o $@ -gatt_browser: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} gatt_browser.c - ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} gatt_browser.c ${CFLAGS} ${LDFLAGS} -o $@ +gatt_browser: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} gatt_browser.c + ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} gatt_browser.c ${CFLAGS} ${LDFLAGS} -o $@ clean: rm -f spp_counter sdp_rfcomm_query sdp_general_query spp_counter_ssp ble_peripheral ble_client gatt_browser gatt_client ancs_client diff --git a/test/gatt_client/le_central.c b/test/gatt_client/le_central.c index c36a31951..02387d92d 100644 --- a/test/gatt_client/le_central.c +++ b/test/gatt_client/le_central.c @@ -13,6 +13,7 @@ #include "CppUTest/TestHarness.h" #include "CppUTest/CommandLineTestRunner.h" +#include "CppUTestExt/MockSupport.h" #include @@ -48,7 +49,7 @@ static void verify_advertisement(ad_event_t * e){ } -static void handle_ble_client_event(le_event_t * event){ +static void handle_le_client_event(le_event_t * event){ switch(event->type){ case GAP_LE_ADVERTISING_REPORT: advertisement_received = 1; @@ -76,20 +77,45 @@ TEST_GROUP(LECentral){ advertisement_received = 0; connected = 0; - ble_client_init(); - ble_client_register_packet_handler(handle_ble_client_event); - mock_simulate_hci_state_working(); - connect(); + + // mock().expectOneCall("productionCode").andReturnValue(10); + + // ble_client_init(); + // le_central_register_handler(handle_le_client_event); + // le_central_register_connection_handler(handle_le_client_event); + + // mock().expectOneCall("hci_can_send_packet_now_using_packet_buffer").andReturnValue(1); + // mock_simulate_hci_state_working(); + // connect(); } + + void teardown(){ + mock().clear(); + } }; -TEST(LECentral, TestScanning){ - le_central_start_scan(); - mock_simulate_command_complete(&hci_le_set_scan_enable); - mock_simulate_scan_response(); - CHECK(advertisement_received); + + +// TEST(LECentral, TestScanning){ +// le_central_start_scan(); +// mock_simulate_command_complete(&hci_le_set_scan_enable); +// mock_simulate_scan_response(); +// CHECK(advertisement_received); +// } + +int productionCode(){ + printf("productionCode 20\n"); + mock().actualCall("productionCode"); + return 20; } +TEST(LECentral, SimpleScenario){ + mock().expectOneCall("productionCode").andReturnValue(10); + printf("productionCode %d\n", productionCode()); + mock().checkExpectations(); +} + + int main (int argc, const char * argv[]){ return CommandLineTestRunner::RunAllTests(argc, argv); } diff --git a/test/gatt_client/mock.c b/test/gatt_client/mock.c index 1ed6456fe..ee5b62c15 100644 --- a/test/gatt_client/mock.c +++ b/test/gatt_client/mock.c @@ -45,18 +45,10 @@ static void att_init_connection(att_connection_t * att_connection){ att_connection->authorized = 0; } -int hci_can_send_packet_now_using_packet_buffer(uint8_t packet_type){ - return 1; -} - int l2cap_can_send_connectionless_packet_now(void){ return 1; } -int hci_send_cmd(const hci_cmd_t *cmd, ...){ -// printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode); - return 0; -} uint8_t *l2cap_get_outgoing_buffer(void){ @@ -98,14 +90,22 @@ int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t l return 0; } +// int hci_send_cmd(const hci_cmd_t *cmd, ...){ +// // printf("hci_send_cmd opcode 0x%02x\n", cmd->opcode); +// return 0; +// } -void hci_disconnect_security_block(hci_con_handle_t con_handle){ - printf("hci_disconnect_security_block \n"); -} +// int hci_can_send_packet_now_using_packet_buffer(uint8_t packet_type){ +// return 1; +// } -void hci_dump_log(const char * format, ...){ - printf("hci_disconnect_security_block \n"); -} +// void hci_disconnect_security_block(hci_con_handle_t con_handle){ +// printf("hci_disconnect_security_block \n"); +// } + +// void hci_dump_log(const char * format, ...){ +// printf("hci_disconnect_security_block \n"); +// } void l2cap_run(void){ }