mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-28 19:20:54 +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
|
# 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
|
#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
|
spp_counter_ssp: ${CORE_OBJ} ${COMMON_OBJ} spp_counter_ssp.c
|
||||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||||
|
|
||||||
|
gap_dedicated_bonding: ${CORE_OBJ} ${COMMON_OBJ} gap_dedicated_bonding.c
|
||||||
|
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||||
|
|
||||||
# compile .ble description
|
# compile .ble description
|
||||||
profile.h: profile.gatt
|
profile.h: profile.gatt
|
||||||
python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@
|
python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@
|
||||||
|
@ -244,10 +244,13 @@ extern "C" {
|
|||||||
#define SM_AUTHORIZATION_REQUEST 0xb9
|
#define SM_AUTHORIZATION_REQUEST 0xb9
|
||||||
#define SM_AUTHORIZATION_RESULT 0xba
|
#define SM_AUTHORIZATION_RESULT 0xba
|
||||||
|
|
||||||
// GAP SECURITY
|
// GAP
|
||||||
|
|
||||||
// data: event(8), len(8), hci_handle (16), security_level (8)
|
// data: event(8), len(8), hci_handle (16), security_level (8)
|
||||||
#define GAP_SECURITY_LEVEL 0xc0
|
#define GAP_SECURITY_LEVEL 0xc0
|
||||||
|
|
||||||
|
// data: event(8), len(8), status (8), bd_addr(48)
|
||||||
|
#define GAP_DEDICATED_BONDING_COMPLETED 0xc1
|
||||||
|
|
||||||
// Error Code
|
// Error Code
|
||||||
#define ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02
|
#define ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02
|
||||||
|
@ -81,6 +81,15 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
void gap_set_bondable_mode(int enabled);
|
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_for_link_key_type(link_key_type_t link_key_type);
|
||||||
gap_security_level_t gap_security_level(hci_con_handle_t con_handle);
|
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]){
|
if (!packet[2]){
|
||||||
conn->state = OPEN;
|
conn->state = OPEN;
|
||||||
conn->con_handle = READ_BT_16(packet, 3);
|
conn->con_handle = READ_BT_16(packet, 3);
|
||||||
conn->bonding_flags = BONDING_REQUEST_REMOTE_FEATURES;
|
conn->bonding_flags |= BONDING_REQUEST_REMOTE_FEATURES;
|
||||||
|
|
||||||
// restart timer
|
// restart timer
|
||||||
run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
|
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();
|
hci_emit_nr_connections_changed();
|
||||||
} else {
|
} else {
|
||||||
|
// notify client if dedicated bonding
|
||||||
|
if (conn->bonding_flags & BONDING_DEDICATED){
|
||||||
|
hci_emit_dedicated_bonding_result(conn, packet[2]);
|
||||||
|
}
|
||||||
|
|
||||||
// connection failed, remove entry
|
// connection failed, remove entry
|
||||||
linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
|
linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
|
||||||
btstack_memory_hci_connection_free( conn );
|
btstack_memory_hci_connection_free( conn );
|
||||||
@ -634,6 +639,10 @@ static void event_handler(uint8_t *packet, int size){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn->bonding_flags |= BONDING_RECEIVED_REMOTE_FEATURES;
|
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;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_LINK_KEY_REQUEST:
|
case HCI_EVENT_LINK_KEY_REQUEST:
|
||||||
@ -694,14 +703,15 @@ static void event_handler(uint8_t *packet, int size){
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_ENCRYPTION_CHANGE:
|
case HCI_EVENT_ENCRYPTION_CHANGE:
|
||||||
if (packet[2]) break; // error status
|
|
||||||
handle = READ_BT_16(packet, 3);
|
handle = READ_BT_16(packet, 3);
|
||||||
conn = hci_connection_for_handle(handle);
|
conn = hci_connection_for_handle(handle);
|
||||||
if (!conn) break;
|
if (!conn) break;
|
||||||
if (packet[5]){
|
if (packet[2] == 0) {
|
||||||
conn->authentication_flags |= CONNECTION_ENCRYPTED;
|
if (packet[5]){
|
||||||
} else {
|
conn->authentication_flags |= CONNECTION_ENCRYPTED;
|
||||||
conn->authentication_flags &= ~CONNECTION_ENCRYPTED;
|
} else {
|
||||||
|
conn->authentication_flags &= ~CONNECTION_ENCRYPTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
||||||
break;
|
break;
|
||||||
@ -710,13 +720,22 @@ static void event_handler(uint8_t *packet, int size){
|
|||||||
handle = READ_BT_16(packet, 3);
|
handle = READ_BT_16(packet, 3);
|
||||||
conn = hci_connection_for_handle(handle);
|
conn = hci_connection_for_handle(handle);
|
||||||
if (!conn) break;
|
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){
|
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
|
// link key sufficient for requested security
|
||||||
conn->bonding_flags |= BONDING_SEND_ENCRYPTION_REQUEST;
|
conn->bonding_flags |= BONDING_SEND_ENCRYPTION_REQUEST;
|
||||||
} else {
|
break;
|
||||||
// not enough
|
|
||||||
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
|
||||||
}
|
}
|
||||||
|
// not enough
|
||||||
|
hci_emit_security_level(handle, gap_security_level_for_connection(conn));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifndef EMBEDDED
|
#ifndef EMBEDDED
|
||||||
@ -1233,6 +1252,12 @@ void hci_run(){
|
|||||||
|
|
||||||
connection = (hci_connection_t *) it;
|
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){
|
if (connection->state == RECEIVED_CONNECTION_REQUEST){
|
||||||
log_info("sending hci_accept_connection_request\n");
|
log_info("sending hci_accept_connection_request\n");
|
||||||
connection->state = ACCEPTED_CONNECTION_REQUEST;
|
connection->state = ACCEPTED_CONNECTION_REQUEST;
|
||||||
@ -1296,6 +1321,11 @@ void hci_run(){
|
|||||||
hci_send_cmd(&hci_disconnect, connection->con_handle, 0x0005); // authentication failure
|
hci_send_cmd(&hci_disconnect, connection->con_handle, 0x0005); // authentication failure
|
||||||
return;
|
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){
|
if (connection->bonding_flags & BONDING_SEND_AUTHENTICATE_REQUEST){
|
||||||
connection->bonding_flags &= ~BONDING_SEND_AUTHENTICATE_REQUEST;
|
connection->bonding_flags &= ~BONDING_SEND_AUTHENTICATE_REQUEST;
|
||||||
hci_send_cmd(&hci_authentication_requested, connection->con_handle);
|
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)){
|
if (IS_COMMAND(packet, hci_create_connection)){
|
||||||
bt_flip_addr(addr, &packet[3]);
|
bt_flip_addr(addr, &packet[3]);
|
||||||
log_info("Create_connection to %s\n", bd_addr_to_str(addr));
|
log_info("Create_connection to %s\n", bd_addr_to_str(addr));
|
||||||
|
|
||||||
conn = connection_for_address(addr);
|
conn = connection_for_address(addr);
|
||||||
if (conn) {
|
if (!conn){
|
||||||
// if connection exists
|
conn = create_connection_for_addr(addr);
|
||||||
if (conn->state == OPEN) {
|
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
|
// and OPEN, emit connection complete command
|
||||||
hci_emit_connection_complete(conn, 0);
|
hci_emit_connection_complete(conn, 0);
|
||||||
}
|
break;
|
||||||
// otherwise, just ignore as it is already in the open process
|
case SEND_CREATE_CONNECTION:
|
||||||
return 0; // don't sent packet to controller
|
// connection created by hci, e.g. dedicated bonding
|
||||||
|
break;
|
||||||
}
|
default:
|
||||||
// create connection struct and register, state = SENT_CREATE_CONNECTION
|
// otherwise, just ignore as it is already in the open process
|
||||||
conn = create_connection_for_addr(addr);
|
return 0;
|
||||||
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 = SENT_CREATE_CONNECTION;
|
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));
|
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
|
// query if remote side supports SSP
|
||||||
int hci_remote_ssp_supported(hci_con_handle_t con_handle){
|
int hci_remote_ssp_supported(hci_con_handle_t con_handle){
|
||||||
hci_connection_t * connection = hci_connection_for_handle(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
|
// try to authenticate connection
|
||||||
connection->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
|
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;
|
} hci_authentication_flags_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SENT_CREATE_CONNECTION = 1,
|
SEND_CREATE_CONNECTION = 0,
|
||||||
|
SENT_CREATE_CONNECTION,
|
||||||
RECEIVED_CONNECTION_REQUEST,
|
RECEIVED_CONNECTION_REQUEST,
|
||||||
ACCEPTED_CONNECTION_REQUEST,
|
ACCEPTED_CONNECTION_REQUEST,
|
||||||
REJECTED_CONNECTION_REQUEST,
|
REJECTED_CONNECTION_REQUEST,
|
||||||
@ -233,8 +234,10 @@ typedef enum {
|
|||||||
BONDING_RECEIVED_REMOTE_FEATURES = 0x02,
|
BONDING_RECEIVED_REMOTE_FEATURES = 0x02,
|
||||||
BONDING_REMOTE_SUPPORTS_SSP = 0x04,
|
BONDING_REMOTE_SUPPORTS_SSP = 0x04,
|
||||||
BONDING_DISCONNECT_SECURITY_BLOCK = 0x08,
|
BONDING_DISCONNECT_SECURITY_BLOCK = 0x08,
|
||||||
BONDING_SEND_AUTHENTICATE_REQUEST = 0x10,
|
BONDING_DISCONNECT_DEDICATED_DONE = 0x10,
|
||||||
BONDING_SEND_ENCRYPTION_REQUEST = 0x20,
|
BONDING_SEND_AUTHENTICATE_REQUEST = 0x20,
|
||||||
|
BONDING_SEND_ENCRYPTION_REQUEST = 0x40,
|
||||||
|
BONDING_DEDICATED = 0x80,
|
||||||
} bonding_flags_t;
|
} bonding_flags_t;
|
||||||
|
|
||||||
typedef enum {
|
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_remote_name_cached(bd_addr_t *addr, device_name_t *name);
|
||||||
void hci_emit_discoverable_enabled(uint8_t enabled);
|
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_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 remote side supports SSP
|
||||||
// query if the local side supports SSP
|
// query if the local side supports SSP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user