mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
support dedicated bonding and provide example for it
This commit is contained in:
parent
6724cd9e0e
commit
ad83dc6a89
@ -55,7 +55,7 @@ ATT_OBJ = $(ATT:.c=.o)
|
||||
|
||||
# create firmware image from common objects and example source file
|
||||
|
||||
all: ../../include/btstack/version.h ble_client ble_client_uart sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral ble_peripheral_sm_minimal
|
||||
all: ../../include/btstack/version.h ble_client ble_client_uart gap_dedicated_bonding sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral ble_peripheral_sm_minimal
|
||||
|
||||
#spp-usb l2cap-server-usb l2cap-client-usb l2cap-server-uart l2cap-client-uart
|
||||
|
||||
@ -74,6 +74,9 @@ spp_counter: ${CORE_OBJ} ${COMMON_OBJ} spp_counter.c
|
||||
spp_counter_ssp: ${CORE_OBJ} ${COMMON_OBJ} spp_counter_ssp.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
||||
gap_dedicated_bonding: ${CORE_OBJ} ${COMMON_OBJ} gap_dedicated_bonding.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
||||
# compile .ble description
|
||||
profile.h: profile.gatt
|
||||
python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@
|
||||
|
@ -244,10 +244,13 @@ extern "C" {
|
||||
#define SM_AUTHORIZATION_REQUEST 0xb9
|
||||
#define SM_AUTHORIZATION_RESULT 0xba
|
||||
|
||||
// GAP SECURITY
|
||||
// GAP
|
||||
|
||||
// data: event(8), len(8), hci_handle (16), security_level (8)
|
||||
#define GAP_SECURITY_LEVEL 0xc0
|
||||
// data: event(8), len(8), hci_handle (16), security_level (8)
|
||||
#define GAP_SECURITY_LEVEL 0xc0
|
||||
|
||||
// data: event(8), len(8), status (8), bd_addr(48)
|
||||
#define GAP_DEDICATED_BONDING_COMPLETED 0xc1
|
||||
|
||||
// Error Code
|
||||
#define ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02
|
||||
|
@ -81,6 +81,15 @@ typedef enum {
|
||||
*/
|
||||
void gap_set_bondable_mode(int enabled);
|
||||
|
||||
/**
|
||||
* @brief start dedicated bonding with device. disconnect after bonding
|
||||
* @param device
|
||||
* @param request MITM protection
|
||||
* @returns error, if max num acl connections active
|
||||
* @result GAP_DEDICATED_BONDING_COMPLETE
|
||||
*/
|
||||
int gap_dedicated_bonding(bd_addr_t device, int mitm_protection_required);
|
||||
|
||||
gap_security_level_t gap_security_level_for_link_key_type(link_key_type_t link_key_type);
|
||||
gap_security_level_t gap_security_level(hci_con_handle_t con_handle);
|
||||
|
||||
|
138
src/hci.c
138
src/hci.c
@ -601,7 +601,7 @@ static void event_handler(uint8_t *packet, int size){
|
||||
if (!packet[2]){
|
||||
conn->state = OPEN;
|
||||
conn->con_handle = READ_BT_16(packet, 3);
|
||||
conn->bonding_flags = BONDING_REQUEST_REMOTE_FEATURES;
|
||||
conn->bonding_flags |= BONDING_REQUEST_REMOTE_FEATURES;
|
||||
|
||||
// restart timer
|
||||
run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
|
||||
@ -611,6 +611,11 @@ static void event_handler(uint8_t *packet, int size){
|
||||
|
||||
hci_emit_nr_connections_changed();
|
||||
} else {
|
||||
// notify client if dedicated bonding
|
||||
if (conn->bonding_flags & BONDING_DEDICATED){
|
||||
hci_emit_dedicated_bonding_result(conn, packet[2]);
|
||||
}
|
||||
|
||||
// connection failed, remove entry
|
||||
linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
|
||||
btstack_memory_hci_connection_free( conn );
|
||||
@ -634,6 +639,10 @@ static void event_handler(uint8_t *packet, int size){
|
||||
}
|
||||
}
|
||||
conn->bonding_flags |= BONDING_RECEIVED_REMOTE_FEATURES;
|
||||
log_info("HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE, bonding flags %x", conn->bonding_flags);
|
||||
if (conn->bonding_flags & BONDING_DEDICATED){
|
||||
conn->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_LINK_KEY_REQUEST:
|
||||
@ -694,14 +703,15 @@ static void event_handler(uint8_t *packet, int size){
|
||||
break;
|
||||
|
||||
case HCI_EVENT_ENCRYPTION_CHANGE:
|
||||
if (packet[2]) break; // error status
|
||||
handle = READ_BT_16(packet, 3);
|
||||
conn = hci_connection_for_handle(handle);
|
||||
if (!conn) break;
|
||||
if (packet[5]){
|
||||
conn->authentication_flags |= CONNECTION_ENCRYPTED;
|
||||
} else {
|
||||
conn->authentication_flags &= ~CONNECTION_ENCRYPTED;
|
||||
if (packet[2] == 0) {
|
||||
if (packet[5]){
|
||||
conn->authentication_flags |= CONNECTION_ENCRYPTED;
|
||||
} else {
|
||||
conn->authentication_flags &= ~CONNECTION_ENCRYPTED;
|
||||
}
|
||||
}
|
||||
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
||||
break;
|
||||
@ -710,13 +720,22 @@ static void event_handler(uint8_t *packet, int size){
|
||||
handle = READ_BT_16(packet, 3);
|
||||
conn = hci_connection_for_handle(handle);
|
||||
if (!conn) break;
|
||||
|
||||
// dedicated bonding: send result and disconnect
|
||||
if (conn->bonding_flags & BONDING_DEDICATED){
|
||||
conn->bonding_flags &= ~BONDING_DEDICATED;
|
||||
hci_emit_dedicated_bonding_result( conn, packet[2]);
|
||||
conn->bonding_flags |= BONDING_DISCONNECT_DEDICATED_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet[2] == 0 && gap_security_level_for_link_key_type(conn->link_key_type) >= conn->requested_security_level){
|
||||
// link key sufficient for requested security
|
||||
conn->bonding_flags |= BONDING_SEND_ENCRYPTION_REQUEST;
|
||||
} else {
|
||||
// not enough
|
||||
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
||||
break;
|
||||
}
|
||||
// not enough
|
||||
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
||||
break;
|
||||
|
||||
#ifndef EMBEDDED
|
||||
@ -1233,6 +1252,12 @@ void hci_run(){
|
||||
|
||||
connection = (hci_connection_t *) it;
|
||||
|
||||
if (connection->state == SEND_CREATE_CONNECTION){
|
||||
log_info("sending hci_create_connection\n");
|
||||
hci_send_cmd(&hci_create_connection, connection->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->state == RECEIVED_CONNECTION_REQUEST){
|
||||
log_info("sending hci_accept_connection_request\n");
|
||||
connection->state = ACCEPTED_CONNECTION_REQUEST;
|
||||
@ -1296,6 +1321,11 @@ void hci_run(){
|
||||
hci_send_cmd(&hci_disconnect, connection->con_handle, 0x0005); // authentication failure
|
||||
return;
|
||||
}
|
||||
if (connection->bonding_flags & BONDING_DISCONNECT_DEDICATED_DONE){
|
||||
connection->bonding_flags &= ~BONDING_DISCONNECT_DEDICATED_DONE;
|
||||
hci_send_cmd(&hci_disconnect, connection->con_handle, 0); // authentication done
|
||||
return;
|
||||
}
|
||||
if (connection->bonding_flags & BONDING_SEND_AUTHENTICATE_REQUEST){
|
||||
connection->bonding_flags &= ~BONDING_SEND_AUTHENTICATE_REQUEST;
|
||||
hci_send_cmd(&hci_authentication_requested, connection->con_handle);
|
||||
@ -1537,23 +1567,30 @@ int hci_send_cmd_packet(uint8_t *packet, int size){
|
||||
if (IS_COMMAND(packet, hci_create_connection)){
|
||||
bt_flip_addr(addr, &packet[3]);
|
||||
log_info("Create_connection to %s\n", bd_addr_to_str(addr));
|
||||
|
||||
conn = connection_for_address(addr);
|
||||
if (conn) {
|
||||
// if connection exists
|
||||
if (conn->state == OPEN) {
|
||||
if (!conn){
|
||||
conn = create_connection_for_addr(addr);
|
||||
if (!conn){
|
||||
// notify client that alloc failed
|
||||
hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
|
||||
return 0; // don't sent packet to controller
|
||||
}
|
||||
conn->state = SEND_CREATE_CONNECTION;
|
||||
}
|
||||
log_info("conn state %u", conn->state);
|
||||
switch (conn->state){
|
||||
// if connection active exists
|
||||
case OPEN:
|
||||
// and OPEN, emit connection complete command
|
||||
hci_emit_connection_complete(conn, 0);
|
||||
}
|
||||
// otherwise, just ignore as it is already in the open process
|
||||
return 0; // don't sent packet to controller
|
||||
|
||||
}
|
||||
// create connection struct and register, state = SENT_CREATE_CONNECTION
|
||||
conn = create_connection_for_addr(addr);
|
||||
if (!conn){
|
||||
// notify client that alloc failed
|
||||
hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
|
||||
return 0; // don't sent packet to controller
|
||||
break;
|
||||
case SEND_CREATE_CONNECTION:
|
||||
// connection created by hci, e.g. dedicated bonding
|
||||
break;
|
||||
default:
|
||||
// otherwise, just ignore as it is already in the open process
|
||||
return 0;
|
||||
}
|
||||
conn->state = SENT_CREATE_CONNECTION;
|
||||
}
|
||||
@ -1777,6 +1814,19 @@ void hci_emit_security_level(hci_con_handle_t con_handle, gap_security_level_t l
|
||||
hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
void hci_emit_dedicated_bonding_result(hci_connection_t * connection, uint8_t status){
|
||||
log_info("hci_emit_dedicated_bonding_result %u ", status);
|
||||
uint8_t event[9];
|
||||
int pos = 0;
|
||||
event[pos++] = GAP_DEDICATED_BONDING_COMPLETED;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = status;
|
||||
bt_flip_addr( * (bd_addr_t *) &event[pos], connection->address);
|
||||
pos += 6;
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
// query if remote side supports SSP
|
||||
int hci_remote_ssp_supported(hci_con_handle_t con_handle){
|
||||
hci_connection_t * connection = hci_connection_for_handle(con_handle);
|
||||
@ -1865,3 +1915,45 @@ void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_
|
||||
// try to authenticate connection
|
||||
connection->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief start dedicated bonding with device. disconnect after bonding
|
||||
* @param device
|
||||
* @param request MITM protection
|
||||
* @result GAP_DEDICATED_BONDING_COMPLETE
|
||||
*/
|
||||
int gap_dedicated_bonding(bd_addr_t device, int mitm_protection_required){
|
||||
|
||||
|
||||
printf("gap_dedicated_bonding clled\n");
|
||||
// create connection state machine
|
||||
hci_connection_t * connection = create_connection_for_addr(device);
|
||||
|
||||
if (!connection){
|
||||
return BTSTACK_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
printf("gap_dedicated_bonding 2\n");
|
||||
|
||||
// delete linkn key
|
||||
hci_drop_link_key_for_bd_addr( (bd_addr_t *) &device);
|
||||
|
||||
// @TODO answer AutHReq based on context instead of global state
|
||||
hci_stack.ssp_authentication_requirement =
|
||||
SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_DEDICATED_BONDING;
|
||||
|
||||
// configure LEVEL_2/3, dedicated bonding
|
||||
connection->state = SEND_CREATE_CONNECTION;
|
||||
connection->requested_security_level = mitm_protection_required ? LEVEL_3 : LEVEL_2;
|
||||
connection->bonding_flags = BONDING_DEDICATED;
|
||||
|
||||
// wait for GAP Security Result and send GAP Dedicated Bonding complete
|
||||
|
||||
// handle: connnection failure (connection complete != ok)
|
||||
// handle: authentication failure
|
||||
// handle: disconnect on done
|
||||
|
||||
hci_run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
10
src/hci.h
10
src/hci.h
@ -220,7 +220,8 @@ typedef enum {
|
||||
} hci_authentication_flags_t;
|
||||
|
||||
typedef enum {
|
||||
SENT_CREATE_CONNECTION = 1,
|
||||
SEND_CREATE_CONNECTION = 0,
|
||||
SENT_CREATE_CONNECTION,
|
||||
RECEIVED_CONNECTION_REQUEST,
|
||||
ACCEPTED_CONNECTION_REQUEST,
|
||||
REJECTED_CONNECTION_REQUEST,
|
||||
@ -233,8 +234,10 @@ typedef enum {
|
||||
BONDING_RECEIVED_REMOTE_FEATURES = 0x02,
|
||||
BONDING_REMOTE_SUPPORTS_SSP = 0x04,
|
||||
BONDING_DISCONNECT_SECURITY_BLOCK = 0x08,
|
||||
BONDING_SEND_AUTHENTICATE_REQUEST = 0x10,
|
||||
BONDING_SEND_ENCRYPTION_REQUEST = 0x20,
|
||||
BONDING_DISCONNECT_DEDICATED_DONE = 0x10,
|
||||
BONDING_SEND_AUTHENTICATE_REQUEST = 0x20,
|
||||
BONDING_SEND_ENCRYPTION_REQUEST = 0x40,
|
||||
BONDING_DEDICATED = 0x80,
|
||||
} bonding_flags_t;
|
||||
|
||||
typedef enum {
|
||||
@ -397,6 +400,7 @@ void hci_emit_system_bluetooth_enabled(uint8_t enabled);
|
||||
void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name);
|
||||
void hci_emit_discoverable_enabled(uint8_t enabled);
|
||||
void hci_emit_security_level(hci_con_handle_t con_handle, gap_security_level_t level);
|
||||
void hci_emit_dedicated_bonding_result(hci_connection_t * connection, uint8_t status);
|
||||
|
||||
// query if remote side supports SSP
|
||||
// query if the local side supports SSP
|
||||
|
Loading…
x
Reference in New Issue
Block a user