This commit is contained in:
Milanka Ringwald 2015-10-23 22:39:45 +02:00
commit 588953c14f
23 changed files with 841 additions and 192 deletions

View File

@ -104,7 +104,8 @@ extern "C" {
#define ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0f
#define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
#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
@ -143,7 +144,12 @@ extern "C" {
#define GATT_SECONDARY_SERVICE_UUID 0x2801
#define GATT_INCLUDE_SERVICE_UUID 0x2802
#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_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_NOTIFICATION 1

View File

@ -267,7 +267,7 @@ static void att_run(void){
// signature is { sequence counter, secure hash }
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;
log_info("Orig Signature: ");
hexdump( &att_request_buffer[att_request_size-8], 8);

View File

@ -62,6 +62,7 @@
static linked_list_t gatt_client_connections = NULL;
static linked_list_t gatt_subclients = NULL;
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_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){
gatt_client_connections = NULL;
pts_suppress_mtu_exchange = 0;
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();
if (!context) return NULL;
// init state
memset(context, 0, sizeof(gatt_client_t));
context->handle = con_handle;
context->mtu = ATT_DEFAULT_MTU;
context->mtu_state = SEND_MTU_EXCHANGE;
context->gatt_client_state = P_READY;
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;
}
@ -489,6 +497,15 @@ static void emit_event(uint16_t gatt_client_id, le_event_t* 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){
gatt_complete_event_t event;
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);
}
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){
le_characteristic_value_event_t event;
event.type = event_type;
event.handle = peripheral->handle;
event.value_handle = value_handle;
event.value_offset = offset;
event.blob_length = length;
event.blob = value;
setup_characteristic_value_event(&event, peripheral->handle, value_handle, value, length, offset, event_type);
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);
}
static void report_gatt_notification(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, int length){
send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_NOTIFICATION);
static void report_gatt_notification(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
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){
send_characteristic_value_event(peripheral, handle, value, length, 0, GATT_INDICATION);
static void report_gatt_indication(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
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){
@ -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){
if (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 int is_query_done(gatt_client_t * peripheral, uint16_t last_result_handle){
return last_result_handle >= peripheral->end_group_handle;
}
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){
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){
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);
}
@ -905,7 +937,7 @@ static void gatt_client_run(void){
case P_W4_CMAC_READY:
if (sm_cmac_ready()){
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);
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);
@ -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) {
if (is_ready(peripheral)) return;
gatt_client_handle_transaction_complete(peripheral);
@ -981,8 +1004,21 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
}
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;
switch (packet[0]){
@ -1006,12 +1042,8 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
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:
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;
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:
report_gatt_characteristics(peripheral, 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;
case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
report_gatt_characteristics(peripheral, 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;
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);
}
void gatt_client_pts_suppress_mtu_exchange(void){
pts_suppress_mtu_exchange = 1;
}

View File

@ -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);
/* API_END */
// only used for testing
void gatt_client_pts_suppress_mtu_exchange();
#if defined __cplusplus
}
#endif

View File

@ -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);
/**
* @brief set signing key for this device
* @brief set local signing key for this device
* @param index
* @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 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

View File

@ -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){}
// 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
uint32_t le_device_db_remote_counter_get(int index){

View File

@ -59,10 +59,11 @@ typedef struct le_device_memory_db {
uint8_t authorized;
// Signed Writes by remote
sm_key_t csrk;
sm_key_t remote_csrk;
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;
} 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
void le_device_db_csrk_get(int index, sm_key_t csrk){
if (csrk) memcpy(csrk, le_devices[index].csrk, 16);
void le_device_db_remote_csrk_get(int index, sm_key_t csrk){
if (csrk) memcpy(csrk, le_devices[index].remote_csrk, 16);
}
void le_device_db_csrk_set(int index, sm_key_t csrk){
if (csrk) memcpy(le_devices[index].csrk, csrk, 16);
void le_device_db_remote_csrk_set(int index, sm_key_t csrk){
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
@ -185,6 +194,7 @@ void le_device_db_dump(void){
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_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);
}
}

View File

@ -117,6 +117,8 @@ typedef enum {
// GLOBAL DATA
//
static uint8_t test_use_fixed_local_csrk;
// configuration
static uint8_t sm_accepted_stk_generation_methods;
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
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
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);
}
@ -1505,16 +1507,15 @@ static void sm_run(void){
if (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];
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");
le_device_db_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk);
}
log_info("sm: store local CSRK");
le_device_db_local_csrk_set(connection->sm_le_db_index, setup->sm_local_csrk);
swap128(setup->sm_local_csrk, &buffer[1]);
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
@ -2286,6 +2287,10 @@ void sm_test_set_irk(sm_key_t irk){
sm_persistent_irk_ready = 1;
}
void sm_test_use_fixed_local_csrk(void){
test_use_fixed_local_csrk = 1;
}
void sm_init(void){
// set some (BTstack default) ER and IR
int i;
@ -2317,6 +2322,8 @@ void sm_init(void){
sm_active_connection = 0;
test_use_fixed_local_csrk = 0;
// attach to lower layers
l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
}

View File

@ -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 );
/* API_END */
// testing only
void sm_test_use_fixed_local_csrk(void);
#if defined __cplusplus
}
#endif

27
platforms/posix-h4/.gitignore vendored Normal file
View 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

View 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}

View 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
View 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;
}

View File

@ -85,6 +85,7 @@ static void hci_connection_timestamp(hci_connection_t *connection);
static int hci_power_control_on(void);
static void hci_power_control_off(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
#ifndef HAVE_MALLOC
@ -1573,27 +1574,35 @@ static void event_handler(uint8_t *packet, int size){
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));
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]){
// outgoing connection establishment is done
hci_stack->le_connecting_state = LE_CONNECTING_IDLE;
// remove entry
if (conn){
// outgoing connection failed, remove entry
linked_list_remove(&hci_stack->connections, (linked_item_t *) 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;
}
if (!conn){
// advertisemts are stopped on incoming connection
// on success, both hosts receive connection complete event
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;
// 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);
}
// no memory, sorry.
if (!conn){
// no memory
break;
}
@ -2204,9 +2213,12 @@ void hci_run(void){
}
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);
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;
}
}
@ -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_todo |= LE_ADVERTISEMENT_TASKS_SET_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_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;
// 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_run();
@ -3214,13 +3226,7 @@ int gap_auto_connection_start(bd_addr_type_t address_type, bd_addr_t address){
return 0;
}
/**
* @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){
static void hci_remove_from_whitelist(bd_addr_type_t address_type, bd_addr_t address){
linked_list_iterator_t it;
linked_list_iterator_init(&it, &hci_stack->le_whitelist);
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);
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();
return 0;
}

View File

@ -12,24 +12,23 @@ SUBDIRS = \
sdp_client \
security_manager \
# security_manager \
EXCLUDED = ios
subdirs:
echo Building all tests
@set -e; \
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
clean:
echo Clean all test
@set -e; \
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done
test:
echo Run all test
@set -e; \
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir test; \
done

View File

@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
COMMON = \
utils.c \
hci_dump.c \
att_db_util.c \
COMMON_OBJ = $(COMMON:.c=.o)

View File

@ -13,6 +13,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
COMMON = \
sdp_util.c \
hci_dump.c \
utils.c
COMMON_OBJ = $(COMMON:.c=.o)

View File

@ -32,7 +32,7 @@ const uint8_t included_services_uuid128_handles[][2] = {
uint8_t characteristic_handles[][2]= {
{0x26, 0x2a}, {0x2b, 0x2f}, {0x30, 0x32}, {0x33, 0x35}, {0x36, 0x38},
{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] = {
@ -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, 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, 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};

View File

@ -128,7 +128,7 @@ static void verify_included_services_uuid128(void){
}
static void verify_charasteristics(void){
CHECK_EQUAL(14, result_index);
CHECK_EQUAL(15, result_index);
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);
}

View File

@ -116,7 +116,7 @@ int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t l
int sm_cmac_ready(void){
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);
}
int sm_le_device_index(uint16_t handle ){

View File

@ -70,6 +70,7 @@
// Non standard IXIT
#define PTS_USES_RECONNECTION_ADDRESS_FOR_ITSELF
#define PTS_UUID128_REPRESENTATION
typedef enum {
CENTRAL_IDLE,
@ -79,6 +80,8 @@ typedef enum {
CENTRAL_W4_PERIPHERAL_PRIVACY_FLAG_QUERY_COMPLETE,
CENTRAL_W4_SIGNED_WRITE_QUERY_COMPLETE,
CENTRAL_W4_PRIMARY_SERVICES,
CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS,
CENTRAL_ENTER_END_HANDLE_4_DISCOVER_CHARACTERISTICS,
CENTRAL_W4_CHARACTERISTICS,
CENTRAL_W4_READ_CHARACTERISTIC_VALUE_BY_HANDLE,
CENTRAL_ENTER_HANDLE_4_READ_CHARACTERISTIC_VALUE_BY_UUID,
@ -98,6 +101,13 @@ typedef enum {
CENTRAL_ENTER_HANDLE_4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
CENTRAL_W4_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR,
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;
typedef struct advertising_report {
@ -110,6 +120,19 @@ typedef struct advertising_report {
uint8_t * data;
} 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 int gap_privacy = 0;
@ -129,19 +152,25 @@ static int peer_addr_type;
static bd_addr_t peer_address;
static int ui_passkey = 0;
static int ui_digits_for_passkey = 0;
static int ui_uint16_request = 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_uuid128_request = 0;
static int ui_uuid128_pos = 0;
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_attribute_handle;
static int ui_attribute_offset;
static int ui_value_request = 0;
static uint8_t ui_value_data[50];
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 gc_id;
@ -153,7 +182,7 @@ static int reconnection_address_set = 0;
static bd_addr_t our_private_address;
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 int le_device_db_index;
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_application = "Application Error";
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){
if (code >= 0xe0) return att_error_common_error;
if (code >= 0xa0) return att_error_reserved;
if (code >= 0x80) return att_error_application;
if (code == 0x7f) return att_error_timeout;
if (code >= 0x12) return att_error_reserved;
return att_errors[code];
}
@ -391,6 +422,7 @@ void use_public_pts_address(void){
void handle_gatt_client_event(le_event_t * event){
le_characteristic_value_event_t * value;
le_characteristic_event_t * characteristic_event;
uint8_t address_type;
bd_addr_t flipped_address;
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);
break;
case GATT_CHARACTERISTIC_QUERY_RESULT:
characteristic_event = ((le_characteristic_event_t *) event);
switch (central_state) {
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);
break;
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);
break;
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);
break;
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);
break;
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;
default:
break;
@ -453,7 +501,80 @@ void handle_gatt_client_event(le_event_t * event){
printf("Value: ");
printf_hexdump(value->blob, value->blob_length);
break;
default:
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:
break;
}
break;
@ -465,8 +586,32 @@ void handle_gatt_client_event(le_event_t * event){
break;
case GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
printf("Value: ");
printf_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length);
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_hexdump(characteristic_descriptor_event->value, characteristic_descriptor_event->value_length);
break;
}
break;
case GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT:
characteristic_descriptor_event = (le_characteristic_descriptor_event_t *) event;
@ -523,11 +668,70 @@ void handle_gatt_client_event(le_event_t * event){
printf("Primary Service Discovery complete\n");
central_state = CENTRAL_IDLE;
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:
central_state = CENTRAL_IDLE;
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:
break;
}
@ -537,81 +741,143 @@ uint16_t value_handle = 1;
uint16_t attribute_size = 1;
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){
uint8_t iut_address_type;
bd_addr_t iut_address;
hci_le_advertisement_address(&iut_address_type, iut_address);
printf("\e[1;1H\e[2J");
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");
}
reset_screen();
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){
uint8_t auth_req = 0;
@ -654,12 +920,14 @@ static void ui_request_uint16(const char * message){
fflush(stdout);
ui_uint16_request = 1;
ui_uint16 = 0;
ui_uint16_pos = 0;
}
static void ui_request_uud128(const char * message){
printf("%s", message);
fflush(stdout);
ui_uuid128_request = 1;
ui_uuid128_pos = 0;
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){
if (buffer < '0' || buffer > '9') {
printf("stdinprocess: invalid input 0x%02x\n", buffer);
return 0;
}
printf("%c", buffer);
@ -688,6 +955,15 @@ static int ui_process_digits_for_passkey(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'){
ui_uint16_request = 0;
printf("\n");
@ -696,6 +972,20 @@ static int ui_process_uint16_request(char buffer){
printf("Discover Primary Services with UUID16 %04x\n", ui_uint16);
gatt_client_discover_primary_services_by_uuid16(gc_id, handle, ui_uint16);
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:
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);
@ -737,16 +1027,16 @@ static int ui_process_uint16_request(char buffer){
return 0;
case CENTRAL_W4_READ_MULTIPLE_CHARACTERISTIC_VALUES:
if (ui_uint16){
ui_handles[ui_num_handles++] = ui_uint16;
ui_handles[ui_handles_count++] = ui_uint16;
ui_request_uint16("Please enter handle: ");
} else {
int i;
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("\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;
@ -773,32 +1063,76 @@ static int ui_process_uint16_request(char buffer){
ui_attribute_handle = ui_uint16;
ui_request_data("Please enter data: ");
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:
return 0;
}
}
int hex = hexForChar(buffer);
if (hex < 0){
printf("stdinprocess: invalid input 0x%02x\n", buffer);
return 0;
}
printf("%c", buffer);
fflush(stdout);
ui_uint16 = ui_uint16 << 4 | hex;
ui_uint16_pos++;
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){
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);
if (hex < 0){
printf("stdinprocess: invalid input 0x%02x\n", buffer);
return 0;
}
printf("%c", buffer);
fflush(stdout);
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 {
ui_uuid128[ui_uuid128_pos >> 1] = hex << 4;
}
@ -823,19 +1157,11 @@ static int ui_process_uuid128_request(char buffer){
return 0;
}
}
switch(ui_uuid128_pos){
case 8:
case 12:
case 16:
case 20:
printf("-");
fflush(stdout);
break;
default:
break;
if (uuid128_pos_starts_with_dash(ui_uuid128_pos)){
printf("-");
fflush(stdout);
}
return 0;
}
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){
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'){
ui_value_request = 0;
printf("\n");
@ -884,20 +1221,20 @@ static int ui_process_data_request(char buffer){
}
int hex = hexForChar(buffer);
if (hex < 0){
printf("stdinprocess: invalid input 0x%02x\n", buffer);
return 0;
}
printf("%c", buffer);
fflush(stdout);
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 {
ui_value_data[ui_value_pos >> 1] = hex << 4;
}
ui_value_pos++;
fflush(stdout);
return 0;
}
@ -1041,7 +1378,7 @@ static void ui_process_command(char buffer){
break;
case 'W':
// 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
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;
@ -1094,6 +1431,10 @@ static void ui_process_command(char buffer){
gatt_client_discover_characteristics_for_service(gc_id, handle, &service);
break;
}
case 'h':
central_state = CENTRAL_ENTER_START_HANDLE_4_DISCOVER_CHARACTERISTICS;
ui_request_uint16("Please enter start_handle: ");
break;
case 'i':
{
central_state = CENTRAL_W4_CHARACTERISTICS;
@ -1129,7 +1470,7 @@ static void ui_process_command(char buffer){
break;
case 'N':
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;
break;
case 'O':
@ -1160,6 +1501,10 @@ static void ui_process_command(char buffer){
central_state = CENTRAL_W4_SIGNED_WRITE;
ui_request_uint16("Please enter handle: ");
break;
case 'T':
central_state = CENTRAL_GPA_ENTER_START_HANDLE;
ui_request_uint16("Please enter start handle: ");
break;
default:
show_usage();
break;
@ -1237,6 +1582,9 @@ int btstack_main(int argc, const char * argv[]){
printf("BTstack LE Peripheral starting up...\n");
memset(rows, 0, sizeof(char *) * 100);
memset(lines, 0, sizeof(char *) * 100);
strcpy(gap_device_name, "BTstack");
// 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_test_set_irk(test_irk);
sm_test_use_fixed_local_csrk();
// setup GATT Client
gatt_client_init();

View File

@ -14,6 +14,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
FS = \
utils.c \
hci_dump.c \
remote_device_db_fs.c
@ -21,6 +22,7 @@ MEMORY = \
utils.c \
memory_pool.c \
btstack_memory.c \
hci_dump.c \
remote_device_db_memory.c \
linked_list.c

View File

@ -16,6 +16,7 @@ VPATH += ${BTSTACK_ROOT}/platforms/posix/src
COMMON = \
sdp_util.c \
sdp_parser.c \
hci_dump.c \
utils.c \
COMMON_OBJ = $(COMMON:.c=.o)