mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
gatt client: implemented signed write
This commit is contained in:
parent
22332a8a16
commit
f64240626f
@ -52,6 +52,7 @@
|
|||||||
#include "l2cap.h"
|
#include "l2cap.h"
|
||||||
#include "att.h"
|
#include "att.h"
|
||||||
#include "att_dispatch.h"
|
#include "att_dispatch.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
#ifdef HAVE_UART_CC2564
|
#ifdef HAVE_UART_CC2564
|
||||||
#include "bt_control_cc256x.h"
|
#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);
|
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
|
// 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){
|
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();
|
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;
|
peripheral->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
|
||||||
send_gatt_execute_write_request(peripheral);
|
send_gatt_execute_write_request(peripheral);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1010,7 +1025,40 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
|
|||||||
gatt_client_run();
|
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){
|
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;
|
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
|
||||||
|
@ -98,7 +98,9 @@ typedef enum {
|
|||||||
P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR,
|
P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR,
|
||||||
P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT,
|
P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT,
|
||||||
P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR,
|
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;
|
} gatt_client_state_t;
|
||||||
|
|
||||||
|
|
||||||
@ -145,6 +147,9 @@ typedef struct gatt_client{
|
|||||||
uint8_t filter_with_uuid;
|
uint8_t filter_with_uuid;
|
||||||
uint8_t send_confirmation;
|
uint8_t send_confirmation;
|
||||||
|
|
||||||
|
sm_key_t csrk;
|
||||||
|
uint32_t sign_counter;
|
||||||
|
uint8_t cmac[8];
|
||||||
} gatt_client_t;
|
} gatt_client_t;
|
||||||
|
|
||||||
typedef struct le_event {
|
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_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}
|
// { read/write/subscribe/unsubscribe confirm/result}
|
||||||
|
|
||||||
// { type, le_peripheral *, characteristic handle, int len, uint8_t data[]?}
|
// { type, le_peripheral *, characteristic handle, int len, uint8_t data[]?}
|
||||||
|
@ -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
|
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 $@
|
${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
|
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} ble_client.c ${CFLAGS} ${LDFLAGS} -o $@
|
${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
|
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} gatt_browser.c ${CFLAGS} ${LDFLAGS} -o $@
|
${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL_OBJ} gatt_browser.c ${CFLAGS} ${LDFLAGS} -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f spp_counter sdp_rfcomm_query sdp_general_query spp_counter_ssp ble_peripheral ble_client gatt_browser gatt_client ancs_client
|
rm -f spp_counter sdp_rfcomm_query sdp_general_query spp_counter_ssp ble_peripheral ble_client gatt_browser gatt_client ancs_client
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "CppUTest/TestHarness.h"
|
#include "CppUTest/TestHarness.h"
|
||||||
#include "CppUTest/CommandLineTestRunner.h"
|
#include "CppUTest/CommandLineTestRunner.h"
|
||||||
|
#include "CppUTestExt/MockSupport.h"
|
||||||
|
|
||||||
#include <btstack/hci_cmds.h>
|
#include <btstack/hci_cmds.h>
|
||||||
|
|
||||||
@ -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){
|
switch(event->type){
|
||||||
case GAP_LE_ADVERTISING_REPORT:
|
case GAP_LE_ADVERTISING_REPORT:
|
||||||
advertisement_received = 1;
|
advertisement_received = 1;
|
||||||
@ -76,20 +77,45 @@ TEST_GROUP(LECentral){
|
|||||||
advertisement_received = 0;
|
advertisement_received = 0;
|
||||||
connected = 0;
|
connected = 0;
|
||||||
|
|
||||||
ble_client_init();
|
|
||||||
ble_client_register_packet_handler(handle_ble_client_event);
|
// mock().expectOneCall("productionCode").andReturnValue(10);
|
||||||
mock_simulate_hci_state_working();
|
|
||||||
connect();
|
// 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);
|
// TEST(LECentral, TestScanning){
|
||||||
mock_simulate_scan_response();
|
// le_central_start_scan();
|
||||||
CHECK(advertisement_received);
|
// 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[]){
|
int main (int argc, const char * argv[]){
|
||||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -45,18 +45,10 @@ static void att_init_connection(att_connection_t * att_connection){
|
|||||||
att_connection->authorized = 0;
|
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){
|
int l2cap_can_send_connectionless_packet_now(void){
|
||||||
return 1;
|
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){
|
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;
|
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){
|
// int hci_can_send_packet_now_using_packet_buffer(uint8_t packet_type){
|
||||||
printf("hci_disconnect_security_block \n");
|
// return 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void hci_dump_log(const char * format, ...){
|
// void hci_disconnect_security_block(hci_con_handle_t con_handle){
|
||||||
printf("hci_disconnect_security_block \n");
|
// printf("hci_disconnect_security_block \n");
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// void hci_dump_log(const char * format, ...){
|
||||||
|
// printf("hci_disconnect_security_block \n");
|
||||||
|
// }
|
||||||
|
|
||||||
void l2cap_run(void){
|
void l2cap_run(void){
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user