Merge branch 'develop' into a2dp

This commit is contained in:
Matthias Ringwald 2016-08-24 13:45:38 +02:00
commit 8cff923e81
70 changed files with 1428 additions and 426 deletions

View File

@ -2456,7 +2456,8 @@ void sm_mbedtls_allocator_free(void * data);
/* ECP options */
//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */
#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */
#define MBEDTLS_ECP_WINDOW_SIZE 1 /**< Maximum window size used - 1 == uses double and add to save RAM */
#define MBEDTLS_ECP_MUL_NAIVE_SAFE 0 /**< Enable use of temporary point for window size == 1 - adds ~100 bytes but makes branches independ from n */
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */
/* Entropy options */

View File

@ -728,6 +728,25 @@ cleanup:
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) )
#if defined(ECP_SHORTWEIERSTRASS)
/*
* Check and define parameters used by the comb method (see below for details)
*/
#if MBEDTLS_ECP_WINDOW_SIZE > 7
#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
#endif
#if MBEDTLS_ECP_WINDOW_SIZE >= 2
#define ECP_COMB_METHOD
/* d = ceil( n / w ) */
#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2
/* number of precomputed points */
#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
#endif
/*
* For curves in short Weierstrass form, we do all the internal operations in
* Jacobian coordinates.
@ -775,6 +794,7 @@ cleanup:
return( ret );
}
#ifdef ECP_COMB_METHOD
/*
* Normalize jacobian coordinates of an array of (pointers to) points,
* using Montgomery's trick to perform only one inversion mod P.
@ -887,6 +907,7 @@ cleanup:
return( ret );
}
#endif
/*
* Point doubling R = 2 P, Jacobian coordinates
@ -1068,6 +1089,8 @@ cleanup:
return( ret );
}
#ifdef ECP_COMB_METHOD
/*
* Randomize jacobian coordinates:
* (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l
@ -1115,19 +1138,6 @@ cleanup:
return( ret );
}
/*
* Check and define parameters used by the comb method (see below for details)
*/
#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7
#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
#endif
/* d = ceil( n / w ) */
#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2
/* number of precomputed points */
#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
/*
* Compute the representation of m that will be used with our comb method.
*
@ -1422,6 +1432,63 @@ cleanup:
return( ret );
}
#else /* ECP_COMB_METHOD */
/*
* Multiplication using the double and add method,
* for curves in short Weierstrass form to optimize for RAM usage vs. speed
*
* Implemented by BlueKitchen GmbH
* Note:
*/
static int ecp_mul_naive( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
int i;
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
mbedtls_ecp_point T;
mbedtls_ecp_point_init(&T);
#endif
// calculate m * p using double and add in decreasing fashion to use ecp_add_mixed
mbedtls_ecp_point_init(R);
for (i=(int)grp->nbits;i >= 0;i--){
MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) );
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
MBEDTLS_MPI_CHK( ecp_add_mixed(grp, &T, R, P) );
int bit_set = mbedtls_mpi_get_bit(m, i);
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->X, &T.X, bit_set));
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->Y, &T.Y, bit_set));
MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign(&R->Y, &T.Y, bit_set));
#else
if (mbedtls_mpi_get_bit(m, i)){
MBEDTLS_MPI_CHK( ecp_add_mixed(grp, R, R, P) );
}
#endif
}
// normalize jacobian coordinates
MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
cleanup:
#if MBEDTLS_ECP_MUL_NAIVE_SAFE == 1
mbedtls_ecp_point_free(&T);
#endif
if( ret != 0 )
mbedtls_ecp_point_free( R );
return( ret );
}
#endif /* ECP_COMB_METHOD */
#endif /* ECP_SHORTWEIERSTRASS */
#if defined(ECP_MONTGOMERY)
@ -1612,8 +1679,8 @@ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
int ret;
int ret;
/* Common sanity checks */
if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
@ -1628,7 +1695,11 @@ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
#endif
#if defined(ECP_SHORTWEIERSTRASS)
if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
#ifdef ECP_COMB_METHOD
return( ecp_mul_comb( grp, R, m, P, f_rng, p_rng ) );
#else
return( ecp_mul_naive( grp, R, m, P, f_rng, p_rng ) );
#endif
#endif
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}

View File

@ -40,7 +40,7 @@
#include <string.h>
#include "ant_cmds.h"
#include "ant_cmd.h"
#include "classic/sdp_util.h"
#include "btstack_config.h"
#include "hci.h"

View File

@ -112,10 +112,12 @@ static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buf
hci_cmd_buffer[6] = 0;
}
#if 0
static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){
hci_cmd_buffer[0] = 0x06;
hci_cmd_buffer[1] = 0xFC;
hci_cmd_buffer[2] = 0x06;
reverse_bd_addr(addr, &hci_cmd_buffer[3]);
}
#endif
// Output Power control from: http://e2e.ti.com/support/low_power_rf/f/660/p/134853/484767.aspx
#define NUM_POWER_LEVELS 16
@ -284,7 +286,7 @@ static const btstack_chipset_t btstack_chipset_cc256x = {
chipset_init,
chipset_next_command,
chipset_set_baudrate_command,
NULL, // set bd addr command not available or impemented
chipset_set_bd_addr_command,
};
const btstack_chipset_t * btstack_chipset_cc256x_instance(void){

View File

@ -19,9 +19,9 @@ that is necessary to setup BTstack. From the point when the run loop
is executed, the application runs as a finite
state machine, which processes events received from BTstack. BTstack
groups events logically and provides them via packet handlers.
We provide their overview here, and finally, for the case that there is a need to inspect the data exchanged
We provide their overview here. For the case that there is a need to inspect the data exchanged
between BTstack and the Bluetooth chipset, we describe how to configure
packet logging mechanism.
packet logging mechanism. Finally, we provide an overview on power management in Bluetooth in general and how to save energy in BTstack.
## Configuration in btstack_config.h {#sec:btstackConfigHowTo}
@ -477,3 +477,49 @@ In addition to the HCI packets, you can also enable BTstack's debug information
to the btstack_config.h and recompiling your application.
## Bluetooth Power Control {#sec:powerControl}
In most BTstack examples, the device is set to be discoverable and connectable. In this mode, even when there's no active connection, the Bluetooth Controller will periodicaly activate its receiver in order to listen for inquiries or connecting requests from another device.
The ability to be discoverable requires more energy than the ability to be connected. Being discoverable also announces the device to anybody in the area. Therefore, it is a good idea to pause listening for inquiries when not needed. Other devices that have your Bluetooth address can still connect to your device.
To enable/disable discoverabilty, you can call:
/**
* @brief Allows to control if device is discoverable. OFF by default.
*/
void gap_discoverable_control(uint8_t enable);
If you don't need to become connected from other devices for a longer period of time, you can also disable the listening to connection requests.
To enable/disable connectability, you can call:
/**
* @brief Override page scan mode. Page scan mode enabled by l2cap when services are registered
* @note Might be used to reduce power consumption while Bluetooth module stays powered but no (new)
* connections are expected
*/
void gap_connectable_control(uint8_t enable);
For Bluetooth Low Energy, the radio is periodically used to broadcast advertisements that are used for both discovery and connection establishment.
To enable/disable advertisements, you can call:
/**
* @brief Enable/Disable Advertisements. OFF by default.
* @param enabled
*/
void gap_advertisements_enable(int enabled);
If a Bluetooth Controller is neither discoverable nor conectable, it does not need to periodically turn on its radio and it only needs to respond to commands from the Host. In this case, the Bluetooth Controller is free to enter some kind of deep sleep where the power consumption is minimal.
Finally, if that's not sufficient for your application, you could request BTstack to shutdown the Bluetooth Controller. For this, the "on" and "off" functions in the btstack_control_t struct must be implemented. To shutdown the Bluetooth Controller, you can call:
/**
* @brief Requests the change of BTstack power mode.
*/
int hci_power_control(HCI_POWER_MODE mode);
with mode set to *HCI_POWER_OFF*. When needed later, Bluetooth can be started again via by calling it with mode *HCI_POWER_ON*, as seen in all examples.

View File

@ -877,6 +877,12 @@ After the bonding process, *SM_EVENT_JUST_WORKS_CANCEL*, *SM_EVENT_PASSKEY_DISPL
As part of Bluetooth Core V4.2 specification, a device with a keyboard but no display can send keypress notifications to provide better user feedback. In BTstack, the *sm_keypress_notification()* function is used for sending notifcations. Notifications are received by BTstack via the *SM_EVENT_KEYPRESS_NOTIFICATION* event.
### Cross-transport Key Derivation for LE Secure Connections
In a dual-mode configuration, BTstack automatically generates an BR/EDR Link Key from the LE LTK via the Link Key Conversion function *h6*. It is then stored in the link key db.
To derive an LE LTK from a BR/EDR link key, the Bluetooth controller needs to support Secure Connections via NIST P-256 elliptic curves and the LE Secure Connections needs to get established via the LE Transport. BTstack does not support LE Secure Connections via LE Transport currently.
### Out-of-Band Data with LE Legacy Pairing
LE Legacy Pairing can be made secure by providing a way for both devices

View File

@ -55,7 +55,6 @@ GATT_CLIENT += \
SM_REAL += \
sm.c \
le_device_db_memory.c \
PAN += \
pan.c \
@ -213,7 +212,6 @@ hfp_hf_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} ${SBC_DECODER_OBJ} ${SBC_EN
clean:
rm -f ${EXAMPLES}
rm -f ${EXAMPLES_USING_LE}
rm -f *.o *.out *.hex *.exe
rm -f ancs_client_demo.h profile.h spp_and_le_counter.h
rm -rf *.dSYM

View File

@ -1012,7 +1012,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
case L2CAP_DECLINE_CONNECTION:
cid = little_endian_read_16(packet, 3);
reason = packet[7];
l2cap_decline_connection(cid, reason);
l2cap_decline_connection(cid);
break;
case RFCOMM_CREATE_CHANNEL:
reverse_bd_addr(&packet[3], addr);

View File

@ -145,7 +145,7 @@ OPCODE(OGF_BTSTACK, L2CAP_ACCEPT_CONNECTION), "2"
/**
* @param source_cid (16)
* @param reason
* @param reason (deprecated)
*/
const hci_cmd_t l2cap_decline_connection_cmd = {
OPCODE(OGF_BTSTACK, L2CAP_DECLINE_CONNECTION), "21"

View File

@ -136,7 +136,7 @@ static void btstack_run_loop_posix_disable_data_source_callbacks(btstack_data_so
static uint32_t btstack_run_loop_posix_get_time_ms(void){
struct timeval tv;
gettimeofday(&tv, NULL);
uint32_t time_ms = ((tv.tv_sec - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
uint32_t time_ms = (uint32_t)((tv.tv_sec - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
log_debug("btstack_run_loop_posix_get_time_ms: %u <- %u / %u", time_ms, (int) tv.tv_sec, (int) tv.tv_usec);
return time_ms;
}
@ -190,7 +190,7 @@ static void btstack_run_loop_posix_execute(void) {
delta = 0;
}
tv.tv_sec = delta / 1000;
tv.tv_usec = (delta - (tv.tv_sec * 1000)) * 1000;
tv.tv_usec = (int) (delta - (tv.tv_sec * 1000)) * 1000;
log_debug("btstack_run_loop_execute next timeout in %u ms", delta);
}

View File

@ -81,7 +81,7 @@ static void btstack_uart_posix_process_write(btstack_data_source_t *ds) {
uint32_t start = btstack_run_loop_get_time_ms();
// write up to write_bytes_len to fd
int bytes_written = write(ds->fd, write_bytes_data, write_bytes_len);
int bytes_written = (int) write(ds->fd, write_bytes_data, write_bytes_len);
if (bytes_written < 0) {
btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
return;

View File

@ -0,0 +1,382 @@
/*
* 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
*
*/
#include "ble/le_device_db.h"
#include "ble/core.h"
#include <stdio.h>
#include <string.h>
#include "btstack_debug.h"
// Central Device db implemenation using static memory
typedef struct le_device_memory_db {
// Identification
int addr_type;
bd_addr_t addr;
sm_key_t irk;
// Stored pairing information allows to re-establish an enncrypted connection
// with a peripheral that doesn't have any persistent memory
sm_key_t ltk;
uint16_t ediv;
uint8_t rand[8];
uint8_t key_size;
uint8_t authenticated;
uint8_t authorized;
// Signed Writes by remote
sm_key_t remote_csrk;
uint32_t remote_counter;
// Signed Writes by us
sm_key_t local_csrk;
uint32_t local_counter;
} le_device_memory_db_t;
#define LE_DEVICE_MEMORY_SIZE 20
#define INVALID_ENTRY_ADDR_TYPE 0xff
#define DB_PATH_TEMPLATE "/tmp/btstack_at_%s_le_device_db.txt"
const char * csv_header = "# addr_type, addr, irk, ltk, ediv, rand[8], key_size, authenticated, authorized, remote_csrk, remote_counter, local_csrk, local_counter";
static char db_path[sizeof(DB_PATH_TEMPLATE) - 2 + 17 + 1];
static le_device_memory_db_t le_devices[LE_DEVICE_MEMORY_SIZE];
static char bd_addr_to_dash_str_buffer[6*3]; // 12-45-78-01-34-67\0
static char * bd_addr_to_dash_str(bd_addr_t addr){
char * p = bd_addr_to_dash_str_buffer;
int i;
for (i = 0; i < 6 ; i++) {
*p++ = char_for_nibble((addr[i] >> 4) & 0x0F);
*p++ = char_for_nibble((addr[i] >> 0) & 0x0F);
*p++ = '-';
}
*--p = 0;
return (char *) bd_addr_to_dash_str_buffer;
}
static inline void write_delimiter(FILE * wFile){
fwrite(", ", 1, 1, wFile);
}
static inline void write_hex_byte(FILE * wFile, uint8_t value){
char buffer[2];
buffer[0] = char_for_nibble(value >> 4);
buffer[1] = char_for_nibble(value & 0x0f);
fwrite(buffer, 2, 1, wFile);
}
static inline void write_str(FILE * wFile, const char * str){
fwrite(str, strlen(str), 1, wFile);
write_delimiter(wFile);
}
static void write_hex(FILE * wFile, const uint8_t * value, int len){
int i;
for (i = 0; i < len; i++){
write_hex_byte(wFile, value[i]);
}
write_delimiter(wFile);
}
static void write_value(FILE * wFile, uint32_t value, int len){
switch (len){
case 4:
write_hex_byte(wFile, value >> 24);
case 3:
write_hex_byte(wFile, value >> 16);
case 2:
write_hex_byte(wFile, value >> 8);
case 1:
default:
write_hex_byte(wFile, value);
}
write_delimiter(wFile);
}
static void le_device_db_store(void) {
int i;
// open file
FILE * wFile = fopen(db_path,"w+");
if (wFile == NULL) return;
fwrite(csv_header, strlen(csv_header), 1, wFile);
fwrite("\n", 1, 1, wFile);
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE) continue;
write_value(wFile, le_devices[i].addr_type, 1);
write_str(wFile, bd_addr_to_str(le_devices[i].addr));
write_hex(wFile, le_devices[i].irk, 16);
write_hex(wFile, le_devices[i].ltk, 16);
write_value(wFile, le_devices[i].ediv, 2);
write_hex(wFile, le_devices[i].rand, 8);
write_value(wFile, le_devices[i].key_size, 1);
write_value(wFile, le_devices[i].authenticated, 1);
write_value(wFile, le_devices[i].authorized, 1);
write_hex(wFile, le_devices[i].remote_csrk, 16);
write_value(wFile, le_devices[i].remote_counter, 2);
write_hex(wFile, le_devices[i].local_csrk, 16);
write_value(wFile, le_devices[i].local_counter, 2);
fwrite("\n", 1, 1, wFile);
}
fclose(wFile);
}
static void read_delimiter(FILE * wFile){
fgetc(wFile);
}
static uint8_t read_hex_byte(FILE * wFile){
int c = fgetc(wFile);
if (c == ':') {
c = fgetc(wFile);
}
int d = fgetc(wFile);
return nibble_for_char(c) << 4 | nibble_for_char(d);
}
static void read_hex(FILE * wFile, uint8_t * buffer, int len){
int i;
for (i=0;i<len;i++){
buffer[i] = read_hex_byte(wFile);
}
read_delimiter(wFile);
}
static uint32_t read_value(FILE * wFile, int len){
uint32_t res = 0;
int i;
for (i=0;i<len;i++){
res = res << 8 | read_hex_byte(wFile);
}
read_delimiter(wFile);
return res;
}
static void le_device_db_read(void){
// open file
FILE * wFile = fopen(db_path,"r");
if (wFile == NULL) return;
// skip header
while (1) {
int c = fgetc(wFile);
if (feof(wFile)) goto exit;
if (c == '\n') break;
}
// read entries
int i;
for (i=0;i<LE_DEVICE_MEMORY_SIZE && !feof(wFile);i++){
le_devices[i].addr_type = read_value(wFile, 1);
read_hex(wFile, le_devices[i].addr, 6);
read_hex(wFile, le_devices[i].irk, 16);
read_hex(wFile, le_devices[i].ltk, 16);
le_devices[i].ediv = read_value(wFile, 2);
read_hex(wFile, le_devices[i].rand, 8);
le_devices[i].key_size = read_value(wFile, 1);
le_devices[i].authenticated = read_value(wFile, 1);
le_devices[i].authorized = read_value(wFile, 1);
read_hex(wFile, le_devices[i].remote_csrk, 16);
le_devices[i].remote_counter = read_value(wFile, 2);
read_hex(wFile, le_devices[i].local_csrk, 16);
le_devices[i].local_counter = read_value(wFile, 2);
// read newling
fgetc(wFile);
}
exit:
fclose(wFile);
}
void le_device_db_init(void){
int i;
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
le_devices[i].addr_type = INVALID_ENTRY_ADDR_TYPE;
}
sprintf(db_path, DB_PATH_TEMPLATE, "00-00-00-00-00-00");
}
void le_device_db_set_local_bd_addr(bd_addr_t addr){
sprintf(db_path, DB_PATH_TEMPLATE, bd_addr_to_dash_str(addr));
log_info("le_device_db_fs: path %s", db_path);
le_device_db_read();
le_device_db_dump();
}
// @returns number of device in db
int le_device_db_count(void){
int i;
int counter = 0;
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
if (le_devices[i].addr_type != INVALID_ENTRY_ADDR_TYPE) counter++;
}
return counter;
}
// free device
void le_device_db_remove(int index){
le_devices[index].addr_type = INVALID_ENTRY_ADDR_TYPE;
le_device_db_store();
}
int le_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk){
int i;
int index = -1;
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
if (le_devices[i].addr_type == INVALID_ENTRY_ADDR_TYPE){
index = i;
break;
}
}
if (index < 0) return -1;
log_info("Central Device DB adding type %u - %s", addr_type, bd_addr_to_str(addr));
log_info_key("irk", irk);
le_devices[index].addr_type = addr_type;
memcpy(le_devices[index].addr, addr, 6);
memcpy(le_devices[index].irk, irk, 16);
le_devices[index].remote_counter = 0;
le_device_db_store();
return index;
}
// get device information: addr type and address
void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t irk){
if (addr_type) *addr_type = le_devices[index].addr_type;
if (addr) memcpy(addr, le_devices[index].addr, 6);
if (irk) memcpy(irk, le_devices[index].irk, 16);
}
void le_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk, int key_size, int authenticated, int authorized){
log_info("Central Device DB set encryption for %u, ediv x%04x, key size %u, authenticated %u, authorized %u",
index, ediv, key_size, authenticated, authorized);
le_device_memory_db_t * device = &le_devices[index];
device->ediv = ediv;
if (rand) memcpy(device->rand, rand, 8);
if (ltk) memcpy(device->ltk, ltk, 16);
device->key_size = key_size;
device->authenticated = authenticated;
device->authorized = authorized;
le_device_db_store();
}
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){
le_device_memory_db_t * device = &le_devices[index];
log_info("Central Device DB encryption for %u, ediv x%04x, keysize %u, authenticated %u, authorized %u",
index, device->ediv, device->key_size, device->authenticated, device->authorized);
if (ediv) *ediv = device->ediv;
if (rand) memcpy(rand, device->rand, 8);
if (ltk) memcpy(ltk, device->ltk, 16);
if (key_size) *key_size = device->key_size;
if (authenticated) *authenticated = device->authenticated;
if (authorized) *authorized = device->authorized;
}
// get signature key
void le_device_db_remote_csrk_get(int index, sm_key_t csrk){
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
log_error("le_device_db_remote_csrk_get called with invalid index %d", index);
return;
}
if (csrk) memcpy(csrk, le_devices[index].remote_csrk, 16);
}
void le_device_db_remote_csrk_set(int index, sm_key_t csrk){
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
log_error("le_device_db_remote_csrk_set called with invalid index %d", index);
return;
}
if (csrk) memcpy(le_devices[index].remote_csrk, csrk, 16);
le_device_db_store();
}
void le_device_db_local_csrk_get(int index, sm_key_t csrk){
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
log_error("le_device_db_local_csrk_get called with invalid index %d", index);
return;
}
if (csrk) memcpy(csrk, le_devices[index].local_csrk, 16);
}
void le_device_db_local_csrk_set(int index, sm_key_t csrk){
if (index < 0 || index >= LE_DEVICE_MEMORY_SIZE){
log_error("le_device_db_local_csrk_set called with invalid index %d", index);
return;
}
if (csrk) memcpy(le_devices[index].local_csrk, csrk, 16);
le_device_db_store();
}
// query last used/seen signing counter
uint32_t le_device_db_remote_counter_get(int index){
return le_devices[index].remote_counter;
}
// update signing counter
void le_device_db_remote_counter_set(int index, uint32_t counter){
le_devices[index].remote_counter = counter;
le_device_db_store();
}
// query last used/seen signing counter
uint32_t le_device_db_local_counter_get(int index){
return le_devices[index].local_counter;
}
// update signing counter
void le_device_db_local_counter_set(int index, uint32_t counter){
le_devices[index].local_counter = counter;
le_device_db_store();
}
void le_device_db_dump(void){
log_info("Central Device DB dump, devices: %d", le_device_db_count());
int i;
for (i=0;i<LE_DEVICE_MEMORY_SIZE;i++){
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_key("ltk", le_devices[i].ltk);
log_info_key("irk", le_devices[i].irk);
log_info_key("local csrk", le_devices[i].local_csrk);
log_info_key("remote csrk", le_devices[i].remote_csrk);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2016 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
*
*/
#ifndef __LE_DEVICE_DB_FS_H
#define __LE_DEVICE_DB_FS_H
#include "ble/le_device_db.h"
#if defined __cplusplus
extern "C" {
#endif
/*
* @brief Get le device db implementation that stores bonding information in /tmp
*/
const le_device_db_t * le_device_db_fs_instance(void);
/* API_END */
#if defined __cplusplus
}
#endif
#endif // __LE_DEVICE_DB_FS_H

View File

@ -721,8 +721,8 @@ void BTstackManager::setPublicBdAddr(bd_addr_t addr){
memcpy(public_bd_addr, addr ,6);
}
void bluetooth_hardware_error(){
printf("Bluetooth Hardware Error event. Restarting...\n\n\n");
void bluetooth_hardware_error(uint8_t error){
printf("Bluetooth Hardware Error event 0x%02x. Restarting...\n\n\n", error);
#ifdef __AVR__
wdt_enable(WDTO_15MS);
// wait for watchdog to trigger

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_EMBEDDED_TICK
// BTstack features that can be enabled

View File

@ -8,14 +8,18 @@ gap_dedicated_bonding
gap_inquiry
gap_inquiry_and_bond
gap_le_advertisements
gap_le_advertisements
gatt_battery_query
gatt_browser
hfp_ag_demo
hfp_hf_demo
hsp_ag_demo
hsp_hs_demo
l2cap_test
le_counter
le_counter.h
le_streamer
le_streamer
le_streamer.h
led_counter
panu_demo
@ -23,15 +27,11 @@ profile.h
sdp_bnep_query
sdp_general_query
sdp_rfcomm_query
sm_pairing_central
sm_pairing_peripheral
sm_pairing_peripheral.h
spp_and_le_counter
spp_and_le_counter.h
spp_counter
spp_streamer
le_streamer
le_streamer.h
gap_le_advertisements
le_streamer
spp_streamer
hfp_ag_demo
hfp_hf_demo
sm_pairing_peripheral.h
spp_streamer

View File

@ -3,7 +3,7 @@ BTSTACK_ROOT = ../..
CORE += main.c stdin_support.c
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c le_device_db_fs.c
include ${BTSTACK_ROOT}/example/Makefile.inc

View File

@ -101,6 +101,9 @@
#define SCO_RING_BUFFER_COUNT (8)
#define SCO_RING_BUFFER_SIZE (SCO_RING_BUFFER_COUNT * SCO_PACKET_SIZE)
// seems to be the max depth for USB 3
#define USB_MAX_PATH_LEN 7
// prototypes
static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
static int usb_close(void);
@ -185,6 +188,10 @@ static int acl_out_addr;
static int sco_in_addr;
static int sco_out_addr;
// device path
static int usb_path_len;
static uint8_t usb_path[USB_MAX_PATH_LEN];
#ifdef ENABLE_SCO_OVER_HCI
static void sco_ring_init(void){
@ -196,6 +203,14 @@ static int sco_ring_have_space(void){
}
#endif
void hci_transport_usb_set_path(int len, uint8_t * port_numbers){
if (len > USB_MAX_PATH_LEN || !port_numbers){
log_error("hci_transport_usb_set_path: len or port numbers invalid");
return;
}
usb_path_len = len;
memcpy(usb_path, port_numbers, len);
}
//
static void queue_transfer(struct libusb_transfer *transfer){
@ -572,6 +587,18 @@ static int scan_for_bt_device(libusb_device **devs, int start_index) {
static int prepare_device(libusb_device_handle * aHandle){
// print device path
uint8_t port_numbers[USB_MAX_PATH_LEN];
libusb_device * device = libusb_get_device(aHandle);
int path_len = libusb_get_port_numbers(device, port_numbers, USB_MAX_PATH_LEN);
printf("USB Path: ");
int i;
for (i=0;i<path_len;i++){
if (i) printf("-");
printf("%02x", port_numbers[i]);
}
printf("\n");
int r;
int kernel_driver_detached = 0;
@ -643,6 +670,30 @@ static int prepare_device(libusb_device_handle * aHandle){
return 0;
}
static libusb_device_handle * try_open_device(libusb_device * device){
int r;
libusb_device_handle * dev_handle;
r = libusb_open(device, &dev_handle);
if (r < 0) {
log_error("libusb_open failed!");
dev_handle = NULL;
return NULL;
}
log_info("libusb open %d, handle %p", r, dev_handle);
// reset device
libusb_reset_device(dev_handle);
if (r < 0) {
log_error("libusb_reset_device failed!");
libusb_close(dev_handle);
return NULL;
}
return dev_handle;
}
static int usb_open(void){
int r;
@ -691,57 +742,61 @@ static int usb_open(void){
#else
// Scan system for an appropriate devices
libusb_device **devs;
ssize_t cnt;
ssize_t num_devices;
log_info("Scanning for USB Bluetooth device");
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
num_devices = libusb_get_device_list(NULL, &devs);
if (num_devices < 0) {
usb_close();
return -1;
}
int startIndex = 0;
dev = NULL;
while (1){
int deviceIndex = scan_for_bt_device(devs, startIndex);
if (deviceIndex < 0){
if (usb_path_len){
int i;
for (i=0;i<num_devices;i++){
uint8_t port_numbers[USB_MAX_PATH_LEN];
int len = libusb_get_port_numbers(devs[i], port_numbers, USB_MAX_PATH_LEN);
if (len != usb_path_len) continue;
if (memcmp(usb_path, port_numbers, len) == 0){
log_info("USB device found at specified path");
handle = try_open_device(devs[i]);
if (!handle) continue;
r = prepare_device(handle);
if (r < 0) continue;
dev = devs[i];
libusb_state = LIB_USB_INTERFACE_CLAIMED;
break;
};
}
if (!handle){
log_error("USB device with given path not found");
printf("USB device with given path not found\n");
return -1;
}
} else {
int deviceIndex = -1;
while (1){
// look for next Bluetooth dongle
deviceIndex = scan_for_bt_device(devs, deviceIndex+1);
if (deviceIndex < 0) break;
log_info("USB Bluetooth device found, index %u", deviceIndex);
handle = try_open_device(devs[deviceIndex]);
if (!handle) continue;
r = prepare_device(handle);
if (r < 0) continue;
dev = devs[deviceIndex];
libusb_state = LIB_USB_INTERFACE_CLAIMED;
break;
}
startIndex = deviceIndex+1;
log_info("USB Bluetooth device found, index %u", deviceIndex);
handle = NULL;
r = libusb_open(devs[deviceIndex], &handle);
if (r < 0) {
log_error("libusb_open failed!");
handle = NULL;
continue;
}
log_info("libusb open %d, handle %p", r, handle);
// reset device
libusb_reset_device(handle);
if (r < 0) {
log_error("libusb_reset_device failed!");
libusb_close(handle);
handle = NULL;
continue;
}
// device found
r = prepare_device(handle);
if (r < 0){
continue;
}
libusb_state = LIB_USB_INTERFACE_CLAIMED;
break;
}
libusb_free_device_list(devs, 1);

View File

@ -92,14 +92,47 @@ void hal_led_toggle(void){
}
#define USB_MAX_PATH_LEN 7
int main(int argc, const char * argv[]){
uint8_t usb_path[USB_MAX_PATH_LEN];
int usb_path_len = 0;
if (argc >= 3 && strcmp(argv[1], "-u") == 0){
// parse command line options for "-u 11:22:33"
const char * port_str = argv[2];
printf("Specified USB Path: ");
while (1){
char * delimiter;
int port = strtol(port_str, &delimiter, 16);
usb_path[usb_path_len] = port;
usb_path_len++;
printf("%02x ", port);
if (!delimiter) break;
if (*delimiter != ':' && *delimiter != '-') break;
port_str = delimiter+1;
}
printf("\n");
}
/// GET STARTED with BTstack ///
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_posix_get_instance());
if (usb_path_len){
hci_transport_usb_set_path(usb_path_len, usb_path);
}
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
char pklg_path[100];
strcpy(pklg_path, "/tmp/hci_dump");
if (usb_path_len){
strcat(pklg_path, "_");
strcat(pklg_path, argv[2]);
}
strcat(pklg_path, ".pklg");
printf("Packet Log: %s\n", pklg_path);
hci_dump_open(pklg_path, HCI_DUMP_PACKETLOGGER);
// init HCI
hci_init(hci_transport_usb_instance(), NULL);

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_EMBEDDED_TICK
// BTstack features that can be enabled

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_EMBEDDED_TICK
// BTstack features that can be enabled

View File

@ -3,28 +3,41 @@ ancs_client_demo.h
ble_central_test
ble_peripheral
ble_peripheral_sm_minimal
ble_peripheral_test
bluetooth_init_cc2560_2.44.c
bluetooth_init_cc2560a_2.14.c
bluetooth_init_cc2560B_1.2_BT_Spec_4.0.c
bluetooth_init_cc2564_2.14.c
bluetooth_init_cc2564B_1.2_BT_Spec_4.0.c
bnep_test
classic_test
gap_dedicated_bonding
gap_inquiry
gap_inquiry_and_bond
gap_le_advertisements
gatt_battery_query
gatt_browser
hfp_ag_demo
hfp_hf_demo
hsp_ag_demo
hsp_ag_test
hsp_hs_demo
hsp_hs_test
l2cap_test
le_counter
le_counter.h
le_streamer
le_streamer.h
led_counter
profile.h
sco_input.wav
sdp_bnep_query
sdp_general_query
sdp_rfcomm_query
sm_pairing_peripheral.h
spp_and_le_counter
spp_and_le_counter.h
spp_counter
spp_streamer
led_counter
le_counter.h
ble_peripheral_test
le_counter
gap_le_advertisements
le_streamer
le_streamer.h
TIInit_12.10.28.c
TIInit_12.8.32.c

View File

@ -2,6 +2,7 @@
BTSTACK_ROOT = ../..
CORE += \
bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c \
btstack_chipset_cc256x.c \
btstack_chipset_csr.c \
btstack_chipset_em9301.c \
@ -11,9 +12,9 @@ CORE += \
btstack_run_loop_posix.c \
btstack_uart_block_posix.c \
hci_transport_h4.c \
le_device_db_fs.c \
main.c \
stdin_support.c \
bluetooth_init_cc2564B_1.4_BT_Spec_4.1.c \
# bluetooth_init_cc2564_2.14.c \
# btstack_chipset_bcm.c \

View File

@ -141,6 +141,8 @@ static void local_version_information_callback(uint8_t * packet){
hci_set_chipset(btstack_chipset_cc256x_instance());
#ifdef ENABLE_EHCILL
printf("eHCILL enabled.\n");
#else
printf("eHCILL disable.\n");
#endif
break;
case COMPANY_ID_BROADCOM_CORPORATION:

View File

@ -13,6 +13,7 @@ CORE += \
btstack_uart_block_posix.c \
btstack_slip.c \
hci_transport_h5.c \
le_device_db_fs.c \
main.c \
stdin_support.c \
# btstack_chipset_bcm.c \

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_EMBEDDED_TICK
// BTstack features that can be enabled

View File

@ -12,7 +12,7 @@
// BTstack features that can be enabled
#define ENABLE_BLE
#define ENABLE_CLASSIC
#define ENABLE_LE_SECURE_CONNECTIONS
// #define ENABLE_LE_SECURE_CONNECTIONS
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO

View File

@ -20,6 +20,7 @@ GLOBAL_INCLUDES += .
$(NAME)_SOURCES := ../../../libraries/btstack/example/EXAMPLE.c
$(NAME)_COMPONENTS += btstack/port/wiced
$(NAME)_CFLAGS += ADDITIONAL_CFLAGS
'''
gatt_update_template = '''#!/bin/sh
@ -45,7 +46,14 @@ if not "WICED Version" in wiced_version:
sys.exit(1)
# show WICED version
print("Found %s" % wiced_version)
wiced_version = wiced_version.split()[2]
print("Found WICED SDK version: %s" % wiced_version)
additional_cflags = ""
if wiced_version < "3.4.0":
print("Adding WICED_UART_READ_DOES_NOT_RETURN_BYTES_READ for SDK < 3.4.0")
additional_cflags = "-DWICED_UART_READ_DOES_NOT_RETURN_BYTES_READ"
# path to examples
examples_embedded = script_path + "/../../example/"
@ -68,7 +76,7 @@ for file in os.listdir(examples_embedded):
# create .mk file
with open(apps_folder + example + ".mk", "wt") as fout:
fout.write(mk_template.replace("EXAMPLE", example).replace("TOOL", script_path).replace("DATE",time.strftime("%c")))
fout.write(mk_template.replace("EXAMPLE", example).replace("TOOL", script_path).replace("ADDITIONAL_CFLAGS", additional_cflags).replace("DATE",time.strftime("%c")))
# create update_gatt.sh if .gatt file is present
gatt_path = examples_embedded + example + ".gatt"

View File

@ -121,10 +121,22 @@ static wiced_result_t h4_main_notify_packet_send(void *arg){
}
// executed on rx worker thread
static void h4_rx_worker_receive_bytes(int bytes_to_read){
#ifdef WICED_UART_READ_DOES_NOT_RETURN_BYTES_READ
// older API passes in number of bytes to read (checked in 3.3.1 and 3.4.0)
platform_uart_receive_bytes(wiced_bt_uart_driver, &hci_packet[rx_worker_read_pos], bytes_to_read, WICED_NEVER_TIMEOUT);
#else
// newer API uses pointer to return number of read bytes
uint32_t bytes = bytes_to_read;
platform_uart_receive_bytes(wiced_bt_uart_driver, &hci_packet[rx_worker_read_pos], &bytes, WICED_NEVER_TIMEOUT);
// assumption: bytes = bytes_to_rad as timeout is never
#endif
rx_worker_read_pos += bytes_to_read;
}
static wiced_result_t h4_rx_worker_receive_packet(void * arg){
#ifdef WICED_BT_UART_MANUAL_CTS_RTS
@ -166,11 +178,15 @@ static wiced_result_t h4_rx_worker_receive_packet(void * arg){
// executed on tx worker thread
static wiced_result_t h4_tx_worker_send_packet(void * arg){
#ifdef WICED_BT_UART_MANUAL_CTS_RTS
int cts_was_raised = 0;
while (platform_gpio_input_get(wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]) == WICED_TRUE){
printf(".");
wiced_rtos_delay_milliseconds(10);
wiced_rtos_delay_milliseconds(100);
cts_was_raised = 1;
}
if (cts_was_raised){
printf("\n");
}
printf("\n");
#endif
// blocking send
platform_uart_transmit_bytes(wiced_bt_uart_driver, tx_worker_data_buffer, tx_worker_data_size);
@ -181,7 +197,7 @@ static wiced_result_t h4_tx_worker_send_packet(void * arg){
static int h4_set_baudrate(uint32_t baudrate){
#ifdef _STM32F205RGT6_
#if defined(_STM32F205RGT6_) || defined(STM32F40_41xxx)
// directly use STM peripheral functions to change baud rate dynamically
@ -258,6 +274,13 @@ static int h4_open(void){
platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_HOST_WAKE], INPUT_HIGH_IMPEDANCE);
platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE], OUTPUT_PUSH_PULL);
platform_gpio_output_low(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE]);
/* Configure Reg Enable pin to output. Set to HIGH */
if (wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){
platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_POWER ], OUTPUT_OPEN_DRAIN_PULL_UP );
platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
}
wiced_rtos_delay_milliseconds( 100 );
// -- init UART
@ -279,12 +302,23 @@ static int h4_open(void){
#endif
platform_uart_init( wiced_bt_uart_driver, wiced_bt_uart_peripheral, &uart_config, ring_buffer );
// reset Bluetooth
platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_POWER ], OUTPUT_PUSH_PULL );
platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
wiced_rtos_delay_milliseconds( 100 );
platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
// Reset Bluetooth via RESET line. Fallback to toggling POWER otherwise
if ( wiced_bt_control_pins[ WICED_BT_PIN_RESET ]){
platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_RESET ], OUTPUT_PUSH_PULL );
platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
wiced_rtos_delay_milliseconds( 100 );
platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
}
else if ( wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){
platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
wiced_rtos_delay_milliseconds( 100 );
platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
}
// wait for Bluetooth to start up
wiced_rtos_delay_milliseconds( 500 );
// create worker threads for rx/tx. only single request is posted to their queues

View File

@ -43,7 +43,7 @@
#include "platform_bluetooth.h"
#include "wiced.h"
#include "platform/wwd_platform_interface.h"
// see generated_mac_address.txt - "macaddr=02:0A:F7:3d:76:be"
static const char * wifi_mac_address = NVRAM_GENERATED_MAC_ADDRESS;
@ -53,7 +53,7 @@ static btstack_packet_callback_registration_t hci_event_callback_registration;
static const hci_transport_config_uart_t hci_transport_config_uart = {
HCI_TRANSPORT_CONFIG_UART,
115200,
0, // 3000000,
0,
1,
NULL,
};
@ -69,8 +69,11 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
void application_start(void){
/* Initialise the WICED device */
wiced_init();
/* Initialise the WICED device without WLAN */
wiced_core_init();
/* 32 kHz clock also needed for Bluetooth */
host_platform_init_wlan_powersave_clock();
printf("BTstack on WICED\n");
@ -82,7 +85,7 @@ void application_start(void){
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
// init HCI
hci_init(hci_transport_h4_instance(btstack_uart_block_embedded_instance()), (void*) &hci_transport_config_uart);
hci_init(hci_transport_h4_instance(NULL), (void*) &hci_transport_config_uart);
hci_set_link_key_db(btstack_link_key_db_memory_instance());
hci_set_chipset(btstack_chipset_bcm_instance());

View File

@ -1,6 +1,8 @@
# BTstack port for WICED platform
To integrate BTstack into the WICED SDK, please move the BTstack project into WICED-SDK-X/libraries.
Only tested on Redbear Duo platform. Please install [RedBear WICED Add-On](https://github.com/redbear/WICED-SDK) first.
To integrate BTstack into the WICED SDK, please move the BTstack project into WICED-SDK-3.5.2/libraries.
Then create projects for BTstack examples in WICED/apps/btstack by running:
./create_examples.py
@ -13,15 +15,13 @@ to build the SPP-and-LE-Counter example.
See WICED documentation about how to install it.
Only tested on Redbear Duo platform.
It should work with all WICED platforms that contain a Broadcom Bluetooth chipset.
The maximal baud rate is limited to 3 mbps.
The port uses the generated WIFI address plus 1 as Bluetooth MAC address.
The examples that implement a BLE Peripheral/provide a GATT Server use the GATT DB in the .gatt file.
The examples that implement a BLE Peripheral/provide a GATT Server that uses the GATT DB in the .gatt file.
After modifying the .gatt file, please run ./update_gatt_db.sh in the apps/btstack/$(EXAMPLE) folder.

View File

@ -12,7 +12,8 @@ GLOBAL_INCLUDES += . ../../src ../../platform/embedded ../../chipset/bcm ../../.
# core BTstack sources
$(NAME)_SOURCES += \
../../src/ble/att_db.c \
../../src/ble/ad_parser.c \
../../src/ble/att_db.c \
../../src/ble/att_dispatch.c \
../../src/ble/att_server.c \
../../src/ble/le_device_db_memory.c \
@ -20,17 +21,18 @@ $(NAME)_SOURCES += \
../../src/classic/hsp_hs.c \
../../src/classic/btstack_link_key_db_memory.c \
../../src/classic/rfcomm.c \
../../src/classic/sdp_server.c \
../../src/classic/sdp_server.c \
../../src/classic/sdp_client.c \
../../src/classic/sdp_client_rfcomm.c \
../../src/classic/sdp_client_rfcomm.c \
../../src/classic/sdp_util.c \
../../src/classic/spp_server.c \
../../src/btstack_linked_list.c \
../../src/btstack_memory.c \
../../src/btstack_memory_pool.c \
../../src/btstack_run_loop.c \
../../src/btstack_util.c \
../../src/hci.c \
../../src/hci_cmd.c \
../../src/hci_cmd.c \
../../src/hci_dump.c \
../../src/l2cap.c \
../../src/l2cap_signaling.c \
@ -39,7 +41,11 @@ $(NAME)_SOURCES += \
$(NAME)_SOURCES += \
main.c \
btstack_run_loop_wiced.c \
btstack_uart_block_embedded.c \
hci_transport_h4_wiced.c \
../../chipset/bcm/btstack_chipset_bcm.c \
../../../drivers/bluetooth/firmware/$(BT_CHIP)$(BT_CHIP_REVISION)/bt_firmware_image.c \
ifeq ($(BT_CHIP_XTAL_FREQUENCY),)
$(NAME)_SOURCES += ../../../drivers/bluetooth/firmware/$(BT_CHIP)$(BT_CHIP_REVISION)/bt_firmware_image.c
else
$(NAME)_SOURCES += ../../../drivers/bluetooth/firmware/$(BT_CHIP)$(BT_CHIP_REVISION)/$(BT_CHIP_XTAL_FREQUENCY)/bt_firmware_image.c
endif

View File

@ -106,7 +106,6 @@ static void att_handle_value_indication_notify_client(uint8_t status, uint16_t c
little_endian_store_16(event, pos, client_handle);
pos += 2;
little_endian_store_16(event, pos, attribute_handle);
pos += 2;
(*att_client_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event));
}
@ -120,7 +119,6 @@ static void att_emit_mtu_event(hci_con_handle_t con_handle, uint16_t mtu){
little_endian_store_16(event, pos, con_handle);
pos += 2;
little_endian_store_16(event, pos, mtu);
pos += 2;
(*att_client_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event));
}
@ -176,11 +174,11 @@ static void att_event_packet_handler (uint8_t packet_type, uint16_t channel, uin
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
// check handle
if (att_connection.con_handle != hci_event_disconnection_complete_get_connection_handle(packet)) break;
att_clear_transaction_queue(&att_connection);
att_connection.con_handle = 0;
att_handle_value_indication_handle = 0; // reset error state
// restart advertising if we have been connected before
// -> avoid sending advertise enable a second time before command complete was received
att_server_state = ATT_SERVER_IDLE;
break;
@ -326,7 +324,7 @@ static void att_run(void){
log_info("Orig Signature: ");
log_info_hexdump( &att_request_buffer[att_request_size-8], 8);
uint16_t attribute_handle = little_endian_read_16(att_request_buffer, 1);
sm_cmac_start(csrk, att_request_buffer[0], attribute_handle, att_request_size - 15, &att_request_buffer[3], counter_packet, att_signed_write_handle_cmac_result);
sm_cmac_signed_write_start(csrk, att_request_buffer[0], attribute_handle, att_request_size - 15, &att_request_buffer[3], counter_packet, att_signed_write_handle_cmac_result);
return;
}

View File

@ -965,7 +965,7 @@ static void gatt_client_run(void){
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);
sm_cmac_signed_write_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
}
return;

View File

@ -67,6 +67,13 @@ extern "C" {
*/
void le_device_db_init(void);
/**
* @brief sets local bd addr. allows for db per Bluetooth controller
* @param bd_addr
*/
void le_device_db_set_local_bd_addr(bd_addr_t bd_addr);
/**
* @brief add device to db
* @param addr_type, address of the device

View File

@ -82,6 +82,9 @@ void le_device_db_init(void){
}
}
void le_device_db_set_local_bd_addr(bd_addr_t bd_addr){
}
// @returns number of device in db
int le_device_db_count(void){
int i;

View File

@ -231,8 +231,11 @@ static uint8_t ec_qx[32];
static uint8_t ec_qy[32];
static uint8_t ec_d[32];
#ifndef HAVE_MALLOC
// 4304 bytes with 73 allocations
#define MBEDTLS_ALLOC_BUFFER_SIZE (1300+23*sizeof(void *))
// COMP Method with Window 2
// 1300 bytes with 23 allocations
// #define MBEDTLS_ALLOC_BUFFER_SIZE (1300+23*sizeof(void *))
// NAIVE Method with safe cond assignments (without safe cond, order changes and allocations fail)
#define MBEDTLS_ALLOC_BUFFER_SIZE (700+18*sizeof(void *))
static uint8_t mbedtls_memory_buffer[MBEDTLS_ALLOC_BUFFER_SIZE];
#endif
#endif
@ -288,7 +291,7 @@ typedef struct sm_setup_context {
sm_key_t sm_local_dhkey_check;
sm_key_t sm_ra;
sm_key_t sm_rb;
sm_key_t sm_t; // used for f5
sm_key_t sm_t; // used for f5 and h6
sm_key_t sm_mackey;
uint8_t sm_passkey_bit; // also stores number of generated random bytes for EC key generation
#endif
@ -648,20 +651,6 @@ static void aes_cmac(sm_key_t aes_cmac, const sm_key_t key, const uint8_t * data
aes128_calc_cyphertext(key, sm_cmac_y, aes_cmac);
}
#endif
#if 0
//
// Link Key Conversion Function h6
//
// h6(W, keyID) = AES-CMACW(keyID)
// - W is 128 bits
// - keyID is 32 bits
static void h6(sm_key_t res, const sm_key_t w, const uint32_t key_id){
uint8_t key_id_buffer[4];
big_endian_store_32(key_id_buffer, 0, key_id);
aes_cmac(res, w, key_id_buffer, 4);
}
#endif
#endif
static void sm_setup_event_base(uint8_t * event, int event_size, uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address){
@ -867,23 +856,8 @@ static int sm_cmac_last_block_complete(void){
return (sm_cmac_message_len & 0x0f) == 0;
}
static inline uint8_t sm_cmac_message_get_byte(uint16_t offset){
if (offset >= sm_cmac_message_len) {
log_error("sm_cmac_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_message_len);
return 0;
}
offset = sm_cmac_message_len - 1 - offset;
// sm_cmac_header[3] | message[] | sm_cmac_sign_counter[4]
if (offset < 3){
return sm_cmac_header[offset];
}
int actual_message_len_incl_header = sm_cmac_message_len - 4;
if (offset < actual_message_len_incl_header){
return sm_cmac_message[offset - 3];
}
return sm_cmac_sign_counter[offset - actual_message_len_incl_header];
int sm_cmac_ready(void){
return sm_cmac_state == CMAC_IDLE;
}
// generic cmac calculation
@ -913,19 +887,35 @@ void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*g
}
// cmac for ATT Message signing
void sm_cmac_start(const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)){
static uint8_t sm_cmac_signed_write_message_get_byte(uint16_t offset){
if (offset >= sm_cmac_message_len) {
log_error("sm_cmac_signed_write_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_message_len);
return 0;
}
offset = sm_cmac_message_len - 1 - offset;
// sm_cmac_header[3] | message[] | sm_cmac_sign_counter[4]
if (offset < 3){
return sm_cmac_header[offset];
}
int actual_message_len_incl_header = sm_cmac_message_len - 4;
if (offset < actual_message_len_incl_header){
return sm_cmac_message[offset - 3];
}
return sm_cmac_sign_counter[offset - actual_message_len_incl_header];
}
void sm_cmac_signed_write_start(const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)){
// ATT Message Signing
sm_cmac_header[0] = opcode;
little_endian_store_16(sm_cmac_header, 1, con_handle);
little_endian_store_32(sm_cmac_sign_counter, 0, sign_counter);
uint16_t total_message_len = 3 + message_len + 4; // incl. virtually prepended att opcode, handle and appended sign_counter in LE
sm_cmac_message = message;
sm_cmac_general_start(k, total_message_len, &sm_cmac_message_get_byte, done_handler);
sm_cmac_general_start(k, total_message_len, &sm_cmac_signed_write_message_get_byte, done_handler);
}
int sm_cmac_ready(void){
return sm_cmac_state == CMAC_IDLE;
}
static void sm_cmac_handle_aes_engine_ready(void){
switch (sm_cmac_state){
@ -1095,12 +1085,16 @@ static int sm_key_distribution_flags_for_auth_req(void){
return flags;
}
static void sm_init_setup(sm_connection_t * sm_conn){
static void sm_reset_setup(void){
// fill in sm setup
setup->sm_state_vars = 0;
setup->sm_keypress_notification = 0xff;
sm_reset_tk();
}
static void sm_init_setup(sm_connection_t * sm_conn){
// fill in sm setup
setup->sm_peer_addr_type = sm_conn->sm_peer_addr_type;
memcpy(setup->sm_peer_address, sm_conn->sm_peer_address, 6);
@ -1184,7 +1178,7 @@ static void sm_address_resolution_handle_event(address_resolution_event_t event)
hci_con_handle_t con_handle = 0;
sm_connection_t * sm_connection;
uint16_t ediv;
sm_key_t ltk;
switch (mode){
case ADDRESS_RESOLUTION_GENERAL:
break;
@ -1200,8 +1194,8 @@ static void sm_address_resolution_handle_event(address_resolution_event_t event)
if (!sm_connection->sm_bonding_requested && !sm_connection->sm_security_request_received) break;
sm_connection->sm_security_request_received = 0;
sm_connection->sm_bonding_requested = 0;
le_device_db_encryption_get(sm_connection->sm_le_db_index, &ediv, NULL, NULL, NULL, NULL, NULL);
if (ediv){
le_device_db_encryption_get(sm_connection->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL);
if (!sm_is_null_key(ltk)){
sm_connection->sm_engine_state = SM_INITIATOR_PH0_HAS_LTK;
} else {
sm_connection->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
@ -1274,7 +1268,6 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
}
if (le_db_index >= 0){
le_device_db_local_counter_set(le_db_index, 0);
// store local CSRK
if (setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
@ -1290,13 +1283,23 @@ static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
le_device_db_remote_counter_set(le_db_index, 0);
}
// store encryption information
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION
&& setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION){
// store encryption information for secure connections: LTK generated by ECDH
if (setup->sm_use_secure_connections){
log_info("sm: store SC LTK (key size %u, authenticatd %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
uint8_t zero_rand[8];
memset(zero_rand, 0, 8);
le_device_db_encryption_set(le_db_index, 0, zero_rand, setup->sm_ltk, sm_conn->sm_actual_encryption_key_size,
sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED);
}
// store encryption infromation for legacy pairing: peer LTK, EDIV, RAND
else if ( (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION)
&& (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION )){
log_info("sm: set encryption information (key size %u, authenticatd %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
le_device_db_encryption_set(le_db_index, setup->sm_peer_ediv, setup->sm_peer_rand, setup->sm_peer_ltk,
sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED);
}
}
}
// keep le_db_index
@ -1375,6 +1378,7 @@ static void sm_sc_cmac_done(uint8_t * hash){
sm_connection_t * sm_conn = sm_cmac_connection;
sm_cmac_connection = NULL;
link_key_type_t link_key_type;
switch (sm_conn->sm_engine_state){
case SM_SC_W4_CMAC_FOR_CONFIRMATION:
@ -1405,7 +1409,13 @@ static void sm_sc_cmac_done(uint8_t * hash){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_LTK;
break;
case SM_SC_W4_CALCULATE_F5_LTK:
// truncate sm_ltk, but keep full LTK for cross-transport key derivation in sm_local_ltk
// Errata Service Release to the Bluetooth Specification: ESR09
// E6405 Cross transport key derivation from a key of size less than 128 bits
// Note: When the BR/EDR link key is being derived from the LTK, the derivation is done before the LTK gets masked."
memcpy(setup->sm_ltk, hash, 16);
memcpy(setup->sm_local_ltk, hash, 16);
sm_truncate_key(setup->sm_ltk, sm_conn->sm_actual_encryption_key_size);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK;
break;
case SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK:
@ -1434,6 +1444,23 @@ static void sm_sc_cmac_done(uint8_t * hash){
sm_conn->sm_engine_state = SM_INITIATOR_PH3_SEND_START_ENCRYPTION;
}
break;
case SM_SC_W4_CALCULATE_H6_ILK:
memcpy(setup->sm_t, hash, 16);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY;
break;
case SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY:
reverse_128(hash, setup->sm_t);
link_key_type = sm_conn->sm_connection_authenticated ?
AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256 : UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256;
if (sm_conn->sm_role){
gap_store_link_key_for_bd_addr(setup->sm_m_address, setup->sm_t, link_key_type);
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
} else {
gap_store_link_key_for_bd_addr(setup->sm_s_address, setup->sm_t, link_key_type);
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}
sm_done_for_handle(sm_conn->sm_handle);
break;
default:
log_error("sm_sc_cmac_done in state %u", sm_conn->sm_engine_state);
break;
@ -1470,12 +1497,12 @@ static void sm_sc_calculate_dhkey(sm_key256_t dhkey){
mbedtls_mpi_read_binary(&d, ec_d, 32);
mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32);
mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32);
mbedtls_mpi_read_string(&Q.Z, 16, "1" );
mbedtls_mpi_lset(&Q.Z, 1);
mbedtls_ecp_mul(&mbedtls_ec_group, &DH, &d, &Q, NULL, NULL);
mbedtls_mpi_write_binary(&DH.X, dhkey, 32);
mbedtls_ecp_point_free(&DH);
mbedtls_mpi_free(&d);
mbedtls_ecp_point_free(&Q);
mbedtls_ecp_point_free(&DH);
#endif
log_info("dhkey");
log_info_hexdump(dhkey, 32);
@ -1574,7 +1601,7 @@ static void g2_engine(sm_connection_t * sm_conn, const sm_key256_t u, const sm_k
log_info("g2 key");
log_info_hexdump(x, 16);
log_info("g2 message");
log_info_hexdump(sm_cmac_sc_buffer, sizeof(sm_cmac_sc_buffer));
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_general_start(x, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done);
}
@ -1663,8 +1690,48 @@ static void sm_sc_calculate_f6_to_verify_dhkey_check(sm_connection_t * sm_conn){
f6_engine(sm_conn, setup->sm_mackey, setup->sm_peer_nonce, setup->sm_local_nonce, setup->sm_ra, iocap_b, bd_addr_slave, bd_addr_master);
}
}
//
// Link Key Conversion Function h6
//
// h6(W, keyID) = AES-CMACW(keyID)
// - W is 128 bits
// - keyID is 32 bits
static void h6_engine(sm_connection_t * sm_conn, const sm_key_t w, const uint32_t key_id){
const uint16_t message_len = 4;
sm_cmac_connection = sm_conn;
big_endian_store_32(sm_cmac_sc_buffer, 0, key_id);
log_info("h6 key");
log_info_hexdump(w, 16);
log_info("h6 message");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_general_start(w, message_len, &sm_sc_cmac_get_byte, &sm_sc_cmac_done);
}
// For SC, setup->sm_local_ltk holds full LTK (sm_ltk is already truncated)
// Errata Service Release to the Bluetooth Specification: ESR09
// E6405 Cross transport key derivation from a key of size less than 128 bits
// "Note: When the BR/EDR link key is being derived from the LTK, the derivation is done before the LTK gets masked."
static void h6_calculate_ilk(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_local_ltk, 0x746D7031); // "tmp1"
}
static void h6_calculate_br_edr_link_key(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_t, 0x6c656272); // "lebr"
}
#endif
// key management legacy connections:
// - potentially two different LTKs based on direction. each device stores LTK provided by peer
// - master stores LTK, EDIV, RAND. responder optionally stored master LTK (only if it needs to reconnect)
// - initiators reconnects: initiator uses stored LTK, EDIV, RAND generated by responder
// - responder reconnects: responder uses LTK receveived from master
// key management secure connections:
// - both devices store same LTK from ECDH key exchange.
static void sm_load_security_info(sm_connection_t * sm_connection){
int encryption_key_size;
int authenticated;
@ -1679,6 +1746,19 @@ static void sm_load_security_info(sm_connection_t * sm_connection){
sm_connection->sm_connection_authorization_state = authorized ? AUTHORIZATION_GRANTED : AUTHORIZATION_UNKNOWN;
}
static void sm_start_calculating_ltk_from_ediv_and_rand(sm_connection_t * sm_connection){
memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
setup->sm_local_ediv = sm_connection->sm_local_ediv;
// re-establish used key encryption size
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1;
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
log_info("sm: received ltk request with key size %u, authenticated %u",
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
sm_connection->sm_engine_state = SM_RESPONDER_PH4_Y_GET_ENC;
}
static void sm_run(void){
btstack_linked_list_iterator_t it;
@ -1857,6 +1937,7 @@ static void sm_run(void){
done = 0;
break;
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
sm_reset_setup();
sm_init_setup(sm_connection);
// recover pairing request
memcpy(&setup->sm_m_preq, &sm_connection->sm_m_preq, sizeof(sm_pairing_packet_t));
@ -1875,48 +1956,52 @@ static void sm_run(void){
sm_connection->sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE;
break;
case SM_INITIATOR_PH0_HAS_LTK:
sm_reset_setup();
sm_load_security_info(sm_connection);
sm_connection->sm_engine_state = SM_INITIATOR_PH0_SEND_START_ENCRYPTION;
break;
case SM_RESPONDER_PH0_RECEIVED_LTK:
switch (sm_connection->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:{
sm_load_security_info(sm_connection);
sm_connection->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
break;
}
case IRK_LOOKUP_FAILED:
// assume that we don't have a LTK for ediv == 0 and random == null
if (sm_connection->sm_local_ediv == 0 && sm_is_null_random(sm_connection->sm_local_rand)){
log_info("LTK Request: ediv & random are empty");
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
// TODO: no need to lock context yet -> done = 0;
break;
}
// re-establish previously used LTK using Rand and EDIV
memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
setup->sm_local_ediv = sm_connection->sm_local_ediv;
// re-establish used key encryption size
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1;
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
log_info("sm: received ltk request with key size %u, authenticated %u",
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
sm_connection->sm_engine_state = SM_RESPONDER_PH4_Y_GET_ENC;
break;
default:
// just wait until IRK lookup is completed
// don't lock sxetup context yet
done = 0;
break;
}
case SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST:
sm_reset_setup();
sm_start_calculating_ltk_from_ediv_and_rand(sm_connection);
break;
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:
sm_reset_setup();
sm_init_setup(sm_connection);
sm_timeout_start(sm_connection);
sm_connection->sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST;
break;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
case SM_SC_RECEIVED_LTK_REQUEST:
switch (sm_connection->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:
// assuming Secure Connection, we have a stored LTK and the EDIV/RAND are null
sm_reset_setup();
sm_load_security_info(sm_connection);
if (setup->sm_peer_ediv == 0 && sm_is_null_random(setup->sm_peer_rand) && !sm_is_null_key(setup->sm_peer_ltk)){
memcpy(setup->sm_ltk, setup->sm_peer_ltk, 16);
sm_connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
break;
}
log_info("LTK Request: ediv & random are empty, but no stored LTK (IRK Lookup Succeeded)");
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
// don't lock setup context yet
done = 0;
break;
case IRK_LOOKUP_FAILED:
log_info("LTK Request: ediv & random are empty, but no stored LTK (IRK Lookup Failed)");
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
// don't lock setup context yet
done = 0;
break;
default:
// just wait until IRK lookup is completed
// don't lock setup context yet
done = 0;
break;
}
break;
#endif
default:
done = 0;
break;
@ -1949,6 +2034,7 @@ static void sm_run(void){
buffer[1] = setup->sm_keypress_notification;
setup->sm_keypress_notification = 0xff;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
return;
}
sm_key_t plaintext;
@ -2019,6 +2105,16 @@ static void sm_run(void){
connection->sm_engine_state = SM_SC_W4_CALCULATE_G2;
g2_calculate(connection);
break;
case SM_SC_W2_CALCULATE_H6_ILK:
if (!sm_cmac_ready()) break;
connection->sm_engine_state = SM_SC_W4_CALCULATE_H6_ILK;
h6_calculate_ilk(connection);
break;
case SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY:
if (!sm_cmac_ready()) break;
connection->sm_engine_state = SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY;
h6_calculate_br_edr_link_key(connection);
break;
#endif
// initiator side
@ -2298,7 +2394,7 @@ static void sm_run(void){
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle, 0, 0, 0, stk_flipped);
return;
}
case SM_RESPONDER_PH4_SEND_LTK: {
case SM_RESPONDER_PH4_SEND_LTK_REPLY: {
sm_key_t ltk_flipped;
reverse_128(setup->sm_ltk, ltk_flipped);
connection->sm_engine_state = SM_RESPONDER_IDLE;
@ -2545,9 +2641,13 @@ static void sm_handle_encryption_result(uint8_t * data){
// slave -> receive master keys
connection->sm_engine_state = SM_PH3_RECEIVE_KEYS;
} else {
// master -> all done
connection->sm_engine_state = SM_INITIATOR_CONNECTED;
sm_done_for_handle(connection->sm_handle);
if (setup->sm_use_secure_connections && (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION)){
connection->sm_engine_state = SM_SC_W2_CALCULATE_H6_ILK;
} else {
// master -> all done
connection->sm_engine_state = SM_INITIATOR_CONNECTED;
sm_done_for_handle(connection->sm_handle);
}
}
}
return;
@ -2555,7 +2655,7 @@ static void sm_handle_encryption_result(uint8_t * data){
reverse_128(data, setup->sm_ltk);
sm_truncate_key(setup->sm_ltk, connection->sm_actual_encryption_key_size);
log_info_key("ltk", setup->sm_ltk);
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK;
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
return;
default:
break;
@ -2595,6 +2695,7 @@ static void sm_handle_random_result(uint8_t * data){
setup->sm_passkey_bit = num_bytes;
if (num_bytes >= 64){
// generate EC key
setup->sm_passkey_bit = 0;
mbedtls_mpi d;
@ -2612,11 +2713,15 @@ static void sm_handle_random_result(uint8_t * data){
sm_log_ec_keypair();
#if 0
printf("test dhkey check\n");
int i;
sm_key256_t dhkey;
memcpy(setup->sm_peer_qx, ec_qx, 32);
memcpy(setup->sm_peer_qy, ec_qy, 32);
sm_sc_calculate_dhkey(dhkey);
for (i=0;i<10;i++){
// printf("test dhkey check\n");
memcpy(setup->sm_peer_qx, ec_qx, 32);
memcpy(setup->sm_peer_qy, ec_qy, 32);
sm_sc_calculate_dhkey(dhkey);
// printf("test dhkey check end\n");
}
#endif
}
@ -2736,6 +2841,12 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
// bt stack activated, get started
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
log_info("HCI Working!");
// set local addr for le device db
bd_addr_t local_bd_addr;
gap_local_bd_addr(local_bd_addr);
le_device_db_set_local_bd_addr(local_bd_addr);
dkg_state = sm_persistent_irk_ready ? DKG_CALC_DHK : DKG_CALC_IRK;
rau_state = RAU_IDLE;
#ifdef USE_MBEDTLS_FOR_ECDH
@ -2807,14 +2918,28 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
break;
}
if (sm_conn->sm_engine_state == SM_SC_W4_LTK_REQUEST_SC){
// PH2 SEND LTK as we need to exchange keys in PH3
sm_conn->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
break;
}
// store rand and ediv
reverse_64(&packet[5], sm_conn->sm_local_rand);
sm_conn->sm_local_ediv = little_endian_read_16(packet, 13);
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK;
sm_conn->sm_local_ediv = little_endian_read_16(packet, 13);
// For Legacy Pairing (<=> EDIV != 0 || RAND != NULL), we need to recalculated our LTK as a
// potentially stored LTK is from the master
if (sm_conn->sm_local_ediv != 0 || !sm_is_null_random(sm_conn->sm_local_rand)){
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST;
break;
}
#ifdef ENABLE_LE_SECURE_CONNECTIONS
sm_conn->sm_engine_state = SM_SC_RECEIVED_LTK_REQUEST;
#else
log_info("LTK Request: ediv & random are empty, but LE Secure Connections not supported");
sm_conn->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
#endif
break;
default:
@ -3026,10 +3151,9 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
break;
}
if (sm_conn->sm_irk_lookup_state == IRK_LOOKUP_SUCCEEDED){
uint16_t ediv;
sm_key_t ltk;
le_device_db_encryption_get(sm_conn->sm_le_db_index, &ediv, NULL, ltk, NULL, NULL, NULL);
if (!sm_is_null_key(ltk) || ediv){
le_device_db_encryption_get(sm_conn->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL);
if (!sm_is_null_key(ltk)){
log_info("sm: Setting up previous ltk/ediv/rand for device index %u", sm_conn->sm_le_db_index);
sm_conn->sm_engine_state = SM_INITIATOR_PH0_HAS_LTK;
} else {
@ -3137,7 +3261,7 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
mbedtls_ecp_point_init( &Q );
mbedtls_mpi_read_binary(&Q.X, setup->sm_peer_qx, 32);
mbedtls_mpi_read_binary(&Q.Y, setup->sm_peer_qy, 32);
mbedtls_mpi_read_string(&Q.Z, 16, "1" );
mbedtls_mpi_lset(&Q.Z, 1);
err = mbedtls_ecp_check_pubkey(&mbedtls_ec_group, &Q);
mbedtls_ecp_point_free( & Q);
if (err){
@ -3331,8 +3455,12 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin
sm_key_distribution_handle_all_received(sm_conn);
if (sm_conn->sm_role){
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
sm_done_for_handle(sm_conn->sm_handle);
if (setup->sm_use_secure_connections && (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION)){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_H6_ILK;
} else {
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
sm_done_for_handle(sm_conn->sm_handle);
}
} else {
if (setup->sm_use_secure_connections){
sm_conn->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
@ -3450,7 +3578,6 @@ void sm_init(void){
#endif
mbedtls_ecp_group_init(&mbedtls_ec_group);
mbedtls_ecp_group_load(&mbedtls_ec_group, MBEDTLS_ECP_DP_SECP256R1);
#if 0
// test
sm_test_use_fixed_ec_keypair();

View File

@ -236,6 +236,23 @@ void sm_authorization_decline(hci_con_handle_t con_handle);
*/
void sm_authorization_grant(hci_con_handle_t con_handle);
/**
* @brief Check if CMAC AES engine is ready
* @return ready
*/
int sm_cmac_ready(void);
/*
* @brief Generic CMAC AES
* @param key
* @param message_len
* @param get_byte_callback
* @param done_callback
* @note hash is 16 bytes in big endian
*/
void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash));
/**
* @brief Support for signed writes, used by att_server.
* @note Message is in little endian to allows passing in ATT PDU without flipping.
@ -248,18 +265,7 @@ void sm_authorization_grant(hci_con_handle_t con_handle);
* @param message
* @param sign_counter
*/
int sm_cmac_ready(void);
void sm_cmac_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash));
/*
* @brief Generic CMAC AES
* @param key
* @param message_len
* @param get_byte_callback
* @param done_callback
* @note hash is 16 bytes in big endian
*/
void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash));
void sm_cmac_signed_write_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash));
/*
* @brief Match address against bonded devices

View File

@ -118,6 +118,7 @@ typedef uint8_t sm_key_t[16];
#define L2CAP_SERVICE_ALREADY_REGISTERED 0x69
#define L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU 0x6A
#define L2CAP_SERVICE_DOES_NOT_EXIST 0x6B
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71

View File

@ -118,7 +118,7 @@ int btstack_linked_list_remove(btstack_linked_list_t * list, btstack_linked_ite
int btstack_linked_list_count(btstack_linked_list_t * list){
btstack_linked_item_t *it;
int counter = 0;
for (it = (btstack_linked_item_t *) list; it ; it = it->next) {
for (it = (btstack_linked_item_t *) list; it->next ; it = it->next) {
counter++;
}
return counter;

View File

@ -82,7 +82,7 @@ int btstack_run_loop_get_data_source_fd(btstack_data_source_t *ds){
void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){
btstack_run_loop_assert();
if (the_run_loop->enable_data_source_callbacks){
return the_run_loop->enable_data_source_callbacks(ds, callbacks);
the_run_loop->enable_data_source_callbacks(ds, callbacks);
} else {
log_error("btstack_run_loop_remove_data_source not implemented");
}
@ -91,7 +91,7 @@ void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t *ds, ui
void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){
btstack_run_loop_assert();
if (the_run_loop->disable_data_source_callbacks){
return the_run_loop->disable_data_source_callbacks(ds, callbacks);
the_run_loop->disable_data_source_callbacks(ds, callbacks);
} else {
log_error("btstack_run_loop_disable_data_source_callbacks not implemented");
}

View File

@ -120,6 +120,9 @@ uint8_t btstack_slip_encoder_get_byte(void){
case SLIP_ENCODER_SEND_DD:
encoder_state = SLIP_ENCODER_DEFAULT;
return 0x0dd;
default:
log_error("btstack_slip_encoder_get_byte invalid state %x", encoder_state);
return 0x00;
}
}

View File

@ -44,10 +44,11 @@
*/
#include "btstack_config.h"
#include "btstack_debug.h"
#include "btstack_util.h"
#include <stdio.h>
#include <string.h>
#include "btstack_debug.h"
/**
@ -171,19 +172,24 @@ void printf_hexdump(const void *data, int size){
printf("\n");
}
// void log_info_hexdump(..){
//
// }
void log_info_hexdump(const void *data, int size){
#ifdef ENABLE_LOG_INFO
char buffer[6*16+1];
int i, j;
uint8_t low = 0x0F;
uint8_t high = 0xF0;
const int items_per_line = 16;
const int bytes_per_byte = 6; // strlen('0x12, ')
const uint8_t low = 0x0F;
const uint8_t high = 0xF0;
char buffer[bytes_per_byte*items_per_line+1];
int i, j;
j = 0;
for (i=0; i<size;i++){
// help static analyzer proof that j stays within bounds
if (j > bytes_per_byte * (items_per_line-1)){
j = 0;
}
uint8_t byte = ((uint8_t *)data)[i];
buffer[j++] = '0';
buffer[j++] = 'x';
@ -191,7 +197,8 @@ void log_info_hexdump(const void *data, int size){
buffer[j++] = char_for_nibble(byte & low);
buffer[j++] = ',';
buffer[j++] = ' ';
if (j >= 6*16 ){
if (j >= bytes_per_byte * items_per_line ){
buffer[j] = 0;
log_info("%s", buffer);
j = 0;
@ -205,8 +212,20 @@ void log_info_hexdump(const void *data, int size){
}
void log_info_key(const char * name, sm_key_t key){
// log_info("%-6s ", name);
// hexdump(key, 16);
#ifdef ENABLE_LOG_INFO
char buffer[16*2+1];
const uint8_t low = 0x0F;
const uint8_t high = 0xF0;
int i;
int j = 0;
for (i=0; i<16;i++){
uint8_t byte = key[i];
buffer[j++] = char_for_nibble((byte & high) >> 4);
buffer[j++] = char_for_nibble(byte & low);
}
buffer[j] = 0;
log_info("%-6s %s", name, buffer);
#endif
}
// UUIDs are stored in big endian, similar to bd_addr_t
@ -226,9 +245,19 @@ int uuid_has_bluetooth_prefix(uint8_t * uuid128){
static char uuid128_to_str_buffer[32+4+1];
char * uuid128_to_str(uint8_t * uuid){
sprintf(uuid128_to_str_buffer, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
int i;
int j = 0;
const uint8_t low = 0x0F;
const uint8_t high = 0xF0;
// after 4, 6, 8, and 10 bytes = XYXYXYXY-XYXY-XYXY-XYXY-XYXYXYXYXYXY, there's a dash
const int dash_locations = (1<<3) | (1<<5) | (1<<7) | (1<<9);
for (i=0;i<16;i++){
uuid128_to_str_buffer[j++] = char_for_nibble((uuid[i] & high) >> 4);
uuid128_to_str_buffer[j++] = char_for_nibble(uuid[i] & low);
if (dash_locations & (1<<i)){
uuid128_to_str_buffer[j++] = '-';
}
}
return uuid128_to_str_buffer;
}

View File

@ -785,7 +785,7 @@ static void bnep_channel_finalize(bnep_channel_t *channel)
static int bnep_handle_connection_request(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
{
uint16_t uuid_size;
uint16_t uuid_offset;
uint16_t uuid_offset = 0; // avoid "may be unitialized when used" in clang
uuid_size = packet[1];
uint16_t response_code = BNEP_RESP_SETUP_SUCCESS;
bnep_service_t * service;
@ -1193,7 +1193,7 @@ static int bnep_hci_event_handler(uint8_t *packet, uint16_t size)
if (channel) {
log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - channel already exists", l2cap_cid);
l2cap_decline_connection(l2cap_cid, 0x04); // no resources available
l2cap_decline_connection(l2cap_cid);
return 1;
}
@ -1202,7 +1202,7 @@ static int bnep_hci_event_handler(uint8_t *packet, uint16_t size)
if (!channel) {
log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - no memory left", l2cap_cid);
l2cap_decline_connection(l2cap_cid, 0x04); // no resources available
l2cap_decline_connection(l2cap_cid);
return 1;
}

View File

@ -250,7 +250,7 @@ void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subt
event[0] = HCI_EVENT_HFP_META;
event[1] = sizeof(event) - 2;
event[2] = event_subtype;
int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4;
int size = (strlen(value) < sizeof(event) - 4) ? (int) strlen(value) : sizeof(event) - 4;
strncpy((char*)&event[3], value, size);
event[3 + size] = 0;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));

View File

@ -281,7 +281,7 @@ static int string_len_for_uint32(uint32_t i){
// get size for indicator string
static int hfp_ag_indicators_string_size(hfp_connection_t * hfp_connection, int i){
// template: ("$NAME",($MIN,$MAX))
return 8 + strlen(hfp_ag_get_ag_indicators(hfp_connection)[i].name)
return 8 + (int) strlen(hfp_ag_get_ag_indicators(hfp_connection)[i].name)
+ string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range)
+ string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range);
}
@ -1049,6 +1049,7 @@ static void hfp_ag_set_callsetup_indicator(void){
hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callsetup");
if (!indicator){
log_error("hfp_ag_set_callsetup_indicator: callsetup indicator is missing");
return;
};
indicator->status = hfp_gsm_callsetup_status();
}
@ -1057,6 +1058,7 @@ static void hfp_ag_set_callheld_indicator(void){
hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld");
if (!indicator){
log_error("hfp_ag_set_callheld_state: callheld indicator is missing");
return;
};
indicator->status = hfp_gsm_callheld_status();
}
@ -1065,6 +1067,7 @@ static void hfp_ag_set_call_indicator(void){
hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call");
if (!indicator){
log_error("hfp_ag_set_call_state: call indicator is missing");
return;
};
indicator->status = hfp_gsm_call_status();
}
@ -1145,7 +1148,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL);
hfp_ag_set_callsetup_indicator();
hfp_ag_trigger_incoming_call();
printf("AG rings\n");
log_info("AG rings");
break;
default:
break;
@ -1157,7 +1160,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL);
hfp_ag_set_callsetup_indicator();
hfp_ag_trigger_incoming_call();
printf("AG call waiting\n");
log_info("AG call waiting");
break;
default:
break;
@ -1174,7 +1177,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_indicator();
hfp_ag_ag_accept_call();
printf("AG answers call, accept call by GSM\n");
log_info("AG answers call, accept call by GSM");
break;
default:
break;
@ -1183,7 +1186,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
switch (hfp_gsm_callsetup_status()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
printf("AG: current call is placed on hold, incoming call gets active\n");
log_info("AG: current call is placed on hold, incoming call gets active");
hfp_gsm_handle_event(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG);
hfp_ag_set_callsetup_indicator();
hfp_ag_set_callheld_indicator();
@ -1202,7 +1205,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
switch (hfp_gsm_callheld_status()){
case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED:
printf("AG: joining held call with active call\n");
log_info("AG: joining held call with active call");
hfp_gsm_handle_event(HFP_AG_HELD_CALL_JOINED_BY_AG);
hfp_ag_set_callheld_indicator();
hfp_ag_transfer_callheld_state();
@ -1226,7 +1229,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_callsetup_indicator();
hfp_ag_set_call_indicator();
hfp_ag_hf_accept_call(hfp_connection);
printf("HF answers call, accept call by GSM\n");
log_info("HF answers call, accept call by GSM");
hfp_emit_simple_event(hfp_callback, HFP_SUBEVENT_CALL_ANSWERED);
break;
default:
@ -1251,7 +1254,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_indicator();
hfp_ag_ag_accept_call();
printf("AG response and hold - hold by AG\n");
log_info("AG response and hold - hold by AG");
break;
default:
break;
@ -1275,7 +1278,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_call_indicator();
hfp_ag_set_callsetup_indicator();
hfp_ag_hf_accept_call(hfp_connection);
printf("AG response and hold - hold by HF\n");
log_info("AG response and hold - hold by HF");
break;
default:
break;
@ -1294,7 +1297,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_response_and_hold_active = 0;
hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED;
hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
printf("Held Call accepted and active\n");
log_info("Held Call accepted and active");
break;
case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
@ -1319,14 +1322,14 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_callsetup_indicator();
hfp_ag_transfer_callsetup_state();
hfp_ag_trigger_reject_call();
printf("HF Rejected Incoming call, AG terminate call\n");
log_info("HF Rejected Incoming call, AG terminate call");
break;
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE:
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_HF);
hfp_ag_set_callsetup_indicator();
hfp_ag_transfer_callsetup_state();
printf("AG terminate outgoing call process\n");
log_info("AG terminate outgoing call process");
default:
break;
}
@ -1336,7 +1339,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_call_indicator();
hfp_ag_transfer_call_state();
hfp_connection->call_state = HFP_CALL_IDLE;
printf("AG terminate call\n");
log_info("AG terminate call");
break;
}
break;
@ -1349,7 +1352,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_gsm_handle_event(HFP_AG_TERMINATE_CALL_BY_AG);
hfp_ag_set_callsetup_indicator();
hfp_ag_trigger_reject_call();
printf("AG Rejected Incoming call, AG terminate call\n");
log_info("AG Rejected Incoming call, AG terminate call");
break;
default:
break;
@ -1359,7 +1362,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_callsetup_indicator();
hfp_ag_set_call_indicator();
hfp_ag_trigger_terminate_call();
printf("AG terminate call\n");
log_info("AG terminate call");
break;
default:
break;
@ -1371,12 +1374,12 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
switch (hfp_gsm_callsetup_status()){
case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
hfp_ag_stop_ringing();
printf("Incoming call interrupted\n");
log_info("Incoming call interrupted");
break;
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE:
case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
printf("Outgoing call interrupted\n");
printf("AG notify call dropped\n");
log_info("Outgoing call interrupted\n");
log_info("AG notify call dropped\n");
break;
default:
break;
@ -1395,7 +1398,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_callsetup_indicator();
hfp_ag_set_call_indicator();
hfp_ag_trigger_terminate_call();
printf("AG notify call dropped\n");
log_info("AG notify call dropped");
break;
default:
break;
@ -1427,14 +1430,14 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_gsm_handle_event(HFP_AG_OUTGOING_REDIAL_INITIATED);
hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED;
printf("\nRedial last number");
log_info("Redial last number");
char * last_dialed_number = hfp_gsm_last_dialed_number();
if (strlen(last_dialed_number) > 0){
printf("\nLast number exists: accept call");
log_info("Last number exists: accept call");
hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, last_dialed_number);
} else {
printf("\nLast number missing: reject call");
log_info("log_infoLast number missing: reject call");
hfp_ag_outgoing_call_rejected();
}
break;
@ -1472,7 +1475,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
// put current call on hold if active
if (put_call_on_hold){
printf("AG putting current call on hold for new outgoing call\n");
log_info("AG putting current call on hold for new outgoing calllog_info");
hfp_ag_set_callheld_indicator();
indicator_index = get_ag_indicator_index_for_name("callheld");
hfp_ag_transfer_ag_indicators_status_cmd(hfp_connection->rfcomm_cid, &hfp_ag_indicators[indicator_index]);
@ -1525,7 +1528,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_ag_set_callsetup_indicator();
hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
hfp_connection->call_state = HFP_CALL_ACTIVE;
printf("AG: Call Waiting, User Busy\n");
log_info("AG: Call Waiting, User Busy");
break;
case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
@ -1539,11 +1542,11 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
}
if (call_setup_in_progress){
printf("AG: Call Dropped, Accept new call\n");
log_info("AG: Call Dropped, Accept new call");
hfp_ag_set_callsetup_indicator();
hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Call Dropped, Resume held call\n");
log_info("AG: Call Dropped, Resume held call");
}
if (call_held){
hfp_ag_set_callheld_indicator();
@ -1561,11 +1564,11 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
hfp_gsm_handle_event_with_call_index(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection->call_index);
if (call_setup_in_progress){
printf("AG: Call on Hold, Accept new call\n");
log_info("AG: Call on Hold, Accept new call");
hfp_ag_set_callsetup_indicator();
hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
} else {
printf("AG: Swap calls\n");
log_info("AG: Swap calls");
}
hfp_ag_set_callheld_indicator();
@ -1578,7 +1581,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
case HFP_AG_CALL_HOLD_ADD_HELD_CALL:
// Adds a held call to the conversation.
if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
printf("AG: Join 3-way-call\n");
log_info("AG: Join 3-way-call");
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_ADD_HELD_CALL);
hfp_ag_set_callheld_indicator();
hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
@ -1589,7 +1592,7 @@ static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_con
case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:
// Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
hfp_gsm_handle_event(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS);
printf("AG: Transfer call -> Connect two calls and disconnect\n");
log_info("AG: Transfer call -> Connect two calls and disconnect");
hfp_ag_set_call_indicator();
hfp_ag_set_callheld_indicator();
hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
@ -1624,7 +1627,7 @@ static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_
offset += snprintf(buffer+offset, sizeof(buffer)-offset, ", \"%s\",%u", number, type);
}
snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
printf("hfp_ag_send_current_call_status 000 index %d, dir %d, status %d, mode %d, mpty %d, type %d, number %s\n", idx, dir, status,
log_info("hfp_ag_send_current_call_status 000 index %d, dir %d, status %d, mode %d, mpty %d, type %d, number %s", idx, dir, status,
mode, mpty, type, number);
send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
}
@ -1830,7 +1833,7 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
break;
case HFP_CMD_RESPONSE_AND_HOLD_COMMAND:
value = atoi((char *)&hfp_connection->line_buffer[0]);
printf("HF Response and Hold: %u\n", value);
log_info("HF Response and Hold: %u", value);
switch(value){
case HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD:
hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, hfp_connection);
@ -1861,17 +1864,17 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
hfp_connection->send_error = 1;
return;
}
printf("HF Indicator 'enhanced security' set to %u\n", value);
log_info("HF Indicator 'enhanced security' set to %u", value);
break;
case 2: // battery level
if (value > 100){
hfp_connection->send_error = 1;
return;
}
printf("HF Indicator 'battery' set to %u\n", value);
log_info("HF Indicator 'battery' set to %u", value);
break;
default:
printf("HF Indicator unknown set to %u\n", value);
log_info("HF Indicator unknown set to %u", value);
break;
}
hfp_connection->ok_pending = 1;
@ -1908,14 +1911,14 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
if (get_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION)){
hfp_connection->ok_pending = 1;
hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION, hfp_connection->ag_echo_and_noise_reduction);
printf("AG: EC/NR = %u\n", hfp_connection->ag_echo_and_noise_reduction);
log_info("AG: EC/NR = %u", hfp_connection->ag_echo_and_noise_reduction);
} else {
hfp_connection->send_error = 1;
}
break;
case HFP_CMD_CALL_ANSWERED:
hfp_connection->command = HFP_CMD_NONE;
printf("HFP: ATA\n");
log_info("HFP: ATA");
hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, hfp_connection);
break;
case HFP_CMD_HANG_UP_CALL:
@ -1987,12 +1990,12 @@ static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_
case HFP_CMD_SET_SPEAKER_GAIN:
hfp_connection->command = HFP_CMD_NONE;
hfp_connection->ok_pending = 1;
printf("HF speaker gain = %u\n", hfp_connection->speaker_gain);
log_info("HF speaker gain = %u", hfp_connection->speaker_gain);
break;
case HFP_CMD_SET_MICROPHONE_GAIN:
hfp_connection->command = HFP_CMD_NONE;
hfp_connection->ok_pending = 1;
printf("HF microphone gain = %u\n", hfp_connection->microphone_gain);
log_info("HF microphone gain = %u", hfp_connection->microphone_gain);
break;
default:
break;
@ -2276,7 +2279,7 @@ void hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle, int activate
}
if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) {
printf("AG cannot acivate voice recognition - not supported by HF\n");
log_info("AG cannot acivate voice recognition - not supported by HF");
return;
}

View File

@ -224,7 +224,7 @@ static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * numb
gsm_calls[index_in_table].clip_type = type;
int clip_number_size = strlen(number) < HFP_GSM_MAX_CALL_NUMBER_SIZE ? strlen(number) : HFP_GSM_MAX_CALL_NUMBER_SIZE-1;
int clip_number_size = strlen(number) < HFP_GSM_MAX_CALL_NUMBER_SIZE ? (int) strlen(number) : HFP_GSM_MAX_CALL_NUMBER_SIZE-1;
strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size);
gsm_calls[index_in_table].clip_number[clip_number_size] = '\0';
strncpy(last_dialed_number, number, clip_number_size);

View File

@ -102,7 +102,7 @@ static void hfp_hf_emit_subscriber_information(btstack_packet_handler_t callback
event[2] = event_subtype;
event[3] = status;
event[4] = bnip_type;
int size = (strlen(bnip_number) < sizeof(event) - 6) ? strlen(bnip_number) : sizeof(event) - 6;
int size = (strlen(bnip_number) < sizeof(event) - 6) ? (int) strlen(bnip_number) : sizeof(event) - 6;
strncpy((char*)&event[5], bnip_number, size);
event[5 + size] = 0;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
@ -115,7 +115,7 @@ static void hfp_hf_emit_type_and_number(btstack_packet_handler_t callback, uint8
event[1] = sizeof(event) - 2;
event[2] = event_subtype;
event[3] = bnip_type;
int size = (strlen(bnip_number) < sizeof(event) - 5) ? strlen(bnip_number) : sizeof(event) - 5;
int size = (strlen(bnip_number) < sizeof(event) - 5) ? (int) strlen(bnip_number) : sizeof(event) - 5;
strncpy((char*)&event[4], bnip_number, size);
event[4 + size] = 0;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
@ -133,7 +133,7 @@ static void hfp_hf_emit_enhanced_call_status(btstack_packet_handler_t callback,
event[6] = clcc_status;
event[7] = clcc_mpty;
event[8] = bnip_type;
int size = (strlen(bnip_number) < sizeof(event) - 10) ? strlen(bnip_number) : sizeof(event) - 10;
int size = (strlen(bnip_number) < sizeof(event) - 10) ? (int) strlen(bnip_number) : sizeof(event) - 10;
strncpy((char*)&event[9], bnip_number, size);
event[9 + size] = 0;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
@ -835,7 +835,7 @@ static void hfp_run_for_context(hfp_connection_t * hfp_connection){
sprintf(buffer, "AT%s=%u,%u\r\n", HFP_TRANSFER_HF_INDICATOR_STATUS, hfp_indicators[i], hfp_indicators_value[i]);
send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
} else {
printf("Not sending HF indicator %u as it is disabled\n", hfp_indicators[i]);
log_info("Not sending HF indicator %u as it is disabled", hfp_indicators[i]);
}
return;
}
@ -944,7 +944,7 @@ static void hfp_hf_switch_on_ok(hfp_connection_t *hfp_connection){
switch (hfp_connection->hf_query_operator_state){
case HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK:
printf("Format set, querying name\n");
// printf("Format set, querying name\n");
hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SEND_QUERY;
break;
case HPF_HF_QUERY_OPERATOR_W4_RESULT:

View File

@ -287,7 +287,6 @@ void hsp_ag_connect(bd_addr_t bd_addr){
void hsp_ag_disconnect(void){
hsp_ag_release_audio_connection();
printf(" rfcomm diconnect %d\n", hsp_state);
if (hsp_state < HSP_W4_RFCOMM_CONNECTED){
hsp_state = HSP_IDLE;
return;
@ -302,8 +301,6 @@ void hsp_ag_disconnect(void){
}
void hsp_ag_establish_audio_connection(void){
printf("hsp_ag_establish_audio_connection state %d\n", hsp_state);
switch (hsp_state){
case HSP_RFCOMM_CONNECTION_ESTABLISHED:
hsp_establish_audio_connection = 1;

View File

@ -932,7 +932,7 @@ static int rfcomm_hci_event_handler(uint8_t *packet, uint16_t size){
if (multiplexer) {
log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - multiplexer already exists", l2cap_cid);
l2cap_decline_connection(l2cap_cid, 0x04); // no resources available
l2cap_decline_connection(l2cap_cid);
return 1;
}
@ -940,7 +940,7 @@ static int rfcomm_hci_event_handler(uint8_t *packet, uint16_t size){
multiplexer = rfcomm_multiplexer_create_for_addr(event_addr);
if (!multiplexer){
log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - no memory left", l2cap_cid);
l2cap_decline_connection(l2cap_cid, 0x04); // no resources available
l2cap_decline_connection(l2cap_cid);
return 1;
}
@ -2260,11 +2260,9 @@ uint8_t rfcomm_create_channel(btstack_packet_handler_t packet_handler, bd_addr_t
void rfcomm_disconnect(uint16_t rfcomm_cid){
log_info("RFCOMM_DISCONNECT cid 0x%02x", rfcomm_cid);
rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
if (channel) {
channel->state = RFCOMM_CHANNEL_SEND_DISC;
}
// process
if (!channel) return;
channel->state = RFCOMM_CHANNEL_SEND_DISC;
l2cap_request_can_send_now_event(channel->multiplexer->l2cap_cid);
}

View File

@ -495,7 +495,7 @@ static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
case L2CAP_EVENT_INCOMING_CONNECTION:
if (l2cap_cid) {
// CONNECTION REJECTED DUE TO LIMITED RESOURCES
l2cap_decline_connection(channel, 0x04);
l2cap_decline_connection(channel);
break;
}
// accept

View File

@ -248,7 +248,7 @@ void gap_advertisements_set_params(uint16_t adv_int_min, uint16_t adv_int_max, u
uint8_t direct_address_typ, bd_addr_t direct_address, uint8_t channel_map, uint8_t filter_policy);
/**
* @brief Enable/Disable Advertisements
* @brief Enable/Disable Advertisements. OFF by default.
* @param enabled
*/
void gap_advertisements_enable(int enabled);
@ -353,9 +353,18 @@ void gap_local_bd_addr(bd_addr_t address_buffer);
/**
* @brief Deletes link key for remote device with baseband address.
* @param addr
*/
void gap_drop_link_key_for_bd_addr(bd_addr_t addr);
/**
* @brief Store link key for remote device with baseband address
* @param addr
* @param link_key
* @param link_key_type
*/
void gap_store_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t type);
// LE
/**

107
src/hci.c
View File

@ -83,7 +83,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_emit_connection_complete(hci_connection_t *conn, uint8_t status);
static void hci_emit_connection_complete(bd_addr_t address, hci_con_handle_t con_handle, uint8_t status);
static void hci_emit_l2cap_check_timeout(hci_connection_t *conn);
static void hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason);
static void hci_emit_nr_connections_changed(void);
@ -263,9 +263,15 @@ int hci_authentication_active_for_handle(hci_con_handle_t handle){
}
void gap_drop_link_key_for_bd_addr(bd_addr_t addr){
if (hci_stack->link_key_db) {
hci_stack->link_key_db->delete_link_key(addr);
}
if (!hci_stack->link_key_db) return;
log_info("gap_drop_link_key_for_bd_addr: %s", bd_addr_to_str(addr));
hci_stack->link_key_db->delete_link_key(addr);
}
void gap_store_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t type){
if (!hci_stack->link_key_db) return;
log_info("gap_store_link_key_for_bd_addr: %s, type %u", bd_addr_to_str(addr), type);
hci_stack->link_key_db->put_link_key(addr, link_key, type);
}
static int hci_is_le_connection(hci_connection_t * connection){
@ -273,7 +279,6 @@ static int hci_is_le_connection(hci_connection_t * connection){
connection->address_type == BD_ADDR_TYPE_LE_RANDOM;
}
/**
* count connections
*/
@ -885,17 +890,18 @@ static void hci_initialization_timeout_handler(btstack_timer_source_t * ds){
hci_stack->num_cmd_packets = 1;
hci_run();
break;
case HCI_INIT_W4_SEND_BAUD_CHANGE: {
uint32_t baud_rate = hci_transport_uart_get_main_baud_rate();
log_info("Local baud rate change to %"PRIu32"(timeout handler)", baud_rate);
hci_stack->hci_transport->set_baudrate(baud_rate);
case HCI_INIT_W4_SEND_BAUD_CHANGE:
if (hci_stack->hci_transport->set_baudrate){
uint32_t baud_rate = hci_transport_uart_get_main_baud_rate();
log_info("Local baud rate change to %"PRIu32"(timeout handler)", baud_rate);
hci_stack->hci_transport->set_baudrate(baud_rate);
}
// For CSR, HCI Reset is sent on new baud rate
if (hci_stack->manufacturer == COMPANY_ID_CAMBRIDGE_SILICON_RADIO){
hci_stack->substate = HCI_INIT_SEND_RESET_CSR_WARM_BOOT;
hci_run();
}
break;
}
default:
break;
}
@ -1067,10 +1073,11 @@ static void hci_initializing_run(void){
if (hci_stack->local_name){
hci_send_cmd(&hci_write_local_name, hci_stack->local_name);
} else {
char local_name[30];
// BTstack-11:22:33:44:55:66
strcpy(local_name, "BTstack ");
strcat(local_name, bd_addr_to_str(hci_stack->local_bd_addr));
char local_name[8+17+1];
// BTstack 11:22:33:44:55:66
memcpy(local_name, "BTstack ", 8);
memcpy(&local_name[8], bd_addr_to_str(hci_stack->local_bd_addr), 17); // strlen(bd_addr_to_str(...)) = 17
local_name[8+17] = '\0';
log_info("---> Name %s", local_name);
hci_send_cmd(&hci_write_local_name, local_name);
}
@ -1248,7 +1255,7 @@ static void hci_initializing_event_handler(uint8_t * packet, uint16_t size){
case HCI_INIT_W4_SEND_BAUD_CHANGE:
// for STLC2500D, baud rate change already happened.
// for others, baud rate gets changed now
if (hci_stack->manufacturer != COMPANY_ID_ST_MICROELECTRONICS){
if ((hci_stack->manufacturer != COMPANY_ID_ST_MICROELECTRONICS) && need_baud_change){
uint32_t baud_rate = hci_transport_uart_get_main_baud_rate();
log_info("Local baud rate change to %"PRIu32"(w4_send_baud_change)", baud_rate);
hci_stack->hci_transport->set_baudrate(baud_rate);
@ -1274,17 +1281,18 @@ static void hci_initializing_event_handler(uint8_t * packet, uint16_t size){
}
hci_stack->substate = HCI_INIT_READ_BD_ADDR;
return;
case HCI_INIT_W4_SEND_BAUD_CHANGE_BCM: {
uint32_t baud_rate = hci_transport_uart_get_main_baud_rate();
log_info("Local baud rate change to %"PRIu32"(w4_send_baud_change_bcm))", baud_rate);
hci_stack->hci_transport->set_baudrate(baud_rate);
case HCI_INIT_W4_SEND_BAUD_CHANGE_BCM:
if (need_baud_change){
uint32_t baud_rate = hci_transport_uart_get_main_baud_rate();
log_info("Local baud rate change to %"PRIu32"(w4_send_baud_change_bcm))", baud_rate);
hci_stack->hci_transport->set_baudrate(baud_rate);
}
if (need_addr_change){
hci_stack->substate = HCI_INIT_SET_BD_ADDR;
return;
}
hci_stack->substate = HCI_INIT_READ_BD_ADDR;
return;
}
case HCI_INIT_W4_SET_BD_ADDR:
// for STLC2500D, bd addr change only gets active after sending reset command
if (hci_stack->manufacturer == COMPANY_ID_ST_MICROELECTRONICS){
@ -1636,8 +1644,7 @@ static void event_handler(uint8_t *packet, int size){
if (link_key_type != CHANGED_COMBINATION_KEY){
conn->link_key_type = link_key_type;
}
if (!hci_stack->link_key_db) break;
hci_stack->link_key_db->put_link_key(addr, &packet[8], conn->link_key_type);
gap_store_link_key_for_bd_addr(addr, &packet[8], conn->link_key_type);
// still forward event to allow dismiss of pairing dialog
break;
}
@ -1715,9 +1722,17 @@ static void event_handler(uint8_t *packet, int size){
case HCI_EVENT_DISCONNECTION_COMPLETE:
if (packet[2]) break; // status != 0
handle = little_endian_read_16(packet, 3);
conn = hci_connection_for_handle(handle);
if (!conn) break; // no conn struct anymore
// drop outgoing ACL fragments if it is for closed connection
if (hci_stack->acl_fragmentation_total_size > 0) {
if (handle == READ_ACL_CONNECTION_HANDLE(hci_stack->hci_packet_buffer)){
log_info("hci: drop fragmented ACL data for closed connection");
hci_stack->acl_fragmentation_total_size = 0;
hci_stack->acl_fragmentation_pos = 0;
}
}
// re-enable advertisements for le connections if active
conn = hci_connection_for_handle(handle);
if (!conn) break;
if (hci_is_le_connection(conn) && hci_stack->le_advertisements_enabled){
hci_stack->le_advertisements_todo |= LE_ADVERTISEMENT_TASKS_ENABLE;
}
@ -1725,8 +1740,9 @@ static void event_handler(uint8_t *packet, int size){
break;
case HCI_EVENT_HARDWARE_ERROR:
log_error("Hardware Error: 0x%02x", packet[2]);
if (hci_stack->hardware_error_callback){
(*hci_stack->hardware_error_callback)();
(*hci_stack->hardware_error_callback)(packet[2]);
} else {
// if no special requests, just reboot stack
hci_power_control_off();
@ -1973,6 +1989,9 @@ void hci_init(const hci_transport_t *transport, const void *config){
// reference to used config
hci_stack->config = config;
// setup pointer for outgoing packet buffer
hci_stack->hci_packet_buffer = &hci_stack->hci_packet_buffer_data[HCI_OUTGOING_PRE_BUFFER_SIZE];
// max acl payload size defined in config.h
hci_stack->acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
@ -2026,11 +2045,16 @@ void hci_close(void){
if (hci_stack->link_key_db) {
hci_stack->link_key_db->close();
}
while (hci_stack->connections) {
// cancel all l2cap connections
hci_emit_disconnection_complete(((hci_connection_t *) hci_stack->connections)->con_handle, 0x16); // terminated by local host
hci_shutdown_connection((hci_connection_t *) hci_stack->connections);
btstack_linked_list_iterator_t lit;
btstack_linked_list_iterator_init(&lit, &hci_stack->connections);
while (btstack_linked_list_iterator_has_next(&lit)){
// cancel all l2cap connections by emitting dicsconnection complete before shutdown (free) connection
hci_connection_t * connection = (hci_connection_t*) btstack_linked_list_iterator_next(&lit);
hci_emit_disconnection_complete(connection->con_handle, 0x16); // terminated by local host
hci_shutdown_connection(connection);
}
hci_power_control(HCI_POWER_OFF);
#ifdef HAVE_MALLOC
@ -2343,16 +2367,18 @@ static void hci_run(void){
// send continuation fragments first, as they block the prepared packet buffer
if (hci_stack->acl_fragmentation_total_size > 0) {
hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(hci_stack->hci_packet_buffer);
if (hci_can_send_prepared_acl_packet_now(con_handle)){
hci_connection_t *connection = hci_connection_for_handle(con_handle);
if (connection) {
hci_connection_t *connection = hci_connection_for_handle(con_handle);
if (connection) {
if (hci_can_send_prepared_acl_packet_now(con_handle)){
hci_send_acl_packet_fragments(connection);
return;
}
}
} else {
// connection gone -> discard further fragments
log_info("hci_run: fragmented ACL packet no connection -> discard fragment");
hci_stack->acl_fragmentation_total_size = 0;
hci_stack->acl_fragmentation_pos = 0;
}
}
}
if (!hci_can_send_command_packet_now()) return;
@ -2790,7 +2816,7 @@ int hci_send_cmd_packet(uint8_t *packet, int size){
conn = create_connection_for_bd_addr_and_type(addr, BD_ADDR_TYPE_CLASSIC);
if (!conn){
// notify client that alloc failed
hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
hci_emit_connection_complete(addr, 0, BTSTACK_MEMORY_ALLOC_FAILED);
return 0; // don't sent packet to controller
}
conn->state = SEND_CREATE_CONNECTION;
@ -2800,7 +2826,7 @@ int hci_send_cmd_packet(uint8_t *packet, int size){
// if connection active exists
case OPEN:
// and OPEN, emit connection complete command, don't send to controller
hci_emit_connection_complete(conn, 0);
hci_emit_connection_complete(addr, conn->con_handle, 0);
return 0;
case SEND_CREATE_CONNECTION:
// connection created by hci, e.g. dedicated bonding
@ -2993,13 +3019,13 @@ void hci_emit_state(void){
hci_emit_event(event, sizeof(event), 1);
}
static void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
static void hci_emit_connection_complete(bd_addr_t address, hci_con_handle_t con_handle, uint8_t status){
uint8_t event[13];
event[0] = HCI_EVENT_CONNECTION_COMPLETE;
event[1] = sizeof(event) - 2;
event[2] = status;
little_endian_store_16(event, 3, conn->con_handle);
reverse_bd_addr(conn->address, &event[5]);
little_endian_store_16(event, 3, con_handle);
reverse_bd_addr(address, &event[5]);
event[11] = 1; // ACL connection
event[12] = 0; // encryption disabled
hci_emit_event(event, sizeof(event), 1);
@ -3088,7 +3114,6 @@ static void hci_emit_dedicated_bonding_result(bd_addr_t address, uint8_t status)
event[pos++] = sizeof(event) - 2;
event[pos++] = status;
reverse_bd_addr(address, &event[pos]);
pos += 6;
hci_emit_event(event, sizeof(event), 1);
}
@ -3589,7 +3614,7 @@ int hci_get_sco_packet_length(void){
/**
* @brief Set callback for Bluetooth Hardware Error
*/
void hci_set_hardware_error_callback(void (*fn)(void)){
void hci_set_hardware_error_callback(void (*fn)(uint8_t error)){
hci_stack->hardware_error_callback = fn;
}

View File

@ -271,7 +271,7 @@ typedef enum {
// state = 35
SM_RESPONDER_IDLE,
SM_RESPONDER_SEND_SECURITY_REQUEST,
SM_RESPONDER_PH0_RECEIVED_LTK,
SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST,
SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY,
SM_RESPONDER_PH1_W4_PAIRING_REQUEST,
SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED,
@ -287,7 +287,7 @@ typedef enum {
SM_RESPONDER_PH4_Y_W4_ENC,
SM_RESPONDER_PH4_LTK_GET_ENC,
SM_RESPONDER_PH4_LTK_W4_ENC,
SM_RESPONDER_PH4_SEND_LTK,
SM_RESPONDER_PH4_SEND_LTK_REPLY,
// INITITIATOR ROLE
// state = 51
@ -303,6 +303,7 @@ typedef enum {
SM_INITIATOR_PH3_SEND_START_ENCRYPTION,
// LE Secure Connections
SM_SC_RECEIVED_LTK_REQUEST,
SM_SC_SEND_PUBLIC_KEY_COMMAND,
SM_SC_W4_PUBLIC_KEY_COMMAND,
SM_SC_W2_GET_RANDOM_A,
@ -333,7 +334,10 @@ typedef enum {
SM_SC_SEND_DHKEY_CHECK_COMMAND,
SM_SC_W4_DHKEY_CHECK_COMMAND,
SM_SC_W4_LTK_REQUEST_SC,
SM_SC_W2_CALCULATE_H6_ILK,
SM_SC_W4_CALCULATE_H6_ILK,
SM_SC_W2_CALCULATE_H6_BR_EDR_LINK_KEY,
SM_SC_W4_CALCULATE_H6_BR_EDR_LINK_KEY,
} security_manager_state_t;
typedef enum {
@ -566,7 +570,7 @@ typedef struct {
void (*local_version_information_callback)(uint8_t * local_version_information);
// hardware error callback
void (*hardware_error_callback)(void);
void (*hardware_error_callback)(uint8_t error);
// basic configuration
const char * local_name;
@ -578,8 +582,8 @@ typedef struct {
uint8_t ssp_auto_accept;
// single buffer for HCI packet assembly + additional prebuffer for H4 drivers
uint8_t hci_packet_buffer_prefix[HCI_OUTGOING_PRE_BUFFER_SIZE];
uint8_t hci_packet_buffer[HCI_PACKET_BUFFER_SIZE]; // opcode (16), len(8)
uint8_t * hci_packet_buffer;
uint8_t hci_packet_buffer_data[HCI_OUTGOING_PRE_BUFFER_SIZE + HCI_PACKET_BUFFER_SIZE];
uint8_t hci_packet_buffer_reserved;
uint16_t acl_fragmentation_pos;
uint16_t acl_fragmentation_total_size;
@ -709,7 +713,7 @@ void hci_set_link_key_db(btstack_link_key_db_t const * link_key_db);
/**
* @brief Set callback for Bluetooth Hardware Error
*/
void hci_set_hardware_error_callback(void (*fn)(void));
void hci_set_hardware_error_callback(void (*fn)(uint8_t error));
/**
* @brief Set callback for local information from Bluetooth controller right after HCI Reset

View File

@ -176,12 +176,13 @@ void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t
case HCI_DUMP_STDOUT: {
/* Obtain the time of day, and convert it to a tm struct. */
ptm = localtime (&curr_time_secs);
/* assert localtime was successful */
if (!ptm) break;
/* Format the date and time, down to a single second. */
strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
/* Compute milliseconds from microseconds. */
uint16_t milliseconds = curr_time.tv_usec / 1000;
/* Print the formatted time, in seconds, followed by a decimal point
and the milliseconds. */
/* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */
printf ("%s.%03u] ", time_string, milliseconds);
printf_packet(packet_type, in, packet, len);
break;
@ -191,8 +192,8 @@ void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t
little_endian_store_16( header_bluez, 0, 1 + len);
header_bluez[2] = in;
header_bluez[3] = 0;
little_endian_store_32( header_bluez, 4, curr_time.tv_sec);
little_endian_store_32( header_bluez, 8, curr_time.tv_usec);
little_endian_store_32( header_bluez, 4, (uint32_t) curr_time.tv_sec);
little_endian_store_32( header_bluez, 8, curr_time.tv_usec);
header_bluez[12] = packet_type;
write (dump_file, header_bluez, HCIDUMP_HDR_SIZE);
write (dump_file, packet, len );
@ -200,7 +201,7 @@ void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t
case HCI_DUMP_PACKETLOGGER:
big_endian_store_32( header_packetlogger, 0, PKTLOG_HDR_SIZE - 4 + len);
big_endian_store_32( header_packetlogger, 4, curr_time.tv_sec);
big_endian_store_32( header_packetlogger, 4, (uint32_t) curr_time.tv_sec);
big_endian_store_32( header_packetlogger, 8, curr_time.tv_usec);
switch (packet_type){
case HCI_COMMAND_DATA_PACKET:

View File

@ -149,6 +149,10 @@ void hci_transport_h5_set_auto_sleep(uint16_t inactivity_timeout_ms);
*/
const hci_transport_t * hci_transport_usb_instance(void);
/**
* @brief Specify USB Bluetooth device via port numbers from root to device
*/
void hci_transport_usb_set_path(int len, uint8_t * port_numbers);
/* API_END */

View File

@ -50,16 +50,17 @@
#include "hci_transport.h"
#include "btstack_uart_block.h"
#define ENABLE_LOG_EHCILL
#ifdef ENABLE_EHCILL
// eHCILL commands
#define EHCILL_GO_TO_SLEEP_IND 0x030
#define EHCILL_GO_TO_SLEEP_ACK 0x031
#define EHCILL_WAKE_UP_IND 0x032
#define EHCILL_WAKE_UP_ACK 0x033
static const uint8_t EHCILL_GO_TO_SLEEP_IND = 0x030;
static const uint8_t EHCILL_GO_TO_SLEEP_ACK = 0x031;
static const uint8_t EHCILL_WAKE_UP_IND = 0x032;
static const uint8_t EHCILL_WAKE_UP_ACK = 0x033;
static int hci_transport_h4_ehcill_outgoing_packet_ready(void);
static int hci_transport_h4_ehcill_sleep_mode_active(void);
static void hci_transport_h4_echill_send_wakeup_ind(void);
static void hci_transport_h4_ehcill_handle_command(uint8_t action);
static void hci_transport_h4_ehcill_handle_ehcill_command_sent(void);
@ -71,8 +72,9 @@ static void hci_transport_h4_ehcill_sleep_ack_timer_setup(void);
static void hci_transport_h4_ehcill_trigger_wakeup(void);
typedef enum {
EHCILL_STATE_W2_SEND_SLEEP_ACK,
EHCILL_STATE_SLEEP,
EHCILL_STATE_W4_ACK,
EHCILL_STATE_W4_WAKEUP_IND_OR_ACK,
EHCILL_STATE_AWAKE
} EHCILL_STATE;
@ -258,9 +260,14 @@ static int hci_transport_h4_send_packet(uint8_t packet_type, uint8_t * packet, i
tx_data = packet;
#ifdef ENABLE_EHCILL
if (hci_transport_h4_ehcill_sleep_mode_active()){
hci_transport_h4_ehcill_trigger_wakeup();
return 0;
switch (ehcill_state){
case EHCILL_STATE_SLEEP:
hci_transport_h4_ehcill_trigger_wakeup();
return 0;
case EHCILL_STATE_W2_SEND_SLEEP_ACK:
return 0;
default:
break;
}
#endif
@ -347,9 +354,12 @@ static void hci_transport_h4_ehcill_open(void){
}
static void hci_transport_h4_echill_send_wakeup_ind(void){
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: send WAKEUP_IND");
#endif
// update state
tx_state = TX_W4_WAKEUP;
ehcill_state = EHCILL_STATE_W4_ACK;
ehcill_state = EHCILL_STATE_W4_WAKEUP_IND_OR_ACK;
ehcill_command_to_send = EHCILL_WAKE_UP_IND;
btstack_uart->send_block(&ehcill_command_to_send, 1);
}
@ -358,28 +368,33 @@ static int hci_transport_h4_ehcill_outgoing_packet_ready(void){
return tx_len != 0;
}
static int hci_transport_h4_ehcill_sleep_mode_active(void){
return ehcill_state == EHCILL_STATE_SLEEP;
}
static void hci_transport_h4_ehcill_reset_statemachine(void){
ehcill_state = EHCILL_STATE_AWAKE;
}
static void hci_transport_h4_ehcill_send_ehcill_command(void){
log_debug("eHCILL: send command %02x", ehcill_command_to_send);
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: send command %02x", ehcill_command_to_send);
#endif
tx_state = TX_W4_EHCILL_SENT;
if (ehcill_command_to_send == EHCILL_GO_TO_SLEEP_ACK){
ehcill_state = EHCILL_STATE_SLEEP;
}
btstack_uart->send_block(&ehcill_command_to_send, 1);
}
static void hci_transport_h4_ehcill_sleep_ack_timer_handler(btstack_timer_source_t * timer){
log_debug("eHCILL: timer triggered");
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: timer triggered");
#endif
hci_transport_h4_ehcill_send_ehcill_command();
}
static void hci_transport_h4_ehcill_sleep_ack_timer_setup(void){
// setup timer
log_debug("eHCILL: set timer for sending command");
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: set timer for sending command %02x", ehcill_command_to_send);
#endif
btstack_run_loop_set_timer_handler(&ehcill_sleep_ack_timer, &hci_transport_h4_ehcill_sleep_ack_timer_handler);
btstack_run_loop_set_timer(&ehcill_sleep_ack_timer, 50);
btstack_run_loop_add_timer(&ehcill_sleep_ack_timer);
@ -403,7 +418,10 @@ static void hci_transport_h4_ehcill_trigger_wakeup(void){
hci_transport_h4_echill_send_wakeup_ind();
}
static void hci_transport_h4_ehcill_schedule_ecill_command(uint8_t command){
static void hci_transport_h4_ehcill_schedule_ehcill_command(uint8_t command){
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: schedule eHCILL command %02x", command);
#endif
ehcill_command_to_send = command;
switch (tx_state){
case TX_IDLE:
@ -427,9 +445,11 @@ static void hci_transport_h4_ehcill_handle_command(uint8_t action){
case EHCILL_STATE_AWAKE:
switch(action){
case EHCILL_GO_TO_SLEEP_IND:
ehcill_state = EHCILL_STATE_SLEEP;
log_info("eHCILL: GO_TO_SLEEP_IND RX");
hci_transport_h4_ehcill_schedule_ecill_command(EHCILL_GO_TO_SLEEP_ACK);
ehcill_state = EHCILL_STATE_W2_SEND_SLEEP_ACK;
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: Received GO_TO_SLEEP_IND RX");
#endif
hci_transport_h4_ehcill_schedule_ehcill_command(EHCILL_GO_TO_SLEEP_ACK);
break;
default:
break;
@ -437,11 +457,14 @@ static void hci_transport_h4_ehcill_handle_command(uint8_t action){
break;
case EHCILL_STATE_SLEEP:
case EHCILL_STATE_W2_SEND_SLEEP_ACK:
switch(action){
case EHCILL_WAKE_UP_IND:
ehcill_state = EHCILL_STATE_AWAKE;
log_info("eHCILL: WAKE_UP_IND RX");
hci_transport_h4_ehcill_schedule_ecill_command(EHCILL_WAKE_UP_ACK);
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: Received WAKE_UP_IND RX");
#endif
hci_transport_h4_ehcill_schedule_ehcill_command(EHCILL_WAKE_UP_ACK);
break;
default:
@ -449,11 +472,13 @@ static void hci_transport_h4_ehcill_handle_command(uint8_t action){
}
break;
case EHCILL_STATE_W4_ACK:
case EHCILL_STATE_W4_WAKEUP_IND_OR_ACK:
switch(action){
case EHCILL_WAKE_UP_IND:
case EHCILL_WAKE_UP_ACK:
log_info("eHCILL: WAKE_UP_IND or ACK");
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: Received WAKE_UP (%02x)", action);
#endif
tx_state = TX_W4_PACKET_SENT;
ehcill_state = EHCILL_STATE_AWAKE;
btstack_uart->send_block(tx_data, tx_len);
@ -466,6 +491,9 @@ static void hci_transport_h4_ehcill_handle_command(uint8_t action){
}
static void hci_transport_h4_ehcill_handle_packet_sent(void){
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: handle packet sent, command to send %02x", ehcill_command_to_send);
#endif
// now, send pending ehcill command if neccessary
switch (ehcill_command_to_send){
case EHCILL_GO_TO_SLEEP_ACK:
@ -483,8 +511,15 @@ static void hci_transport_h4_ehcill_handle_ehcill_command_sent(void){
tx_state = TX_IDLE;
int command = ehcill_command_to_send;
ehcill_command_to_send = 0;
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: handle eHCILL sent, command was %02x", command);
#endif
if (command == EHCILL_GO_TO_SLEEP_ACK) {
#ifdef ENABLE_LOG_EHCILL
log_info("eHCILL: GO_TO_SLEEP_ACK sent, enter sleep mode");
#endif
// UART not needed after EHCILL_GO_TO_SLEEP_ACK was sent
if (btstack_uart_sleep_mode != BTSTACK_UART_SLEEP_OFF){
btstack_uart->set_sleep(btstack_uart_sleep_mode);
@ -495,7 +530,9 @@ static void hci_transport_h4_ehcill_handle_ehcill_command_sent(void){
if (btstack_uart_sleep_mode){
btstack_uart->set_sleep(BTSTACK_UART_SLEEP_OFF);
}
hci_transport_h4_echill_send_wakeup_ind();
if (command != EHCILL_WAKE_UP_IND){
hci_transport_h4_echill_send_wakeup_ind();
}
}
}

View File

@ -304,7 +304,7 @@ static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts
static void l2cap_rtx_timeout(btstack_timer_source_t * ts){
l2cap_channel_t * channel = l2cap_channel_for_rtx_timer(ts);
if (!ts) return;
if (!channel) return;
log_info("l2cap_rtx_timeout for local cid 0x%02x", channel->local_cid);
@ -1131,15 +1131,15 @@ void l2cap_accept_connection(uint16_t local_cid){
l2cap_run();
}
void l2cap_decline_connection(uint16_t local_cid, uint8_t reason){
log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x, reason %x", local_cid, reason);
void l2cap_decline_connection(uint16_t local_cid){
log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x", local_cid);
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
if (!channel) {
log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
return;
}
channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
channel->reason = reason;
channel->reason = 0x04; // no resources available
l2cap_run();
}
@ -1560,18 +1560,20 @@ uint8_t l2cap_register_service(btstack_packet_handler_t service_packet_handler,
return 0;
}
void l2cap_unregister_service(uint16_t psm){
uint8_t l2cap_unregister_service(uint16_t psm){
log_info("L2CAP_UNREGISTER_SERVICE psm 0x%x", psm);
l2cap_service_t *service = l2cap_get_service(psm);
if (!service) return;
if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
btstack_linked_list_remove(&l2cap_services, (btstack_linked_item_t *) service);
btstack_memory_l2cap_service_free(service);
// disable page scan when no services registered
if (!btstack_linked_list_empty(&l2cap_services)) return;
gap_connectable_control(0);
if (btstack_linked_list_empty(&l2cap_services)) {
gap_connectable_control(0);
}
return 0;
}
// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol

View File

@ -234,7 +234,7 @@ uint8_t l2cap_register_service(btstack_packet_handler_t packet_handler, uint16_t
/**
* @brief Unregisters L2CAP service with given PSM. On embedded systems, use NULL for connection parameter.
*/
void l2cap_unregister_service(uint16_t psm);
uint8_t l2cap_unregister_service(uint16_t psm);
/**
* @brief Accepts incoming L2CAP connection.
@ -244,7 +244,7 @@ void l2cap_accept_connection(uint16_t local_cid);
/**
* @brief Deny incoming L2CAP connection.
*/
void l2cap_decline_connection(uint16_t local_cid, uint8_t reason);
void l2cap_decline_connection(uint16_t local_cid);
/**
* @brief Check if outgoing buffer is available and that there's space on the Bluetooth module

View File

@ -43,6 +43,7 @@
#include "l2cap_signaling.h"
#include "btstack_config.h"
#include "btstack_debug.h"
#include "hci.h"
#include <string.h>
@ -60,7 +61,12 @@ static const char *l2cap_signaling_commands_format[] = {
"2", // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
"22D", // 0x0b information response: InfoType, Result, Data
#ifdef ENABLE_BLE
// skip 6 not supported signaling pdus, see below
NULL, // 0x0c non-supported AMP command
NULL, // 0x0d non-supported AMP command
NULL, // 0x0e non-supported AMP command
NULL, // 0x0f non-supported AMP command
NULL, // 0x10 non-supported AMP command
NULL, // 0x11 non-supported AMP command
"2222", // 0x12 connection parameter update request: interval min, interval max, slave latency, timeout multipler
"2", // 0x13 connection parameter update response: result
"22222", // 0X14 le credit based connection request: le psm, source cid, mtu, mps, initial credits
@ -69,6 +75,8 @@ static const char *l2cap_signaling_commands_format[] = {
#endif
};
static const int num_l2cap_commands = sizeof(l2cap_signaling_commands_format) / sizeof(const char *);
uint8_t sig_seq_nr = 0xff;
uint16_t source_cid = 0x40;
@ -87,6 +95,15 @@ uint16_t l2cap_next_local_cid(void){
static uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_handle_t handle, uint16_t cid, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
const char *format = NULL;
if (cmd > 0 && cmd <= num_l2cap_commands) {
format = l2cap_signaling_commands_format[cmd-1];
}
if (!format){
log_error("l2cap_create_signaling_internal: invalid command id 0x%02x", cmd);
return 0;
}
int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
// 0 - Connection handle : PB=pb : BC=00
@ -100,11 +117,6 @@ static uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_ha
// 12 - L2CAP signaling parameters
uint16_t pos = 12;
// skip AMP commands
if (cmd >= CONNECTION_PARAMETER_UPDATE_REQUEST){
cmd = (L2CAP_SIGNALING_COMMANDS) (((int) cmd) - 6);
}
const char *format = l2cap_signaling_commands_format[cmd-1];
uint16_t word;
uint8_t * ptr;
while (*format) {

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_POSIX_TIME
#define HAVE_MALLOC

View File

@ -1,2 +1,4 @@
remote_device_db_fs_test
remote_device_db_memory_test
btstack_link_key_db_fs_test
btstack_link_key_db_memory_test

View File

@ -6,7 +6,6 @@
#define __BTSTACK_CONFIG
// Port related features
#define HAVE_INIT_SCRIPT
#define HAVE_POSIX_TIME
// BTstack features that can be enabled

View File

@ -121,7 +121,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(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash)){
void sm_cmac_signed_write_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash)){
//sm_notify_client(SM_EVENT_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

@ -8,6 +8,16 @@ btstack_linked_item_t itemB;
btstack_linked_item_t itemC;
btstack_linked_item_t itemD;
TEST_GROUP(LinkedListEmpty){
void setup(void){
testList = NULL;
}
};
TEST(LinkedListEmpty, CountAll){
CHECK_EQUAL(0, btstack_linked_list_count(&testList));
}
TEST_GROUP(LinkedList){
void setup(void){
testList = NULL;
@ -18,6 +28,10 @@ TEST_GROUP(LinkedList){
}
};
TEST(LinkedList, CountAll){
CHECK_EQUAL(4, btstack_linked_list_count(&testList));
}
TEST(LinkedList, Iterator){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &testList);

View File

@ -3,7 +3,7 @@ BTSTACK_ROOT = ../..
CORE += main.c stdin_support.c
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c
COMMON += hci_transport_h2_libusb.c btstack_run_loop_posix.c btstack_link_key_db_fs.c le_device_db_fs.c
include ${BTSTACK_ROOT}/example/Makefile.inc

View File

@ -272,7 +272,7 @@ static void handle_advertising_event(uint8_t * packet, int size){
for (ad_iterator_init(&context, adv_size, (uint8_t *)adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
uint8_t data_type = ad_iterator_get_data_type(&context);
// uint8_t size = ad_iterator_get_data_len(&context);
const uint8_t * data = ad_iterator_get_data(&context);
const uint8_t * data = ad_iterator_get_data(&context);
switch (data_type){
case 1: // AD_FLAGS
if (*data & 1) printf("LE Limited Discoverable Mode, ");
@ -1457,7 +1457,7 @@ static void ui_process_command(char buffer){
// fetch 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);
sm_cmac_signed_write_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;
case 'x':
sm_min_key_size = 7;

View File

@ -97,7 +97,7 @@ void mock_simulate_sm_data_packet(uint8_t * packet, uint16_t len){
}
void mock_simulate_command_complete(const hci_cmd_t *cmd){
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, cmd->opcode & 0xff, cmd->opcode >> 8, 0};
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, (uint8_t) cmd->opcode & 0xff, (uint8_t) cmd->opcode >> 8, 0};
mock_simulate_hci_event((uint8_t *)&packet, sizeof(packet));
}
@ -118,6 +118,12 @@ void att_init_connection(att_connection_t * att_connection){
att_connection->authorized = 0;
}
void gap_local_bd_addr(bd_addr_t address_buffer){
int i;
for (i=0;i<6;i++) {
address_buffer[i] = 0x11 * (i+1);
}
}
int hci_can_send_command_packet_now(void){
return 1;
}

View File

@ -275,7 +275,7 @@ TEST(SecurityManager, CMACTest){
parse_hex(key, key_string);
uint8_t message [] = "hallo";
cmac_hash_received = 0;
sm_cmac_start(key, 0x11, 0x1234, sizeof(message), message, 1, &cmac_done);
sm_cmac_signed_write_start(key, 0x11, 0x1234, sizeof(message), message, 1, &cmac_done);
while (!cmac_hash_received){
aes128_report_result();
}

View File

@ -143,7 +143,7 @@ static inline uint8_t hci_event_{meta_event}_meta_get_subevent_code(const uint8_
'''
# global variables/defines
gen_path = '../src/btstack_event.h'
# gen_path = '../src/btstack_event.h'
defines = dict()
defines_used = set()
@ -264,8 +264,8 @@ def create_events(events):
fout.write(hfile_header_end)
# set root
parser.set_btstack_root('..')
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
gen_path = btstack_root + '/src/btstack_event.h'
print(program_info)