mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-11 00:44:27 +00:00
Merge branch 'develop' into a2dp
This commit is contained in:
commit
8cff923e81
3
3rd-party/mbedtls/include/mbedtls/config.h
vendored
3
3rd-party/mbedtls/include/mbedtls/config.h
vendored
@ -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 */
|
||||
|
99
3rd-party/mbedtls/library/ecp.c
vendored
99
3rd-party/mbedtls/library/ecp.c
vendored
@ -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 );
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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){
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
382
platform/posix/le_device_db_fs.c
Normal file
382
platform/posix/le_device_db_fs.c
Normal 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);
|
||||
}
|
||||
}
|
58
platform/posix/le_device_db_fs.h
Normal file
58
platform/posix/le_device_db_fs.h
Normal 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
|
@ -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
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_EMBEDDED_TICK
|
||||
|
||||
// BTstack features that can be enabled
|
||||
|
16
port/libusb/.gitignore
vendored
16
port/libusb/.gitignore
vendored
@ -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
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_EMBEDDED_TICK
|
||||
|
||||
// BTstack features that can be enabled
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_EMBEDDED_TICK
|
||||
|
||||
// BTstack features that can be enabled
|
||||
|
27
port/posix-h4/.gitignore
vendored
27
port/posix-h4/.gitignore
vendored
@ -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
|
@ -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 \
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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 \
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_EMBEDDED_TICK
|
||||
|
||||
// BTstack features that can be enabled
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
333
src/ble/sm.c
333
src/ble/sm.c
@ -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();
|
||||
|
30
src/ble/sm.h
30
src/ble/sm.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
11
src/gap.h
11
src/gap.h
@ -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
107
src/hci.c
@ -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;
|
||||
}
|
||||
|
||||
|
18
src/hci.h
18
src/hci.h
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
18
src/l2cap.c
18
src/l2cap.c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_POSIX_TIME
|
||||
#define HAVE_MALLOC
|
||||
|
||||
|
2
test/btstack_link_key_db/.gitignore
vendored
2
test/btstack_link_key_db/.gitignore
vendored
@ -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
|
@ -6,7 +6,6 @@
|
||||
#define __BTSTACK_CONFIG
|
||||
|
||||
// Port related features
|
||||
#define HAVE_INIT_SCRIPT
|
||||
#define HAVE_POSIX_TIME
|
||||
|
||||
// BTstack features that can be enabled
|
||||
|
@ -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 ){
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user