mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-25 06:40:10 +00:00
Merge branch 'master' of https://github.com/bluekitchen/btstack
This commit is contained in:
commit
588953c14f
@ -104,7 +104,8 @@ extern "C" {
|
|||||||
#define ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0f
|
#define ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0f
|
||||||
#define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
|
#define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
|
||||||
#define ATT_ERROR_INSUFFICIENT_RESOURCES 0x11
|
#define ATT_ERROR_INSUFFICIENT_RESOURCES 0x11
|
||||||
#define ATT_ERROR_TIMEOUT 0x12
|
// custom BTstack ATT error coders
|
||||||
|
#define ATT_ERROR_TIMEOUT 0x7F
|
||||||
|
|
||||||
|
|
||||||
// custom BTstack error codes
|
// custom BTstack error codes
|
||||||
@ -143,7 +144,12 @@ extern "C" {
|
|||||||
#define GATT_SECONDARY_SERVICE_UUID 0x2801
|
#define GATT_SECONDARY_SERVICE_UUID 0x2801
|
||||||
#define GATT_INCLUDE_SERVICE_UUID 0x2802
|
#define GATT_INCLUDE_SERVICE_UUID 0x2802
|
||||||
#define GATT_CHARACTERISTICS_UUID 0x2803
|
#define GATT_CHARACTERISTICS_UUID 0x2803
|
||||||
|
#define GATT_CHARACTERISTIC_EXTENDED_PROPERTIES 0x2900
|
||||||
|
#define GATT_CHARACTERISTIC_USER_DESCRIPTION 0x2901
|
||||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION 0x2902
|
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION 0x2902
|
||||||
|
#define GATT_SERVER_CHARACTERISTICS_CONFIGURATION 0x2903
|
||||||
|
#define GATT_CHARACTERISTIC_PRESENTATION_FORMAT 0x2904
|
||||||
|
#define GATT_CHARACTERISTIC_AGGREGATE_FORMAT 0x2905
|
||||||
|
|
||||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE 0
|
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE 0
|
||||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION 1
|
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION 1
|
||||||
|
@ -267,7 +267,7 @@ static void att_run(void){
|
|||||||
|
|
||||||
// signature is { sequence counter, secure hash }
|
// signature is { sequence counter, secure hash }
|
||||||
sm_key_t csrk;
|
sm_key_t csrk;
|
||||||
le_device_db_csrk_get(att_ir_le_device_db_index, csrk);
|
le_device_db_remote_csrk_get(att_ir_le_device_db_index, csrk);
|
||||||
att_server_state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION;
|
att_server_state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION;
|
||||||
log_info("Orig Signature: ");
|
log_info("Orig Signature: ");
|
||||||
hexdump( &att_request_buffer[att_request_size-8], 8);
|
hexdump( &att_request_buffer[att_request_size-8], 8);
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
static linked_list_t gatt_client_connections = NULL;
|
static linked_list_t gatt_client_connections = NULL;
|
||||||
static linked_list_t gatt_subclients = NULL;
|
static linked_list_t gatt_subclients = NULL;
|
||||||
static uint16_t gatt_client_id = 0;
|
static uint16_t gatt_client_id = 0;
|
||||||
|
static uint8_t pts_suppress_mtu_exchange;
|
||||||
|
|
||||||
static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size);
|
static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size);
|
||||||
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code);
|
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code);
|
||||||
@ -128,6 +129,7 @@ void gatt_client_unregister_packet_handler(uint16_t gatt_client_id){
|
|||||||
|
|
||||||
void gatt_client_init(void){
|
void gatt_client_init(void){
|
||||||
gatt_client_connections = NULL;
|
gatt_client_connections = NULL;
|
||||||
|
pts_suppress_mtu_exchange = 0;
|
||||||
att_dispatch_register_client(gatt_client_att_packet_handler);
|
att_dispatch_register_client(gatt_client_att_packet_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,11 +186,17 @@ static gatt_client_t * provide_context_for_conn_handle(uint16_t con_handle){
|
|||||||
context = btstack_memory_gatt_client_get();
|
context = btstack_memory_gatt_client_get();
|
||||||
if (!context) return NULL;
|
if (!context) return NULL;
|
||||||
// init state
|
// init state
|
||||||
|
memset(context, 0, sizeof(gatt_client_t));
|
||||||
context->handle = con_handle;
|
context->handle = con_handle;
|
||||||
context->mtu = ATT_DEFAULT_MTU;
|
context->mtu = ATT_DEFAULT_MTU;
|
||||||
context->mtu_state = SEND_MTU_EXCHANGE;
|
context->mtu_state = SEND_MTU_EXCHANGE;
|
||||||
context->gatt_client_state = P_READY;
|
context->gatt_client_state = P_READY;
|
||||||
linked_list_add(&gatt_client_connections, (linked_item_t*)context);
|
linked_list_add(&gatt_client_connections, (linked_item_t*)context);
|
||||||
|
|
||||||
|
// skip mtu exchange for testing sm with pts
|
||||||
|
if (pts_suppress_mtu_exchange){
|
||||||
|
context->mtu_state = MTU_EXCHANGED;
|
||||||
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,6 +497,15 @@ static void emit_event(uint16_t gatt_client_id, le_event_t* event){
|
|||||||
(*gatt_client_callback)(event);
|
(*gatt_client_callback)(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void emit_event_to_all_subclients(le_event_t * event){
|
||||||
|
linked_list_iterator_t it;
|
||||||
|
linked_list_iterator_init(&it, &gatt_subclients);
|
||||||
|
while (linked_list_iterator_has_next(&it)){
|
||||||
|
gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
|
||||||
|
(*subclient->callback)(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
|
static void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
|
||||||
gatt_complete_event_t event;
|
gatt_complete_event_t event;
|
||||||
event.type = GATT_QUERY_COMPLETE;
|
event.type = GATT_QUERY_COMPLETE;
|
||||||
@ -604,14 +621,18 @@ static void report_gatt_included_service(gatt_client_t * peripheral, uint8_t *uu
|
|||||||
emit_event(peripheral->subclient_id, (le_event_t*)&event);
|
emit_event(peripheral->subclient_id, (le_event_t*)&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setup_characteristic_value_event(le_characteristic_value_event_t * event, uint16_t handle, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){
|
||||||
|
event->type = event_type;
|
||||||
|
event->handle = handle;
|
||||||
|
event->value_handle = value_handle;
|
||||||
|
event->value_offset = offset;
|
||||||
|
event->blob_length = length;
|
||||||
|
event->blob = value;
|
||||||
|
}
|
||||||
|
|
||||||
static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){
|
static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){
|
||||||
le_characteristic_value_event_t event;
|
le_characteristic_value_event_t event;
|
||||||
event.type = event_type;
|
setup_characteristic_value_event(&event, peripheral->handle, value_handle, value, length, offset, event_type);
|
||||||
event.handle = peripheral->handle;
|
|
||||||
event.value_handle = value_handle;
|
|
||||||
event.value_offset = offset;
|
|
||||||
event.blob_length = length;
|
|
||||||
event.blob = value;
|
|
||||||
emit_event(peripheral->subclient_id, (le_event_t*)&event);
|
emit_event(peripheral->subclient_id, (le_event_t*)&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,12 +640,16 @@ static void report_gatt_long_characteristic_value_blob(gatt_client_t * periphera
|
|||||||
send_characteristic_value_event(peripheral, peripheral->attribute_handle, value, blob_length, value_offset, GATT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT);
|
send_characteristic_value_event(peripheral, peripheral->attribute_handle, value, blob_length, value_offset, GATT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_gatt_notification(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){
|
static void report_gatt_notification(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
|
||||||
send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_NOTIFICATION);
|
le_characteristic_value_event_t event;
|
||||||
|
setup_characteristic_value_event(&event, con_handle, value_handle, value, length, 0, GATT_NOTIFICATION);
|
||||||
|
emit_event_to_all_subclients((le_event_t*)&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_gatt_indication(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){
|
static void report_gatt_indication(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
|
||||||
send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_INDICATION);
|
le_characteristic_value_event_t event;
|
||||||
|
setup_characteristic_value_event(&event, con_handle, value_handle, value, length, 0, GATT_INDICATION);
|
||||||
|
emit_event_to_all_subclients((le_event_t*)&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_gatt_characteristic_value(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){
|
static void report_gatt_characteristic_value(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){
|
||||||
@ -672,17 +697,20 @@ static void report_gatt_all_characteristic_descriptors(gatt_client_t * periphera
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_handle, gatt_client_state_t next_query_state){
|
static int is_query_done(gatt_client_t * peripheral, uint16_t last_result_handle){
|
||||||
if (last_result_handle < peripheral->end_group_handle){
|
return last_result_handle >= peripheral->end_group_handle;
|
||||||
peripheral->start_group_handle = last_result_handle + 1;
|
|
||||||
peripheral->gatt_client_state = next_query_state;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// DONE
|
|
||||||
gatt_client_handle_transaction_complete(peripheral);
|
|
||||||
emit_gatt_complete_event(peripheral, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_handle, gatt_client_state_t next_query_state){
|
||||||
|
if (is_query_done(peripheral, last_result_handle)){
|
||||||
|
gatt_client_handle_transaction_complete(peripheral);
|
||||||
|
emit_gatt_complete_event(peripheral, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// next
|
||||||
|
peripheral->start_group_handle = last_result_handle + 1;
|
||||||
|
peripheral->gatt_client_state = next_query_state;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void trigger_next_included_service_query(gatt_client_t * peripheral, uint16_t last_result_handle){
|
static inline void trigger_next_included_service_query(gatt_client_t * peripheral, uint16_t last_result_handle){
|
||||||
trigger_next_query(peripheral, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY);
|
trigger_next_query(peripheral, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY);
|
||||||
@ -697,6 +725,10 @@ static inline void trigger_next_service_by_uuid_query(gatt_client_t * peripheral
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void trigger_next_characteristic_query(gatt_client_t * peripheral, uint16_t last_result_handle){
|
static inline void trigger_next_characteristic_query(gatt_client_t * peripheral, uint16_t last_result_handle){
|
||||||
|
if (is_query_done(peripheral, last_result_handle)){
|
||||||
|
// report last characteristic
|
||||||
|
characteristic_end_found(peripheral, peripheral->end_group_handle);
|
||||||
|
}
|
||||||
trigger_next_query(peripheral, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY);
|
trigger_next_query(peripheral, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,7 +937,7 @@ static void gatt_client_run(void){
|
|||||||
case P_W4_CMAC_READY:
|
case P_W4_CMAC_READY:
|
||||||
if (sm_cmac_ready()){
|
if (sm_cmac_ready()){
|
||||||
sm_key_t csrk;
|
sm_key_t csrk;
|
||||||
le_device_db_csrk_get(peripheral->le_device_index, csrk);
|
le_device_db_local_csrk_get(peripheral->le_device_index, csrk);
|
||||||
uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index);
|
uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index);
|
||||||
peripheral->gatt_client_state = P_W4_CMAC_RESULT;
|
peripheral->gatt_client_state = P_W4_CMAC_RESULT;
|
||||||
sm_cmac_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
|
sm_cmac_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
|
||||||
@ -932,15 +964,6 @@ static void gatt_client_run(void){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_event_to_all_subclients(le_event_t * event){
|
|
||||||
linked_list_iterator_t it;
|
|
||||||
linked_list_iterator_init(&it, &gatt_subclients);
|
|
||||||
while (linked_list_iterator_has_next(&it)){
|
|
||||||
gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
|
|
||||||
(*subclient->callback)(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) {
|
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) {
|
||||||
if (is_ready(peripheral)) return;
|
if (is_ready(peripheral)) return;
|
||||||
gatt_client_handle_transaction_complete(peripheral);
|
gatt_client_handle_transaction_complete(peripheral);
|
||||||
@ -982,7 +1005,20 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
|
|||||||
|
|
||||||
if (packet_type != ATT_DATA_PACKET) return;
|
if (packet_type != ATT_DATA_PACKET) return;
|
||||||
|
|
||||||
gatt_client_t * peripheral = get_gatt_client_context_for_handle(handle);
|
// special cases: notifications don't need a context while indications motivate creating one
|
||||||
|
gatt_client_t * peripheral;
|
||||||
|
switch (packet[0]){
|
||||||
|
case ATT_HANDLE_VALUE_NOTIFICATION:
|
||||||
|
report_gatt_notification(handle, READ_BT_16(packet,1), &packet[3], size-3);
|
||||||
|
return;
|
||||||
|
case ATT_HANDLE_VALUE_INDICATION:
|
||||||
|
peripheral = provide_context_for_conn_handle(handle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
peripheral = get_gatt_client_context_for_handle(handle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!peripheral) return;
|
if (!peripheral) return;
|
||||||
|
|
||||||
switch (packet[0]){
|
switch (packet[0]){
|
||||||
@ -1006,12 +1042,8 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ATT_HANDLE_VALUE_NOTIFICATION:
|
|
||||||
report_gatt_notification(peripheral, READ_BT_16(packet,1), &packet[3], size-3);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ATT_HANDLE_VALUE_INDICATION:
|
case ATT_HANDLE_VALUE_INDICATION:
|
||||||
report_gatt_indication(peripheral, READ_BT_16(packet,1), &packet[3], size-3);
|
report_gatt_indication(handle, READ_BT_16(packet,1), &packet[3], size-3);
|
||||||
peripheral->send_confirmation = 1;
|
peripheral->send_confirmation = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1020,12 +1052,12 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
|
|||||||
case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
|
case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
|
||||||
report_gatt_characteristics(peripheral, packet, size);
|
report_gatt_characteristics(peripheral, packet, size);
|
||||||
trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
|
trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
|
||||||
// GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
|
// GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
|
||||||
break;
|
break;
|
||||||
case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
|
case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
|
||||||
report_gatt_characteristics(peripheral, packet, size);
|
report_gatt_characteristics(peripheral, packet, size);
|
||||||
trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
|
trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
|
||||||
// GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
|
// GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
|
||||||
break;
|
break;
|
||||||
case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
|
case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
|
||||||
{
|
{
|
||||||
@ -1724,4 +1756,7 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t ga
|
|||||||
return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle, length, value);
|
return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle, length, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gatt_client_pts_suppress_mtu_exchange(void){
|
||||||
|
pts_suppress_mtu_exchange = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -379,6 +379,9 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descr
|
|||||||
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);
|
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);
|
||||||
/* API_END */
|
/* API_END */
|
||||||
|
|
||||||
|
// only used for testing
|
||||||
|
void gatt_client_pts_suppress_mtu_exchange();
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -115,18 +115,32 @@ void le_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_k
|
|||||||
void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk, int * key_size, int * authenticated, int * authorized);
|
void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk, int * key_size, int * authenticated, int * authorized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief set signing key for this device
|
* @brief set local signing key for this device
|
||||||
* @param index
|
* @param index
|
||||||
* @param signing key as input
|
* @param signing key as input
|
||||||
*/
|
*/
|
||||||
void le_device_db_csrk_set(int index, sm_key_t csrk);
|
void le_device_db_local_csrk_set(int index, sm_key_t csrk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get signing key for this device
|
* @brief get local signing key for this device
|
||||||
* @param index
|
* @param index
|
||||||
* @param signing key as output
|
* @param signing key as output
|
||||||
*/
|
*/
|
||||||
void le_device_db_csrk_get(int index, sm_key_t csrk);
|
void le_device_db_local_csrk_get(int index, sm_key_t csrk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set remote signing key for this device
|
||||||
|
* @param index
|
||||||
|
* @param signing key as input
|
||||||
|
*/
|
||||||
|
void le_device_db_remote_csrk_set(int index, sm_key_t csrk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get remote signing key for this device
|
||||||
|
* @param index
|
||||||
|
* @param signing key as output
|
||||||
|
*/
|
||||||
|
void le_device_db_remote_csrk_get(int index, sm_key_t csrk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief query last used/seen signing counter
|
* @brief query last used/seen signing counter
|
||||||
|
@ -57,7 +57,15 @@ void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm
|
|||||||
void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t csrk){}
|
void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t csrk){}
|
||||||
|
|
||||||
// get signature key
|
// get signature key
|
||||||
void le_device_db_csrk_get(int index, sm_key_t csrk){}
|
void le_device_db_remote_csrk_get(int index, sm_key_t csrk){}
|
||||||
|
|
||||||
|
void le_device_db_remote_csrk_set(int index, sm_key_t csrk){}
|
||||||
|
|
||||||
|
// get signature key
|
||||||
|
void le_device_db_local_csrk_get(int index, sm_key_t csrk){}
|
||||||
|
|
||||||
|
void le_device_db_local_csrk_set(int index, sm_key_t csrk){}
|
||||||
|
|
||||||
|
|
||||||
// query last used/seen signing counter
|
// query last used/seen signing counter
|
||||||
uint32_t le_device_db_remote_counter_get(int index){
|
uint32_t le_device_db_remote_counter_get(int index){
|
||||||
|
@ -59,10 +59,11 @@ typedef struct le_device_memory_db {
|
|||||||
uint8_t authorized;
|
uint8_t authorized;
|
||||||
|
|
||||||
// Signed Writes by remote
|
// Signed Writes by remote
|
||||||
sm_key_t csrk;
|
sm_key_t remote_csrk;
|
||||||
uint32_t remote_counter;
|
uint32_t remote_counter;
|
||||||
|
|
||||||
// Signed Writes to remote (local CSRK is fixed)
|
// Signed Writes by us
|
||||||
|
sm_key_t local_csrk;
|
||||||
uint32_t local_counter;
|
uint32_t local_counter;
|
||||||
|
|
||||||
} le_device_memory_db_t;
|
} le_device_memory_db_t;
|
||||||
@ -150,12 +151,20 @@ void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get signature key
|
// get signature key
|
||||||
void le_device_db_csrk_get(int index, sm_key_t csrk){
|
void le_device_db_remote_csrk_get(int index, sm_key_t csrk){
|
||||||
if (csrk) memcpy(csrk, le_devices[index].csrk, 16);
|
if (csrk) memcpy(csrk, le_devices[index].remote_csrk, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void le_device_db_csrk_set(int index, sm_key_t csrk){
|
void le_device_db_remote_csrk_set(int index, sm_key_t csrk){
|
||||||
if (csrk) memcpy(le_devices[index].csrk, csrk, 16);
|
if (csrk) memcpy(le_devices[index].remote_csrk, csrk, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void le_device_db_local_csrk_get(int index, sm_key_t csrk){
|
||||||
|
if (csrk) memcpy(csrk, le_devices[index].local_csrk, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void le_device_db_local_csrk_set(int index, sm_key_t csrk){
|
||||||
|
if (csrk) memcpy(le_devices[index].local_csrk, csrk, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// query last used/seen signing counter
|
// query last used/seen signing counter
|
||||||
@ -185,6 +194,7 @@ void le_device_db_dump(void){
|
|||||||
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue;
|
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue;
|
||||||
log_info("%u: %u %s", i, le_devices[i].addr_type, bd_addr_to_str(le_devices[i].addr));
|
log_info("%u: %u %s", i, le_devices[i].addr_type, bd_addr_to_str(le_devices[i].addr));
|
||||||
log_key("irk", le_devices[i].irk);
|
log_key("irk", le_devices[i].irk);
|
||||||
log_key("csrk", le_devices[i].csrk);
|
log_key("local csrk", le_devices[i].local_csrk);
|
||||||
|
log_key("remote csrk", le_devices[i].remote_csrk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
ble/sm.c
23
ble/sm.c
@ -117,6 +117,8 @@ typedef enum {
|
|||||||
// GLOBAL DATA
|
// GLOBAL DATA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static uint8_t test_use_fixed_local_csrk;
|
||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
static uint8_t sm_accepted_stk_generation_methods;
|
static uint8_t sm_accepted_stk_generation_methods;
|
||||||
static uint8_t sm_max_encryption_key_size;
|
static uint8_t sm_max_encryption_key_size;
|
||||||
@ -1013,7 +1015,7 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
|
|||||||
// store CSRK
|
// store CSRK
|
||||||
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
||||||
log_info("sm: store remote CSRK");
|
log_info("sm: store remote CSRK");
|
||||||
le_device_db_csrk_set(le_db_index, setup->sm_peer_csrk);
|
le_device_db_remote_csrk_set(le_db_index, setup->sm_peer_csrk);
|
||||||
le_device_db_remote_counter_set(le_db_index, 0);
|
le_device_db_remote_counter_set(le_db_index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1505,16 +1507,15 @@ static void sm_run(void){
|
|||||||
if (setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
if (setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
||||||
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
|
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
|
||||||
|
|
||||||
|
// hack to reproduce test runs
|
||||||
|
if (test_use_fixed_local_csrk){
|
||||||
|
memset(setup->sm_local_csrk, 0xcc, 16);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t buffer[17];
|
uint8_t buffer[17];
|
||||||
buffer[0] = SM_CODE_SIGNING_INFORMATION;
|
buffer[0] = SM_CODE_SIGNING_INFORMATION;
|
||||||
// optimization: use CSRK of Peripheral if received, to avoid storing two CSRKs in our DB
|
|
||||||
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
|
|
||||||
log_info("sm: mirror CSRK");
|
|
||||||
memcpy(setup->sm_local_csrk, setup->sm_peer_csrk, 16);
|
|
||||||
} else {
|
|
||||||
log_info("sm: store local CSRK");
|
log_info("sm: store local CSRK");
|
||||||
le_device_db_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk);
|
le_device_db_local_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk);
|
||||||
}
|
|
||||||
swap128(setup->sm_local_csrk, &buffer[1]);
|
swap128(setup->sm_local_csrk, &buffer[1]);
|
||||||
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
|
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
|
||||||
sm_timeout_reset(connection);
|
sm_timeout_reset(connection);
|
||||||
@ -2286,6 +2287,10 @@ void sm_test_set_irk(sm_key_t irk){
|
|||||||
sm_persistent_irk_ready = 1;
|
sm_persistent_irk_ready = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sm_test_use_fixed_local_csrk(void){
|
||||||
|
test_use_fixed_local_csrk = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void sm_init(void){
|
void sm_init(void){
|
||||||
// set some (BTstack default) ER and IR
|
// set some (BTstack default) ER and IR
|
||||||
int i;
|
int i;
|
||||||
@ -2317,6 +2322,8 @@ void sm_init(void){
|
|||||||
|
|
||||||
sm_active_connection = 0;
|
sm_active_connection = 0;
|
||||||
|
|
||||||
|
test_use_fixed_local_csrk = 0;
|
||||||
|
|
||||||
// attach to lower layers
|
// attach to lower layers
|
||||||
l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
|
l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
|
||||||
}
|
}
|
||||||
|
3
ble/sm.h
3
ble/sm.h
@ -279,6 +279,9 @@ int sm_address_resolution_lookup(uint8_t addr_type, bd_addr_t addr);
|
|||||||
int sm_le_device_index(uint16_t handle );
|
int sm_le_device_index(uint16_t handle );
|
||||||
/* API_END */
|
/* API_END */
|
||||||
|
|
||||||
|
// testing only
|
||||||
|
void sm_test_use_fixed_local_csrk(void);
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
27
platforms/posix-h4/.gitignore
vendored
Normal file
27
platforms/posix-h4/.gitignore
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
ancs_client
|
||||||
|
ancs_client.h
|
||||||
|
ble_central_test
|
||||||
|
ble_peripheral
|
||||||
|
ble_peripheral_sm_minimal
|
||||||
|
bnep_test
|
||||||
|
classic_test
|
||||||
|
gap_dedicated_bonding
|
||||||
|
gap_inquiry
|
||||||
|
gap_inquiry_and_bond
|
||||||
|
gatt_battery_query
|
||||||
|
gatt_browser
|
||||||
|
hsp_ag_test
|
||||||
|
hsp_hs_test
|
||||||
|
l2cap_test
|
||||||
|
profile.h
|
||||||
|
sdp_bnep_query
|
||||||
|
sdp_general_query
|
||||||
|
sdp_rfcomm_query
|
||||||
|
spp_and_le_counter
|
||||||
|
spp_and_le_counter.h
|
||||||
|
spp_counter
|
||||||
|
spp_streamer
|
||||||
|
led_counter
|
||||||
|
le_counter.h
|
||||||
|
ble_peripheral_test
|
||||||
|
le_counter
|
27
platforms/posix-h4/Makefile
Normal file
27
platforms/posix-h4/Makefile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Makefile for libusb based examples
|
||||||
|
BTSTACK_ROOT = ../..
|
||||||
|
POSIX_ROOT= ${BTSTACK_ROOT}/platforms/posix
|
||||||
|
|
||||||
|
CORE += main.c stdin_support.c
|
||||||
|
|
||||||
|
COMMON += hci_transport_h4.c run_loop_posix.c remote_device_db_fs.c
|
||||||
|
|
||||||
|
include ${BTSTACK_ROOT}/example/embedded/Makefile.inc
|
||||||
|
|
||||||
|
# CC = gcc-fsf-4.9
|
||||||
|
CFLAGS += -g -Wall
|
||||||
|
# CFLAGS += -Werror
|
||||||
|
|
||||||
|
VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
LDFLAGS += -lws2_32
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Command Line examples require porting to win32, so only build on other unix-ish hosts
|
||||||
|
ifneq ($(OS),Windows_NT)
|
||||||
|
EXAMPLES += ${EXAMPLES_CLI}
|
||||||
|
CFLAGS += -I${POSIX_ROOT}/src
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: ${BTSTACK_ROOT}/include/btstack/version.h ${EXAMPLES}
|
24
platforms/posix-h4/btstack-config.h
Normal file
24
platforms/posix-h4/btstack-config.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// config.h created by configure for BTstack Tue Jun 4 23:10:20 CEST 2013
|
||||||
|
|
||||||
|
#ifndef __BTSTACK_CONFIG
|
||||||
|
#define __BTSTACK_CONFIG
|
||||||
|
|
||||||
|
#define HAVE_TRANSPORT_USB
|
||||||
|
#define HAVE_BLE
|
||||||
|
#define USE_POSIX_RUN_LOOP
|
||||||
|
#define HAVE_SDP
|
||||||
|
#define HAVE_RFCOMM
|
||||||
|
#define REMOTE_DEVICE_DB remote_device_db_iphone
|
||||||
|
#define HAVE_SO_NOSIGPIPE
|
||||||
|
#define HAVE_TIME
|
||||||
|
#define HAVE_MALLOC
|
||||||
|
#define HAVE_BZERO
|
||||||
|
#define SDP_DES_DUMP
|
||||||
|
#define ENABLE_LOG_INFO
|
||||||
|
#define ENABLE_LOG_ERROR
|
||||||
|
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy
|
||||||
|
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
|
||||||
|
#define HAVE_HCI_DUMP
|
||||||
|
#define SDP_DES_DUMP
|
||||||
|
|
||||||
|
#endif
|
115
platforms/posix-h4/main.c
Normal file
115
platforms/posix-h4/main.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 BlueKitchen GmbH
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* 4. Any redistribution, use, or modification is done solely for
|
||||||
|
* personal benefit and not for any commercial purpose or for
|
||||||
|
* monetary gain.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||||
|
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Please inquire about commercial licensing options at
|
||||||
|
* contact@bluekitchen-gmbh.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
//
|
||||||
|
// minimal setup for HCI code
|
||||||
|
//
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "btstack-config.h"
|
||||||
|
|
||||||
|
#include <btstack/run_loop.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "btstack_memory.h"
|
||||||
|
#include "hci.h"
|
||||||
|
#include "hci_dump.h"
|
||||||
|
#include "stdin_support.h"
|
||||||
|
|
||||||
|
int btstack_main(int argc, const char * argv[]);
|
||||||
|
|
||||||
|
static hci_uart_config_t hci_uart_config_generic = {
|
||||||
|
NULL,
|
||||||
|
115200,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sigint_handler(int param){
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
// reset anyway
|
||||||
|
btstack_stdin_reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
log_info(" <= SIGINT received, shutting down..\n");
|
||||||
|
hci_power_control(HCI_POWER_OFF);
|
||||||
|
hci_close();
|
||||||
|
log_info("Good bye, see you.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_state = 0;
|
||||||
|
void hal_led_toggle(void){
|
||||||
|
led_state = 1 - led_state;
|
||||||
|
printf("LED State %u\n", led_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]){
|
||||||
|
|
||||||
|
/// GET STARTED with BTstack ///
|
||||||
|
btstack_memory_init();
|
||||||
|
run_loop_init(RUN_LOOP_POSIX);
|
||||||
|
|
||||||
|
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
|
||||||
|
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
|
||||||
|
|
||||||
|
// pick serial port
|
||||||
|
hci_uart_config_generic.device_name = "/dev/tty.usbmodem1413";
|
||||||
|
|
||||||
|
// init HCI
|
||||||
|
hci_transport_t * transport = hci_transport_h4_instance();
|
||||||
|
remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_fs;
|
||||||
|
|
||||||
|
hci_init(transport, (void*) &hci_uart_config_generic, NULL, remote_db);
|
||||||
|
|
||||||
|
// handle CTRL-c
|
||||||
|
signal(SIGINT, sigint_handler);
|
||||||
|
|
||||||
|
// setup app
|
||||||
|
btstack_main(argc, argv);
|
||||||
|
|
||||||
|
// go
|
||||||
|
run_loop_execute();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
54
src/hci.c
54
src/hci.c
@ -85,6 +85,7 @@ static void hci_connection_timestamp(hci_connection_t *connection);
|
|||||||
static int hci_power_control_on(void);
|
static int hci_power_control_on(void);
|
||||||
static void hci_power_control_off(void);
|
static void hci_power_control_off(void);
|
||||||
static void hci_state_reset(void);
|
static void hci_state_reset(void);
|
||||||
|
static void hci_remove_from_whitelist(bd_addr_type_t address_type, bd_addr_t address);
|
||||||
|
|
||||||
// the STACK is here
|
// the STACK is here
|
||||||
#ifndef HAVE_MALLOC
|
#ifndef HAVE_MALLOC
|
||||||
@ -1573,27 +1574,35 @@ static void event_handler(uint8_t *packet, int size){
|
|||||||
addr_type = (bd_addr_type_t)packet[7];
|
addr_type = (bd_addr_type_t)packet[7];
|
||||||
log_info("LE Connection_complete (status=%u) type %u, %s", packet[3], addr_type, bd_addr_to_str(addr));
|
log_info("LE Connection_complete (status=%u) type %u, %s", packet[3], addr_type, bd_addr_to_str(addr));
|
||||||
conn = hci_connection_for_bd_addr_and_type(addr, addr_type);
|
conn = hci_connection_for_bd_addr_and_type(addr, addr_type);
|
||||||
// handle error first
|
// if auto-connect, remove from whitelist in both roles
|
||||||
|
if (hci_stack->le_connecting_state == LE_CONNECTING_WHITELIST){
|
||||||
|
hci_remove_from_whitelist(addr_type, addr);
|
||||||
|
}
|
||||||
|
// handle error: error is reported only to the initiator -> outgoing connection
|
||||||
if (packet[3]){
|
if (packet[3]){
|
||||||
|
// outgoing connection establishment is done
|
||||||
|
hci_stack->le_connecting_state = LE_CONNECTING_IDLE;
|
||||||
|
// remove entry
|
||||||
if (conn){
|
if (conn){
|
||||||
// outgoing connection failed, remove entry
|
|
||||||
linked_list_remove(&hci_stack->connections, (linked_item_t *) conn);
|
linked_list_remove(&hci_stack->connections, (linked_item_t *) conn);
|
||||||
btstack_memory_hci_connection_free( conn );
|
btstack_memory_hci_connection_free( conn );
|
||||||
}
|
}
|
||||||
// if authentication error, also delete link key
|
|
||||||
if (packet[3] == 0x05) {
|
|
||||||
hci_drop_link_key_for_bd_addr(addr);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!conn){
|
// on success, both hosts receive connection complete event
|
||||||
// advertisemts are stopped on incoming connection
|
if (packet[6] == 0){
|
||||||
|
// if we're master, it was an outgoing connection and we're done with it
|
||||||
|
hci_stack->le_connecting_state = LE_CONNECTING_IDLE;
|
||||||
|
} else {
|
||||||
|
// if we're slave, it was an incoming connection, advertisements have stopped
|
||||||
hci_stack->le_advertisements_active = 0;
|
hci_stack->le_advertisements_active = 0;
|
||||||
|
}
|
||||||
// LE connections are auto-accepted, so just create a connection if there isn't one already
|
// LE connections are auto-accepted, so just create a connection if there isn't one already
|
||||||
|
if (!conn){
|
||||||
conn = create_connection_for_bd_addr_and_type(addr, addr_type);
|
conn = create_connection_for_bd_addr_and_type(addr, addr_type);
|
||||||
}
|
}
|
||||||
|
// no memory, sorry.
|
||||||
if (!conn){
|
if (!conn){
|
||||||
// no memory
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2204,9 +2213,12 @@ void hci_run(void){
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (entry->state & LE_WHITELIST_REMOVE_FROM_CONTROLLER){
|
if (entry->state & LE_WHITELIST_REMOVE_FROM_CONTROLLER){
|
||||||
|
bd_addr_t address;
|
||||||
|
bd_addr_type_t address_type = entry->address_type;
|
||||||
|
memcpy(address, entry->address, 6);
|
||||||
linked_list_remove(&hci_stack->le_whitelist, (linked_item_t *) entry);
|
linked_list_remove(&hci_stack->le_whitelist, (linked_item_t *) entry);
|
||||||
btstack_memory_whitelist_entry_free(entry);
|
btstack_memory_whitelist_entry_free(entry);
|
||||||
hci_send_cmd(&hci_le_remove_device_from_white_list, entry->address_type, entry->address);
|
hci_send_cmd(&hci_le_remove_device_from_white_list, address_type, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3125,7 +3137,7 @@ void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * adve
|
|||||||
hci_stack->le_advertisements_data = advertising_data;
|
hci_stack->le_advertisements_data = advertising_data;
|
||||||
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_DATA;
|
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_DATA;
|
||||||
// disable advertisements before setting data
|
// disable advertisements before setting data
|
||||||
if (hci_stack->le_advertisements_enabled){
|
if (hci_stack->le_advertisements_active){
|
||||||
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE;
|
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE;
|
||||||
}
|
}
|
||||||
hci_run();
|
hci_run();
|
||||||
@ -3159,7 +3171,7 @@ void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * adve
|
|||||||
|
|
||||||
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_PARAMS;
|
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_SET_PARAMS;
|
||||||
// disable advertisements before changing params
|
// disable advertisements before changing params
|
||||||
if (hci_stack->le_advertisements_enabled){
|
if (hci_stack->le_advertisements_active){
|
||||||
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE;
|
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_DISABLE | LE_ADVERTISEMENT_TASKS_ENABLE;
|
||||||
}
|
}
|
||||||
hci_run();
|
hci_run();
|
||||||
@ -3214,13 +3226,7 @@ int gap_auto_connection_start(bd_addr_type_t address_type, bd_addr_t address){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void hci_remove_from_whitelist(bd_addr_type_t address_type, bd_addr_t address){
|
||||||
* @brief Auto Connection Establishment - Stop Connecting to device
|
|
||||||
* @param address_typ
|
|
||||||
* @param address
|
|
||||||
* @returns 0 if ok
|
|
||||||
*/
|
|
||||||
int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){
|
|
||||||
linked_list_iterator_t it;
|
linked_list_iterator_t it;
|
||||||
linked_list_iterator_init(&it, &hci_stack->le_whitelist);
|
linked_list_iterator_init(&it, &hci_stack->le_whitelist);
|
||||||
while (linked_list_iterator_has_next(&it)){
|
while (linked_list_iterator_has_next(&it)){
|
||||||
@ -3236,6 +3242,16 @@ int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){
|
|||||||
linked_list_iterator_remove(&it);
|
linked_list_iterator_remove(&it);
|
||||||
btstack_memory_whitelist_entry_free(entry);
|
btstack_memory_whitelist_entry_free(entry);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Auto Connection Establishment - Stop Connecting to device
|
||||||
|
* @param address_typ
|
||||||
|
* @param address
|
||||||
|
* @returns 0 if ok
|
||||||
|
*/
|
||||||
|
int gap_auto_connection_stop(bd_addr_type_t address_type, bd_addr_t address){
|
||||||
|
hci_remove_from_whitelist(address_type, address);
|
||||||
hci_run();
|
hci_run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,24 +12,23 @@ SUBDIRS = \
|
|||||||
sdp_client \
|
sdp_client \
|
||||||
security_manager \
|
security_manager \
|
||||||
|
|
||||||
# security_manager \
|
|
||||||
|
|
||||||
EXCLUDED = ios
|
|
||||||
|
|
||||||
subdirs:
|
subdirs:
|
||||||
echo Building all tests
|
echo Building all tests
|
||||||
|
@set -e; \
|
||||||
for dir in $(SUBDIRS); do \
|
for dir in $(SUBDIRS); do \
|
||||||
$(MAKE) -C $$dir; \
|
$(MAKE) -C $$dir; \
|
||||||
done
|
done
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
echo Clean all test
|
echo Clean all test
|
||||||
|
@set -e; \
|
||||||
for dir in $(SUBDIRS); do \
|
for dir in $(SUBDIRS); do \
|
||||||
$(MAKE) -C $$dir clean; \
|
$(MAKE) -C $$dir clean; \
|
||||||
done
|
done
|
||||||
|
|
||||||
test:
|
test:
|
||||||
echo Run all test
|
echo Run all test
|
||||||
|
@set -e; \
|
||||||
for dir in $(SUBDIRS); do \
|
for dir in $(SUBDIRS); do \
|
||||||
$(MAKE) -C $$dir test; \
|
$(MAKE) -C $$dir test; \
|
||||||
done
|
done
|
||||||
|
@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
|||||||
|
|
||||||
COMMON = \
|
COMMON = \
|
||||||
utils.c \
|
utils.c \
|
||||||
|
hci_dump.c \
|
||||||
att_db_util.c \
|
att_db_util.c \
|
||||||
|
|
||||||
COMMON_OBJ = $(COMMON:.c=.o)
|
COMMON_OBJ = $(COMMON:.c=.o)
|
||||||
|
@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
|||||||
|
|
||||||
COMMON = \
|
COMMON = \
|
||||||
sdp_util.c \
|
sdp_util.c \
|
||||||
|
hci_dump.c \
|
||||||
utils.c
|
utils.c
|
||||||
|
|
||||||
COMMON_OBJ = $(COMMON:.c=.o)
|
COMMON_OBJ = $(COMMON:.c=.o)
|
||||||
|
@ -32,7 +32,7 @@ const uint8_t included_services_uuid128_handles[][2] = {
|
|||||||
uint8_t characteristic_handles[][2]= {
|
uint8_t characteristic_handles[][2]= {
|
||||||
{0x26, 0x2a}, {0x2b, 0x2f}, {0x30, 0x32}, {0x33, 0x35}, {0x36, 0x38},
|
{0x26, 0x2a}, {0x2b, 0x2f}, {0x30, 0x32}, {0x33, 0x35}, {0x36, 0x38},
|
||||||
{0x39, 0x3b}, {0x3c, 0x3e}, {0x3f, 0x41}, {0x42, 0x44}, {0x45, 0x47},
|
{0x39, 0x3b}, {0x3c, 0x3e}, {0x3f, 0x41}, {0x42, 0x44}, {0x45, 0x47},
|
||||||
{0x48, 0x49}, {0x4a, 0x4f}, {0x50, 0x51}, {0x52, 0x53}
|
{0x48, 0x49}, {0x4a, 0x4f}, {0x50, 0x51}, {0x52, 0x53}, {0x54, 0x55}
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t characteristic_uuids[][16] = {
|
uint8_t characteristic_uuids[][16] = {
|
||||||
@ -49,7 +49,8 @@ uint8_t characteristic_uuids[][16] = {
|
|||||||
{0x00, 0x00, 0xf1, 0x0a, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
{0x00, 0x00, 0xf1, 0x0a, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
||||||
{0x00, 0x00, 0xf1, 0x0b, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
{0x00, 0x00, 0xf1, 0x0b, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
||||||
{0x00, 0x00, 0xf1, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
{0x00, 0x00, 0xf1, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
||||||
{0x00, 0x00, 0xf1, 0x0c, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
|
{0x00, 0x00, 0xf1, 0x0c, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
||||||
|
{0x00, 0x00, 0xf1, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t indication[] = {GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION, 0x00};
|
uint8_t indication[] = {GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION, 0x00};
|
||||||
|
@ -128,7 +128,7 @@ static void verify_included_services_uuid128(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void verify_charasteristics(void){
|
static void verify_charasteristics(void){
|
||||||
CHECK_EQUAL(14, result_index);
|
CHECK_EQUAL(15, result_index);
|
||||||
for (int i=0; i<result_index; i++){
|
for (int i=0; i<result_index; i++){
|
||||||
CHECK_EQUAL_GATT_ATTRIBUTE(characteristic_uuids[i], characteristic_handles[i], characteristics[i].uuid128, characteristics[i].start_handle, characteristics[i].end_handle);
|
CHECK_EQUAL_GATT_ATTRIBUTE(characteristic_uuids[i], characteristic_handles[i], characteristics[i].uuid128, characteristics[i].start_handle, characteristics[i].end_handle);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t l
|
|||||||
int sm_cmac_ready(void){
|
int sm_cmac_ready(void){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
void sm_cmac_start(sm_key_t k, uint16_t message_len, uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t hash[8])){
|
void sm_cmac_start(sm_key_t k, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t hash[8])){
|
||||||
//sm_notify_client(SM_IDENTITY_RESOLVING_SUCCEEDED, sm_central_device_addr_type, sm_central_device_address, 0, sm_central_device_matched);
|
//sm_notify_client(SM_IDENTITY_RESOLVING_SUCCEEDED, sm_central_device_addr_type, sm_central_device_address, 0, sm_central_device_matched);
|
||||||
}
|
}
|
||||||
int sm_le_device_index(uint16_t handle ){
|
int sm_le_device_index(uint16_t handle ){
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
|
|
||||||
// Non standard IXIT
|
// Non standard IXIT
|
||||||
#define PTS_USES_RECONNECTION_ADDRESS_FOR_ITSELF
|
#define PTS_USES_RECONNECTION_ADDRESS_FOR_ITSELF
|
||||||
|
#define PTS_UUID128_REPRESENTATION
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CENTRAL_IDLE,
|
CENTRAL_IDLE,
|
||||||
@ -79,6 +80,8 @@ typedef enum {
|
|||||||
CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE,
|
CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE,
|
||||||
CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE,
|
CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE,
|
||||||
CENTRAL_W4_PRIMARY_SERVICES,
|
CENTRAL_W4_PRIMARY_SERVICES,
|
||||||
|
CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS,
|
||||||
|
CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS,
|
||||||
CENTRAL_W4_CHARACTERISTICS,
|
CENTRAL_W4_CHARACTERISTICS,
|
||||||
CENTRAL_W4_READ_CHARACTERISTIC_VALUE_BY_HANDLE,
|
CENTRAL_W4_READ_CHARACTERISTIC_VALUE_BY_HANDLE,
|
||||||
CENTRAL_ENTER_HANDLE_4_READ_CHARACTERISTIC_VALUE_BY_UUID,
|
CENTRAL_ENTER_HANDLE_4_READ_CHARACTERISTIC_VALUE_BY_UUID,
|
||||||
@ -98,6 +101,13 @@ typedef enum {
|
|||||||
CENTRAL_ENTER_HANDLE_4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
|
CENTRAL_ENTER_HANDLE_4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
|
||||||
CENTRAL_W4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
|
CENTRAL_W4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
|
||||||
CENTRAL_W4_SIGNED_WRITE,
|
CENTRAL_W4_SIGNED_WRITE,
|
||||||
|
CENTRAL_GPA_ENTER_UUID,
|
||||||
|
CENTRAL_GPA_ENTER_START_HANDLE,
|
||||||
|
CENTRAL_GPA_ENTER_END_HANDLE,
|
||||||
|
CENTRAL_GPA_W4_RESPONSE,
|
||||||
|
CENTRAL_GPA_W4_RESPONSE2,
|
||||||
|
CENTRAL_GPA_W4_RESPONSE3,
|
||||||
|
CENTRAL_GPA_W4_RESPONSE4,
|
||||||
} central_state_t;
|
} central_state_t;
|
||||||
|
|
||||||
typedef struct advertising_report {
|
typedef struct advertising_report {
|
||||||
@ -110,6 +120,19 @@ typedef struct advertising_report {
|
|||||||
uint8_t * data;
|
uint8_t * data;
|
||||||
} advertising_report_t;
|
} advertising_report_t;
|
||||||
|
|
||||||
|
static const uint8_t gpa_format_type_len[] = {
|
||||||
|
/* 0x00 */
|
||||||
|
1,1,1,1,1,
|
||||||
|
/* 0x05 */
|
||||||
|
2,2,
|
||||||
|
/* 0x07 */
|
||||||
|
3,4,6,8,16,
|
||||||
|
/* 0x0c */
|
||||||
|
1,2,2,3,4,6,8,16,
|
||||||
|
/* 0x14 */
|
||||||
|
4,8,2,4,4
|
||||||
|
};
|
||||||
|
|
||||||
static uint8_t test_irk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
static uint8_t test_irk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
static int gap_privacy = 0;
|
static int gap_privacy = 0;
|
||||||
@ -129,19 +152,25 @@ static int peer_addr_type;
|
|||||||
static bd_addr_t peer_address;
|
static bd_addr_t peer_address;
|
||||||
static int ui_passkey = 0;
|
static int ui_passkey = 0;
|
||||||
static int ui_digits_for_passkey = 0;
|
static int ui_digits_for_passkey = 0;
|
||||||
static int ui_uint16_request = 0;
|
|
||||||
static int ui_uint16 = 0;
|
static int ui_uint16 = 0;
|
||||||
|
static int ui_uint16_request = 0;
|
||||||
|
static int ui_uint16_pos = 0;
|
||||||
static int ui_uuid16 = 0;
|
static int ui_uuid16 = 0;
|
||||||
static int ui_uuid128_request = 0;
|
static int ui_uuid128_request = 0;
|
||||||
static int ui_uuid128_pos = 0;
|
static int ui_uuid128_pos = 0;
|
||||||
static uint8_t ui_uuid128[16];
|
static uint8_t ui_uuid128[16];
|
||||||
static int ui_num_handles;
|
static int ui_handles_count;
|
||||||
|
static int ui_handles_index;
|
||||||
static uint16_t ui_handles[10];
|
static uint16_t ui_handles[10];
|
||||||
static uint16_t ui_attribute_handle;
|
static uint16_t ui_attribute_handle;
|
||||||
static int ui_attribute_offset;
|
static int ui_attribute_offset;
|
||||||
static int ui_value_request = 0;
|
static int ui_value_request = 0;
|
||||||
static uint8_t ui_value_data[50];
|
static uint8_t ui_value_data[50];
|
||||||
static int ui_value_pos = 0;
|
static int ui_value_pos = 0;
|
||||||
|
static uint16_t ui_start_handle;
|
||||||
|
static uint16_t ui_end_handle;
|
||||||
|
static uint8_t ui_presentation_format[7];
|
||||||
|
static uint16_t ui_aggregate_handle;
|
||||||
static uint16_t handle = 0;
|
static uint16_t handle = 0;
|
||||||
static uint16_t gc_id;
|
static uint16_t gc_id;
|
||||||
|
|
||||||
@ -153,7 +182,7 @@ static int reconnection_address_set = 0;
|
|||||||
static bd_addr_t our_private_address;
|
static bd_addr_t our_private_address;
|
||||||
|
|
||||||
static uint16_t pts_signed_write_characteristic_uuid = 0xb00d;
|
static uint16_t pts_signed_write_characteristic_uuid = 0xb00d;
|
||||||
static uint16_t pts_signed_write_characteristic_handle = 0x0100;
|
static uint16_t pts_signed_write_characteristic_handle = 0x00b1;
|
||||||
static uint8_t signed_write_value[] = { 0x12 };
|
static uint8_t signed_write_value[] = { 0x12 };
|
||||||
static int le_device_db_index;
|
static int le_device_db_index;
|
||||||
static sm_key_t signing_csrk;
|
static sm_key_t signing_csrk;
|
||||||
@ -198,11 +227,13 @@ static const char * att_errors[] = {
|
|||||||
static const char * att_error_reserved = "Reserved";
|
static const char * att_error_reserved = "Reserved";
|
||||||
static const char * att_error_application = "Application Error";
|
static const char * att_error_application = "Application Error";
|
||||||
static const char * att_error_common_error = "Common Profile and Service Error Codes";
|
static const char * att_error_common_error = "Common Profile and Service Error Codes";
|
||||||
|
static const char * att_error_timeout = "Timeout";
|
||||||
|
|
||||||
const char * att_error_string_for_code(uint8_t code){
|
const char * att_error_string_for_code(uint8_t code){
|
||||||
if (code >= 0xe0) return att_error_common_error;
|
if (code >= 0xe0) return att_error_common_error;
|
||||||
if (code >= 0xa0) return att_error_reserved;
|
if (code >= 0xa0) return att_error_reserved;
|
||||||
if (code >= 0x80) return att_error_application;
|
if (code >= 0x80) return att_error_application;
|
||||||
|
if (code == 0x7f) return att_error_timeout;
|
||||||
if (code >= 0x12) return att_error_reserved;
|
if (code >= 0x12) return att_error_reserved;
|
||||||
return att_errors[code];
|
return att_errors[code];
|
||||||
}
|
}
|
||||||
@ -391,6 +422,7 @@ void use_public_pts_address(void){
|
|||||||
|
|
||||||
void handle_gatt_client_event(le_event_t * event){
|
void handle_gatt_client_event(le_event_t * event){
|
||||||
le_characteristic_value_event_t * value;
|
le_characteristic_value_event_t * value;
|
||||||
|
le_characteristic_event_t * characteristic_event;
|
||||||
uint8_t address_type;
|
uint8_t address_type;
|
||||||
bd_addr_t flipped_address;
|
bd_addr_t flipped_address;
|
||||||
le_service_t * service;
|
le_service_t * service;
|
||||||
@ -416,25 +448,41 @@ void handle_gatt_client_event(le_event_t * event){
|
|||||||
printf(", start group handle 0x%04x, end group handle 0x%04x\n", service->start_group_handle, service->end_group_handle);
|
printf(", start group handle 0x%04x, end group handle 0x%04x\n", service->start_group_handle, service->end_group_handle);
|
||||||
break;
|
break;
|
||||||
case GATT_CHARACTERISTIC_QUERY_RESULT:
|
case GATT_CHARACTERISTIC_QUERY_RESULT:
|
||||||
|
characteristic_event = ((le_characteristic_event_t *) event);
|
||||||
switch (central_state) {
|
switch (central_state) {
|
||||||
case CENTRAL_W4_NAME_QUERY_COMPLETE:
|
case CENTRAL_W4_NAME_QUERY_COMPLETE:
|
||||||
gap_name_characteristic = ((le_characteristic_event_t *) event)->characteristic;
|
gap_name_characteristic = characteristic_event->characteristic;
|
||||||
printf("GAP Name Characteristic found, value handle: 0x04%x\n", gap_name_characteristic.value_handle);
|
printf("GAP Name Characteristic found, value handle: 0x04%x\n", gap_name_characteristic.value_handle);
|
||||||
break;
|
break;
|
||||||
case CENTRAL_W4_RECONNECTION_ADDRESS_QUERY_COMPLETE:
|
case CENTRAL_W4_RECONNECTION_ADDRESS_QUERY_COMPLETE:
|
||||||
gap_reconnection_address_characteristic = ((le_characteristic_event_t *) event)->characteristic;
|
gap_reconnection_address_characteristic = characteristic_event->characteristic;
|
||||||
printf("GAP Reconnection Address Characteristic found, value handle: 0x04%x\n", gap_reconnection_address_characteristic.value_handle);
|
printf("GAP Reconnection Address Characteristic found, value handle: 0x04%x\n", gap_reconnection_address_characteristic.value_handle);
|
||||||
break;
|
break;
|
||||||
case CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE:
|
case CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE:
|
||||||
gap_peripheral_privacy_flag_characteristic = ((le_characteristic_event_t *) event)->characteristic;
|
gap_peripheral_privacy_flag_characteristic = characteristic_event->characteristic;
|
||||||
printf("GAP Peripheral Privacy Flag Characteristic found, value handle: 0x04%x\n", gap_peripheral_privacy_flag_characteristic.value_handle);
|
printf("GAP Peripheral Privacy Flag Characteristic found, value handle: 0x04%x\n", gap_peripheral_privacy_flag_characteristic.value_handle);
|
||||||
break;
|
break;
|
||||||
case CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE:
|
case CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE:
|
||||||
signed_write_characteristic = ((le_characteristic_event_t *) event)->characteristic;
|
signed_write_characteristic = characteristic_event->characteristic;
|
||||||
printf("Characteristic for Signed Write found, value handle: 0x%04x\n", signed_write_characteristic.value_handle);
|
printf("Characteristic for Signed Write found, value handle: 0x%04x\n", signed_write_characteristic.value_handle);
|
||||||
break;
|
break;
|
||||||
case CENTRAL_W4_CHARACTERISTICS:
|
case CENTRAL_W4_CHARACTERISTICS:
|
||||||
printf("Characteristic found with handle 0x%04x\n", (((le_characteristic_event_t *) event)->characteristic).value_handle);
|
printf("Characteristic found with handle 0x%04x, uuid ", (characteristic_event->characteristic).value_handle);
|
||||||
|
if ((characteristic_event->characteristic).uuid16){
|
||||||
|
printf("%04x\n", (characteristic_event->characteristic).uuid16);
|
||||||
|
} else {
|
||||||
|
printf_hexdump((characteristic_event->characteristic).uuid128, 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE2:
|
||||||
|
switch (ui_uuid16){
|
||||||
|
case GATT_CHARACTERISTIC_PRESENTATION_FORMAT:
|
||||||
|
case GATT_CHARACTERISTIC_AGGREGATE_FORMAT:
|
||||||
|
ui_attribute_handle = characteristic_event->characteristic.value_handle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -453,6 +501,79 @@ void handle_gatt_client_event(le_event_t * event){
|
|||||||
printf("Value: ");
|
printf("Value: ");
|
||||||
printf_hexdump(value->blob, value->blob_length);
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
break;
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE:
|
||||||
|
switch (ui_uuid16){
|
||||||
|
case GATT_PRIMARY_SERVICE_UUID:
|
||||||
|
printf ("Attribute handle 0x%04x, primary service 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0));
|
||||||
|
break;
|
||||||
|
case GATT_SECONDARY_SERVICE_UUID:
|
||||||
|
printf ("Attribute handle 0x%04x, secondary service 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0));
|
||||||
|
break;
|
||||||
|
case GATT_INCLUDE_SERVICE_UUID:
|
||||||
|
printf ("Attribute handle 0x%04x, included service attribute handle 0x%04x, end group handle 0x%04x, uuid %04x\n",
|
||||||
|
value->value_handle, READ_BT_16(value->blob,0), READ_BT_16(value->blob,2), READ_BT_16(value->blob,4));
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTICS_UUID:
|
||||||
|
printf ("Attribute handle 0x%04x, properties 0x%02x, value handle 0x%04x, uuid ",
|
||||||
|
value->value_handle, value->blob[0], READ_BT_16(value->blob,1));
|
||||||
|
if (value->blob_length < 19){
|
||||||
|
printf("%04x\n", READ_BT_16(value->blob, 3));
|
||||||
|
} else {
|
||||||
|
printUUID128(&value->blob[3]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_EXTENDED_PROPERTIES:
|
||||||
|
printf ("Attribute handle 0x%04x, gatt characteristic properties 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0));
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_USER_DESCRIPTION:
|
||||||
|
// go the value, but PTS 6.3 requires another request
|
||||||
|
printf("Read by type request received, store attribute handle for read request\n");
|
||||||
|
ui_attribute_handle = value->value_handle;
|
||||||
|
break;
|
||||||
|
case GATT_CLIENT_CHARACTERISTICS_CONFIGURATION:
|
||||||
|
printf ("Attribute handle 0x%04x, gatt client characteristic configuration 0x%04x\n", value->value_handle, READ_BT_16(value->blob,0));
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_AGGREGATE_FORMAT:
|
||||||
|
ui_handles_count = value->blob_length >> 1;
|
||||||
|
printf ("Attribute handle 0x%04x, gatt characteristic aggregate format. Handles: ", value->value_handle);
|
||||||
|
for (ui_handles_index = 0; ui_handles_index < ui_handles_count ; ui_handles_index++){
|
||||||
|
ui_handles[ui_handles_index] = READ_BT_16(value->blob, (ui_handles_index << 1));
|
||||||
|
printf("0x%04x, ", ui_handles[ui_handles_index]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
ui_handles_index = 0;
|
||||||
|
ui_aggregate_handle = value->value_handle;
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_PRESENTATION_FORMAT:
|
||||||
|
printf("Presentation format: ");
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
memcpy(ui_presentation_format, value->blob, 7);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Value: ");
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE3:
|
||||||
|
switch (ui_uuid16){
|
||||||
|
case GATT_CHARACTERISTIC_PRESENTATION_FORMAT:
|
||||||
|
printf("Value: ");
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
printf("Format 0x%02x, Exponent 0x%02x, Unit 0x%04x\n",
|
||||||
|
ui_presentation_format[0], ui_presentation_format[1], READ_BT_16(ui_presentation_format, 2));
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_AGGREGATE_FORMAT:
|
||||||
|
printf("Aggregated value: ");
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
memcpy(ui_value_data, value->blob, value->blob_length);
|
||||||
|
ui_value_pos = 0;
|
||||||
|
central_state = CENTRAL_GPA_W4_RESPONSE4;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -465,9 +586,33 @@ void handle_gatt_client_event(le_event_t * event){
|
|||||||
break;
|
break;
|
||||||
case GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
|
case GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
|
||||||
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
|
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
|
||||||
|
switch (central_state){
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE2:
|
||||||
|
switch (ui_uuid16){
|
||||||
|
case GATT_CHARACTERISTIC_USER_DESCRIPTION:
|
||||||
|
characteristic_descriptor_event->value[characteristic_descriptor_event->value_length] = 0;
|
||||||
|
printf ("Attribute handle 0x%04x, characteristic user descriptor: %s\n",
|
||||||
|
characteristic_descriptor_event->handle, characteristic_descriptor_event->value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE4:
|
||||||
|
// only characteristic aggregate format
|
||||||
|
printf("Value: ");
|
||||||
|
printf_hexdump(&ui_value_data[ui_value_pos], gpa_format_type_len[characteristic_descriptor_event->value[0]]);
|
||||||
|
ui_value_pos += gpa_format_type_len[characteristic_descriptor_event->value[0]];
|
||||||
|
printf("Format 0x%02x, Exponent 0x%02x, Unit 0x%04x\n",
|
||||||
|
characteristic_descriptor_event->value[0], characteristic_descriptor_event->value[1],
|
||||||
|
READ_BT_16(characteristic_descriptor_event->value, 2));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
printf("Value: ");
|
printf("Value: ");
|
||||||
printf_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length);
|
printf_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
|
case GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
|
||||||
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
|
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
|
||||||
printf("Value (offset %02u): ", characteristic_descriptor_event->value_offset);
|
printf("Value (offset %02u): ", characteristic_descriptor_event->value_offset);
|
||||||
@ -523,11 +668,70 @@ void handle_gatt_client_event(le_event_t * event){
|
|||||||
printf("Primary Service Discovery complete\n");
|
printf("Primary Service Discovery complete\n");
|
||||||
central_state = CENTRAL_IDLE;
|
central_state = CENTRAL_IDLE;
|
||||||
break;
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE:
|
||||||
|
switch (ui_uuid16){
|
||||||
|
case GATT_CHARACTERISTIC_USER_DESCRIPTION:
|
||||||
|
central_state = CENTRAL_GPA_W4_RESPONSE2;
|
||||||
|
printf("Sending Read Characteristic Descriptor at 0x%04x\n", ui_attribute_handle);
|
||||||
|
gatt_client_read_characteristic_descriptor_using_descriptor_handle(gc_id, handle, ui_attribute_handle);
|
||||||
|
break;
|
||||||
|
case GATT_CHARACTERISTIC_PRESENTATION_FORMAT:
|
||||||
|
case GATT_CHARACTERISTIC_AGGREGATE_FORMAT:
|
||||||
|
{
|
||||||
|
printf("Searching Characteristic Declaration\n");
|
||||||
|
central_state = CENTRAL_GPA_W4_RESPONSE2;
|
||||||
|
le_service_t service;
|
||||||
|
service.start_group_handle = ui_start_handle;
|
||||||
|
service.end_group_handle = ui_end_handle;
|
||||||
|
gatt_client_discover_characteristics_for_service(gc_id, handle, &service);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE2:
|
||||||
|
switch(ui_uuid16){
|
||||||
|
case GATT_CHARACTERISTIC_PRESENTATION_FORMAT:
|
||||||
|
case GATT_CHARACTERISTIC_AGGREGATE_FORMAT:
|
||||||
|
printf("Reading characteristic value at 0x%04x\n", ui_attribute_handle);
|
||||||
|
central_state = CENTRAL_GPA_W4_RESPONSE3;
|
||||||
|
gatt_client_read_value_of_characteristic_using_value_handle(gc_id, handle, ui_attribute_handle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE4:
|
||||||
|
// so far, only GATT_CHARACTERISTIC_AGGREGATE_FORMAT
|
||||||
|
if (ui_handles_index < ui_handles_count) {
|
||||||
|
printf("Reading Characteristic Presentation Format at 0x%04x\n", ui_handles[ui_handles_index]);
|
||||||
|
gatt_client_read_characteristic_descriptor_using_descriptor_handle(gc_id, handle, ui_handles[ui_handles_index]);
|
||||||
|
ui_handles_index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ui_handles_index == ui_handles_count ) {
|
||||||
|
// PTS rqequires to read the characteristic aggregate descriptor again (no idea why)
|
||||||
|
gatt_client_read_value_of_characteristic_using_value_handle(gc_id, handle, ui_aggregate_handle);
|
||||||
|
ui_handles_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
central_state = CENTRAL_IDLE;
|
central_state = CENTRAL_IDLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GATT_NOTIFICATION:
|
||||||
|
value = (le_characteristic_value_event_t *) event;
|
||||||
|
printf("Notification handle 0x%04x, value: ", value->value_handle);
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
break;
|
||||||
|
case GATT_INDICATION:
|
||||||
|
value = (le_characteristic_value_event_t *) event;
|
||||||
|
printf("Indication handle 0x%04x, value: ", value->value_handle);
|
||||||
|
printf_hexdump(value->blob, value->blob_length);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -537,81 +741,143 @@ uint16_t value_handle = 1;
|
|||||||
uint16_t attribute_size = 1;
|
uint16_t attribute_size = 1;
|
||||||
int scanning_active = 0;
|
int scanning_active = 0;
|
||||||
|
|
||||||
|
int num_rows = 0;
|
||||||
|
int num_lines = 0;
|
||||||
|
const char * rows[100];
|
||||||
|
const char * lines[100];
|
||||||
|
const char * empty_string = "";
|
||||||
|
const int width = 70;
|
||||||
|
|
||||||
|
void reset_screen(void){
|
||||||
|
// free memory
|
||||||
|
int i = 0;
|
||||||
|
for (i=0;i<num_rows;i++) {
|
||||||
|
free((void*)rows[i]);
|
||||||
|
rows[i] = NULL;
|
||||||
|
}
|
||||||
|
num_rows = 0;
|
||||||
|
for (i=0;i<num_lines;i++) {
|
||||||
|
free((void*)lines[i]);
|
||||||
|
lines[i] = NULL;
|
||||||
|
}
|
||||||
|
num_lines = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_line(const char * format, ...){
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, format);
|
||||||
|
char * line = malloc(80);
|
||||||
|
vsnprintf(line, 80, format, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
lines[num_lines] = line;
|
||||||
|
num_lines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf_row(const char * format, ...){
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, format);
|
||||||
|
char * row = malloc(80);
|
||||||
|
vsnprintf(row, 80, format, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
rows[num_rows] = row;
|
||||||
|
num_rows++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_screen(void){
|
||||||
|
|
||||||
|
// clear screen
|
||||||
|
printf("\e[1;1H\e[2J");
|
||||||
|
|
||||||
|
// full lines on top
|
||||||
|
int i;
|
||||||
|
for (i=0;i<num_lines;i++){
|
||||||
|
printf("%s\n", lines[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// two columns
|
||||||
|
int second_half = (num_rows + 1) / 2;
|
||||||
|
for (i=0;i<second_half;i++){
|
||||||
|
int pos = strlen(rows[i]);
|
||||||
|
printf("%s", rows[i]);
|
||||||
|
while (pos < width){
|
||||||
|
printf(" ");
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
if (i + second_half < num_rows){
|
||||||
|
printf("| %s", rows[i+second_half]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
void show_usage(void){
|
void show_usage(void){
|
||||||
uint8_t iut_address_type;
|
uint8_t iut_address_type;
|
||||||
bd_addr_t iut_address;
|
bd_addr_t iut_address;
|
||||||
hci_le_advertisement_address(&iut_address_type, iut_address);
|
hci_le_advertisement_address(&iut_address_type, iut_address);
|
||||||
|
|
||||||
printf("\e[1;1H\e[2J");
|
reset_screen();
|
||||||
printf("--- CLI for LE Central ---\n");
|
|
||||||
printf("PTS: addr type %u, addr %s\n", current_pts_address_type, bd_addr_to_str(current_pts_address));
|
|
||||||
printf("IUT: addr type %u, addr %s\n", iut_address_type, bd_addr_to_str(iut_address));
|
|
||||||
printf("--------------------------\n");
|
|
||||||
printf("GAP: connectable %u, bondable %u\n", gap_connectable, gap_bondable);
|
|
||||||
printf("SM: %s, MITM protection %u, key range [%u..16], OOB data: ",
|
|
||||||
sm_io_capabilities, sm_mitm_protection, sm_min_key_size);
|
|
||||||
switch (sm_have_oob_data){
|
|
||||||
case 1:
|
|
||||||
printf_hexdump(sm_oob_data_A, 16);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
printf_hexdump(sm_oob_data_B, 16);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf ("None\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf("Privacy %u\n", gap_privacy);
|
|
||||||
printf("Device name: %s\n", gap_device_name);
|
|
||||||
// printf("Value Handle: %x\n", value_handle);
|
|
||||||
// printf("Attribute Size: %u\n", attribute_size);
|
|
||||||
printf("---\n");
|
|
||||||
printf("c/C - connectable off\n");
|
|
||||||
printf("d/D - bondable off/on\n");
|
|
||||||
printf("---\n");
|
|
||||||
printf("1 - enable privacy using random non-resolvable private address\n");
|
|
||||||
printf("2 - clear Peripheral Privacy Flag on PTS\n");
|
|
||||||
printf("3 - set Peripheral Privacy Flag on PTS\n");
|
|
||||||
printf("9 - create HCI Classic connection to addr %s\n", bd_addr_to_str(public_pts_address));
|
|
||||||
printf("s/S - passive/active scanning\n");
|
|
||||||
printf("a - enable Advertisements\n");
|
|
||||||
printf("b - start bonding\n");
|
|
||||||
printf("n - query GAP Device Name\n");
|
|
||||||
printf("o - set GAP Reconnection Address\n");
|
|
||||||
printf("t - terminate connection, stop connecting\n");
|
|
||||||
printf("p - auto connect to PTS\n");
|
|
||||||
printf("P - direct connect to PTS\n");
|
|
||||||
printf("w - signed write on characteristic with UUID %04x\n", pts_signed_write_characteristic_uuid);
|
|
||||||
printf("W - signed write on attribute with handle 0x%04x and value 0x12\n", pts_signed_write_characteristic_handle);
|
|
||||||
printf("z - Update L2CAP Connection Parameters\n");
|
|
||||||
printf("---\n");
|
|
||||||
printf("e - Discover all Primary Services\n");
|
|
||||||
printf("f/F - Discover Primary Service by UUID16/UUID128\n");
|
|
||||||
printf("g - Discover all characteristics by UUID16\n");
|
|
||||||
printf("i - Find all included services\n");
|
|
||||||
printf("j/J - Read (Long) Characteristic Value by handle\n");
|
|
||||||
printf("k/K - Read Characteristic Value by UUID16/UUID128\n");
|
|
||||||
printf("l/L - Read (Long) Characteristic Descriptor by handle\n");
|
|
||||||
printf("N - Read Multiple Characteristic Values\n");
|
|
||||||
printf("O - Write without Response\n");
|
|
||||||
printf("q/Q - Write (Long) Characteristic Value\n");
|
|
||||||
printf("r - Characteristic Reliable Write\n");
|
|
||||||
printf("R - Signed Write\n");
|
|
||||||
printf("u/U - Write (Long) Characteristic Descriptor\n");
|
|
||||||
printf("---\n");
|
|
||||||
printf("4 - IO_CAPABILITY_DISPLAY_ONLY\n");
|
|
||||||
printf("5 - IO_CAPABILITY_DISPLAY_YES_NO\n");
|
|
||||||
printf("6 - IO_CAPABILITY_NO_INPUT_NO_OUTPUT\n");
|
|
||||||
printf("7 - IO_CAPABILITY_KEYBOARD_ONLY\n");
|
|
||||||
printf("8 - IO_CAPABILITY_KEYBOARD_DISPLAY\n");
|
|
||||||
printf("m/M - MITM protection off\n");
|
|
||||||
printf("x/X - encryption key range [7..16]/[16..16]\n");
|
|
||||||
printf("y/Y - OOB data off/on/toggle A/B\n");
|
|
||||||
printf("---\n");
|
|
||||||
printf("Ctrl-c - exit\n");
|
|
||||||
printf("---\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
print_line("--- CLI for LE Central ---");
|
||||||
|
print_line("PTS: addr type %u, addr %s", current_pts_address_type, bd_addr_to_str(current_pts_address));
|
||||||
|
print_line("IUT: addr type %u, addr %s", iut_address_type, bd_addr_to_str(iut_address));
|
||||||
|
print_line("--------------------------");
|
||||||
|
print_line("GAP: connectable %u, bondable %u", gap_connectable, gap_bondable);
|
||||||
|
print_line("SM: %s, MITM protection %u", sm_io_capabilities, sm_mitm_protection);
|
||||||
|
print_line("SM: key range [%u..16], OOB data: %s", sm_min_key_size,
|
||||||
|
sm_have_oob_data ? (sm_have_oob_data == 1 ? (const char*) sm_oob_data_A : (const char*) sm_oob_data_B) : "None");
|
||||||
|
print_line("Privacy %u", gap_privacy);
|
||||||
|
print_line("Device name: %s", gap_device_name);
|
||||||
|
|
||||||
|
printf_row("c/C - connectable off");
|
||||||
|
printf_row("d/D - bondable off/on");
|
||||||
|
printf_row("---");
|
||||||
|
printf_row("1 - enable privacy using random non-resolvable private address");
|
||||||
|
printf_row("2 - clear Peripheral Privacy Flag on PTS");
|
||||||
|
printf_row("3 - set Peripheral Privacy Flag on PTS");
|
||||||
|
printf_row("9 - create HCI Classic connection to addr %s", bd_addr_to_str(public_pts_address));
|
||||||
|
printf_row("s/S - passive/active scanning");
|
||||||
|
printf_row("a - enable Advertisements");
|
||||||
|
printf_row("b - start bonding");
|
||||||
|
printf_row("n - query GAP Device Name");
|
||||||
|
printf_row("o - set GAP Reconnection Address");
|
||||||
|
printf_row("t - terminate connection, stop connecting");
|
||||||
|
printf_row("p - auto connect to PTS");
|
||||||
|
printf_row("P - direct connect to PTS");
|
||||||
|
printf_row("w - signed write on characteristic with UUID %04x", pts_signed_write_characteristic_uuid);
|
||||||
|
printf_row("W - signed write on attribute with handle 0x%04x and value 0x12", pts_signed_write_characteristic_handle);
|
||||||
|
printf_row("z - Update L2CAP Connection Parameters");
|
||||||
|
printf_row("---");
|
||||||
|
printf_row("e - Discover all Primary Services");
|
||||||
|
printf_row("f/F - Discover Primary Service by UUID16/UUID128");
|
||||||
|
printf_row("g - Discover all characteristics by UUID16");
|
||||||
|
printf_row("h - Discover all characteristics in range");
|
||||||
|
printf_row("i - Find all included services");
|
||||||
|
printf_row("j/J - Read (Long) Characteristic Value by handle");
|
||||||
|
printf_row("k/K - Read Characteristic Value by UUID16/UUID128");
|
||||||
|
printf_row("l/L - Read (Long) Characteristic Descriptor by handle");
|
||||||
|
printf_row("N - Read Multiple Characteristic Values");
|
||||||
|
printf_row("O - Write without Response");
|
||||||
|
printf_row("q/Q - Write (Long) Characteristic Value");
|
||||||
|
printf_row("r - Characteristic Reliable Write");
|
||||||
|
printf_row("R - Signed Write");
|
||||||
|
printf_row("u/U - Write (Long) Characteristic Descriptor");
|
||||||
|
printf_row("T - Read Generic Profile Attributes by Type");
|
||||||
|
printf_row("---");
|
||||||
|
printf_row("4 - IO_CAPABILITY_DISPLAY_ONLY");
|
||||||
|
printf_row("5 - IO_CAPABILITY_DISPLAY_YES_NO");
|
||||||
|
printf_row("6 - IO_CAPABILITY_NO_INPUT_NO_OUTPUT");
|
||||||
|
printf_row("7 - IO_CAPABILITY_KEYBOARD_ONLY");
|
||||||
|
printf_row("8 - IO_CAPABILITY_KEYBOARD_DISPLAY");
|
||||||
|
printf_row("m/M - MITM protection off");
|
||||||
|
printf_row("x/X - encryption key range [7..16]/[16..16]");
|
||||||
|
printf_row("y/Y - OOB data off/on/toggle A/B");
|
||||||
|
printf_row("---");
|
||||||
|
printf_row("Ctrl-c - exit");
|
||||||
|
|
||||||
|
print_screen();
|
||||||
|
}
|
||||||
|
|
||||||
void update_auth_req(void){
|
void update_auth_req(void){
|
||||||
uint8_t auth_req = 0;
|
uint8_t auth_req = 0;
|
||||||
@ -654,12 +920,14 @@ static void ui_request_uint16(const char * message){
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
ui_uint16_request = 1;
|
ui_uint16_request = 1;
|
||||||
ui_uint16 = 0;
|
ui_uint16 = 0;
|
||||||
|
ui_uint16_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ui_request_uud128(const char * message){
|
static void ui_request_uud128(const char * message){
|
||||||
printf("%s", message);
|
printf("%s", message);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
ui_uuid128_request = 1;
|
ui_uuid128_request = 1;
|
||||||
|
ui_uuid128_pos = 0;
|
||||||
memset(ui_uuid128, 0, 16);
|
memset(ui_uuid128, 0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,7 +941,6 @@ static void ui_request_data(const char * message){
|
|||||||
|
|
||||||
static int ui_process_digits_for_passkey(char buffer){
|
static int ui_process_digits_for_passkey(char buffer){
|
||||||
if (buffer < '0' || buffer > '9') {
|
if (buffer < '0' || buffer > '9') {
|
||||||
printf("stdinprocess: invalid input 0x%02x\n", buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
printf("%c", buffer);
|
printf("%c", buffer);
|
||||||
@ -688,6 +955,15 @@ static int ui_process_digits_for_passkey(char buffer){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ui_process_uint16_request(char buffer){
|
static int ui_process_uint16_request(char buffer){
|
||||||
|
if (buffer == 0x7f || buffer == 0x08) {
|
||||||
|
if (ui_uint16_pos){
|
||||||
|
printf("\b \b");
|
||||||
|
fflush(stdout);
|
||||||
|
ui_uint16 >>= 4;
|
||||||
|
ui_uint16_pos--;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (buffer == '\n' || buffer == '\r'){
|
if (buffer == '\n' || buffer == '\r'){
|
||||||
ui_uint16_request = 0;
|
ui_uint16_request = 0;
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -696,6 +972,20 @@ static int ui_process_uint16_request(char buffer){
|
|||||||
printf("Discover Primary Services with UUID16 %04x\n", ui_uint16);
|
printf("Discover Primary Services with UUID16 %04x\n", ui_uint16);
|
||||||
gatt_client_discover_primary_services_by_uuid16(gc_id, handle, ui_uint16);
|
gatt_client_discover_primary_services_by_uuid16(gc_id, handle, ui_uint16);
|
||||||
return 0;
|
return 0;
|
||||||
|
case CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS:
|
||||||
|
ui_attribute_handle = ui_uint16;
|
||||||
|
ui_request_uint16("Please enter end handle: ");
|
||||||
|
central_state = CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS;
|
||||||
|
return 0;
|
||||||
|
case CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS: {
|
||||||
|
printf("Discover Characteristics from 0x%04x to 0x%04x\n", ui_attribute_handle, ui_uint16);
|
||||||
|
central_state = CENTRAL_W4_CHARACTERISTICS;
|
||||||
|
le_service_t service;
|
||||||
|
service.start_group_handle = ui_attribute_handle;
|
||||||
|
service.end_group_handle = ui_uint16;
|
||||||
|
gatt_client_discover_characteristics_for_service(gc_id, handle, &service);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case CENTRAL_W4_CHARACTERISTICS:
|
case CENTRAL_W4_CHARACTERISTICS:
|
||||||
printf("Discover Characteristics with UUID16 %04x\n", ui_uint16);
|
printf("Discover Characteristics with UUID16 %04x\n", ui_uint16);
|
||||||
gatt_client_discover_characteristics_for_handle_range_by_uuid16(gc_id, handle, 0x0001, 0xffff, ui_uint16);
|
gatt_client_discover_characteristics_for_handle_range_by_uuid16(gc_id, handle, 0x0001, 0xffff, ui_uint16);
|
||||||
@ -737,16 +1027,16 @@ static int ui_process_uint16_request(char buffer){
|
|||||||
return 0;
|
return 0;
|
||||||
case CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES:
|
case CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES:
|
||||||
if (ui_uint16){
|
if (ui_uint16){
|
||||||
ui_handles[ui_num_handles++] = ui_uint16;
|
ui_handles[ui_handles_count++] = ui_uint16;
|
||||||
ui_request_uint16("Please enter handle: ");
|
ui_request_uint16("Please enter handle: ");
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
printf("Read multiple values, handles: ");
|
printf("Read multiple values, handles: ");
|
||||||
for (i=0;i<ui_num_handles;i++){
|
for (i=0;i<ui_handles_count;i++){
|
||||||
printf("0x%04x, ", ui_handles[i]);
|
printf("0x%04x, ", ui_handles[i]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
gatt_client_read_multiple_characteristic_values(gc_id, handle, ui_num_handles, ui_handles);
|
gatt_client_read_multiple_characteristic_values(gc_id, handle, ui_handles_count, ui_handles);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -773,32 +1063,76 @@ static int ui_process_uint16_request(char buffer){
|
|||||||
ui_attribute_handle = ui_uint16;
|
ui_attribute_handle = ui_uint16;
|
||||||
ui_request_data("Please enter data: ");
|
ui_request_data("Please enter data: ");
|
||||||
return 0;
|
return 0;
|
||||||
|
case CENTRAL_GPA_ENTER_START_HANDLE:
|
||||||
|
ui_start_handle = ui_uint16;
|
||||||
|
central_state = CENTRAL_GPA_ENTER_END_HANDLE;
|
||||||
|
ui_request_uint16("Please enter end handle: ");
|
||||||
|
return 0;
|
||||||
|
case CENTRAL_GPA_ENTER_END_HANDLE:
|
||||||
|
ui_end_handle = ui_uint16;
|
||||||
|
central_state = CENTRAL_GPA_W4_RESPONSE;
|
||||||
|
ui_request_uint16("Please enter uuid: ");
|
||||||
|
return 0;
|
||||||
|
case CENTRAL_GPA_W4_RESPONSE:
|
||||||
|
ui_uuid16 = ui_uint16;
|
||||||
|
printf("Read by type: range 0x%04x-0x%04x, uuid %04x\n", ui_start_handle, ui_end_handle, ui_uuid16);
|
||||||
|
gatt_client_read_value_of_characteristics_by_uuid16(gc_id, handle, ui_start_handle, ui_end_handle, ui_uuid16);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int hex = hexForChar(buffer);
|
int hex = hexForChar(buffer);
|
||||||
if (hex < 0){
|
if (hex < 0){
|
||||||
printf("stdinprocess: invalid input 0x%02x\n", buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
printf("%c", buffer);
|
printf("%c", buffer);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
ui_uint16 = ui_uint16 << 4 | hex;
|
ui_uint16 = ui_uint16 << 4 | hex;
|
||||||
|
ui_uint16_pos++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uuid128_pos_starts_with_dash(int pos){
|
||||||
|
switch(pos){
|
||||||
|
case 8:
|
||||||
|
case 12:
|
||||||
|
case 16:
|
||||||
|
case 20:
|
||||||
|
#ifdef PTS_UUID128_REPRESENTATION
|
||||||
|
case 4:
|
||||||
|
case 24:
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ui_process_uuid128_request(char buffer){
|
static int ui_process_uuid128_request(char buffer){
|
||||||
if (buffer == '-') return 0; // skip -
|
if (buffer == '-') return 0; // skip -
|
||||||
|
|
||||||
|
if (buffer == 0x7f || buffer == 0x08) {
|
||||||
|
if (ui_uuid128_pos){
|
||||||
|
if (uuid128_pos_starts_with_dash(ui_uuid128_pos)){
|
||||||
|
printf("\b \b");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
printf("\b \b");
|
||||||
|
fflush(stdout);
|
||||||
|
ui_uuid128_pos--;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int hex = hexForChar(buffer);
|
int hex = hexForChar(buffer);
|
||||||
if (hex < 0){
|
if (hex < 0){
|
||||||
printf("stdinprocess: invalid input 0x%02x\n", buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
printf("%c", buffer);
|
printf("%c", buffer);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
if (ui_uuid128_pos & 1){
|
if (ui_uuid128_pos & 1){
|
||||||
ui_uuid128[ui_uuid128_pos >> 1] |= hex;
|
ui_uuid128[ui_uuid128_pos >> 1] = (ui_uuid128[ui_uuid128_pos >> 1] & 0xf0) | hex;
|
||||||
} else {
|
} else {
|
||||||
ui_uuid128[ui_uuid128_pos >> 1] = hex << 4;
|
ui_uuid128[ui_uuid128_pos >> 1] = hex << 4;
|
||||||
}
|
}
|
||||||
@ -823,19 +1157,11 @@ static int ui_process_uuid128_request(char buffer){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch(ui_uuid128_pos){
|
if (uuid128_pos_starts_with_dash(ui_uuid128_pos)){
|
||||||
case 8:
|
|
||||||
case 12:
|
|
||||||
case 16:
|
|
||||||
case 20:
|
|
||||||
printf("-");
|
printf("-");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ui_announce_write(const char * method){
|
static void ui_announce_write(const char * method){
|
||||||
@ -845,6 +1171,17 @@ static void ui_announce_write(const char * method){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ui_process_data_request(char buffer){
|
static int ui_process_data_request(char buffer){
|
||||||
|
if (buffer == 0x7f || buffer == 0x08) {
|
||||||
|
if (ui_value_pos){
|
||||||
|
if ((ui_value_pos & 1) == 0){
|
||||||
|
printf("\b");
|
||||||
|
}
|
||||||
|
printf("\b \b");
|
||||||
|
fflush(stdout);
|
||||||
|
ui_value_pos--;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (buffer == '\n' || buffer == '\r'){
|
if (buffer == '\n' || buffer == '\r'){
|
||||||
ui_value_request = 0;
|
ui_value_request = 0;
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -884,20 +1221,20 @@ static int ui_process_data_request(char buffer){
|
|||||||
}
|
}
|
||||||
int hex = hexForChar(buffer);
|
int hex = hexForChar(buffer);
|
||||||
if (hex < 0){
|
if (hex < 0){
|
||||||
printf("stdinprocess: invalid input 0x%02x\n", buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%c", buffer);
|
printf("%c", buffer);
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
if (ui_value_pos & 1){
|
if (ui_value_pos & 1){
|
||||||
ui_value_data[ui_value_pos >> 1] |= hex;
|
ui_value_data[ui_value_pos >> 1] = (ui_value_data[ui_value_pos >> 1] & 0xf0) | hex;
|
||||||
|
printf(" ");
|
||||||
} else {
|
} else {
|
||||||
ui_value_data[ui_value_pos >> 1] = hex << 4;
|
ui_value_data[ui_value_pos >> 1] = hex << 4;
|
||||||
}
|
}
|
||||||
ui_value_pos++;
|
ui_value_pos++;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,7 +1378,7 @@ static void ui_process_command(char buffer){
|
|||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
// fetch csrk
|
// fetch csrk
|
||||||
le_device_db_csrk_get(le_device_db_index, signing_csrk);
|
le_device_db_local_csrk_get(le_device_db_index, signing_csrk);
|
||||||
// calc signature
|
// calc signature
|
||||||
sm_cmac_start(signing_csrk, ATT_SIGNED_WRITE_COMMAND, pts_signed_write_characteristic_handle, sizeof(signed_write_value), signed_write_value, 0, att_signed_write_handle_cmac_result);
|
sm_cmac_start(signing_csrk, ATT_SIGNED_WRITE_COMMAND, pts_signed_write_characteristic_handle, sizeof(signed_write_value), signed_write_value, 0, att_signed_write_handle_cmac_result);
|
||||||
break;
|
break;
|
||||||
@ -1094,6 +1431,10 @@ static void ui_process_command(char buffer){
|
|||||||
gatt_client_discover_characteristics_for_service(gc_id, handle, &service);
|
gatt_client_discover_characteristics_for_service(gc_id, handle, &service);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'h':
|
||||||
|
central_state = CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS;
|
||||||
|
ui_request_uint16("Please enter start_handle: ");
|
||||||
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
central_state = CENTRAL_W4_CHARACTERISTICS;
|
central_state = CENTRAL_W4_CHARACTERISTICS;
|
||||||
@ -1129,7 +1470,7 @@ static void ui_process_command(char buffer){
|
|||||||
break;
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
ui_request_uint16("Read Multiple Characteristic Values - enter 0 to complete list.\nPlease enter handle: ");
|
ui_request_uint16("Read Multiple Characteristic Values - enter 0 to complete list.\nPlease enter handle: ");
|
||||||
ui_num_handles = 0;
|
ui_handles_count = 0;
|
||||||
central_state = CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES;
|
central_state = CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES;
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
@ -1160,6 +1501,10 @@ static void ui_process_command(char buffer){
|
|||||||
central_state = CENTRAL_W4_SIGNED_WRITE;
|
central_state = CENTRAL_W4_SIGNED_WRITE;
|
||||||
ui_request_uint16("Please enter handle: ");
|
ui_request_uint16("Please enter handle: ");
|
||||||
break;
|
break;
|
||||||
|
case 'T':
|
||||||
|
central_state = CENTRAL_GPA_ENTER_START_HANDLE;
|
||||||
|
ui_request_uint16("Please enter start handle: ");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
show_usage();
|
show_usage();
|
||||||
break;
|
break;
|
||||||
@ -1237,6 +1582,9 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
|
|
||||||
printf("BTstack LE Peripheral starting up...\n");
|
printf("BTstack LE Peripheral starting up...\n");
|
||||||
|
|
||||||
|
memset(rows, 0, sizeof(char *) * 100);
|
||||||
|
memset(lines, 0, sizeof(char *) * 100);
|
||||||
|
|
||||||
strcpy(gap_device_name, "BTstack");
|
strcpy(gap_device_name, "BTstack");
|
||||||
|
|
||||||
// set up l2cap_le
|
// set up l2cap_le
|
||||||
@ -1252,6 +1600,7 @@ int btstack_main(int argc, const char * argv[]){
|
|||||||
|
|
||||||
sm_set_encryption_key_size_range(sm_min_key_size, 16);
|
sm_set_encryption_key_size_range(sm_min_key_size, 16);
|
||||||
sm_test_set_irk(test_irk);
|
sm_test_set_irk(test_irk);
|
||||||
|
sm_test_use_fixed_local_csrk();
|
||||||
|
|
||||||
// setup GATT Client
|
// setup GATT Client
|
||||||
gatt_client_init();
|
gatt_client_init();
|
||||||
|
@ -14,6 +14,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
|||||||
|
|
||||||
FS = \
|
FS = \
|
||||||
utils.c \
|
utils.c \
|
||||||
|
hci_dump.c \
|
||||||
remote_device_db_fs.c
|
remote_device_db_fs.c
|
||||||
|
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ MEMORY = \
|
|||||||
utils.c \
|
utils.c \
|
||||||
memory_pool.c \
|
memory_pool.c \
|
||||||
btstack_memory.c \
|
btstack_memory.c \
|
||||||
|
hci_dump.c \
|
||||||
remote_device_db_memory.c \
|
remote_device_db_memory.c \
|
||||||
linked_list.c
|
linked_list.c
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
|
|||||||
COMMON = \
|
COMMON = \
|
||||||
sdp_util.c \
|
sdp_util.c \
|
||||||
sdp_parser.c \
|
sdp_parser.c \
|
||||||
|
hci_dump.c \
|
||||||
utils.c \
|
utils.c \
|
||||||
|
|
||||||
COMMON_OBJ = $(COMMON:.c=.o)
|
COMMON_OBJ = $(COMMON:.c=.o)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user