From ad83dc6a89670bdaf3268968787ba16e7de09a80 Mon Sep 17 00:00:00 2001 From: "matthias.ringwald@gmail.com" Date: Sat, 18 Jan 2014 20:23:15 +0000 Subject: [PATCH] support dedicated bonding and provide example for it --- example/libusb/Makefile | 5 +- include/btstack/hci_cmds.h | 9 ++- src/gap.h | 9 +++ src/hci.c | 138 ++++++++++++++++++++++++++++++------- src/hci.h | 10 ++- 5 files changed, 141 insertions(+), 30 deletions(-) diff --git a/example/libusb/Makefile b/example/libusb/Makefile index 2f908bdda..c39d8fa82 100644 --- a/example/libusb/Makefile +++ b/example/libusb/Makefile @@ -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 $< $@ diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 1b1cfa91e..a958d97d3 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -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 diff --git a/src/gap.h b/src/gap.h index 7bf584e11..011db713c 100644 --- a/src/gap.h +++ b/src/gap.h @@ -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); diff --git a/src/hci.c b/src/hci.c index 7338b2c6c..5480f96aa 100644 --- a/src/hci.c +++ b/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; +} diff --git a/src/hci.h b/src/hci.h index e4d0bf38d..405ed5678 100644 --- a/src/hci.h +++ b/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