Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
mringwal committed May 1, 2018
2 parents 20e99bd + 989d4da commit 62abb69
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed
- att_db_util: added security requirement arguments to characteristic creators
- SM: use btstack_crypto for cryptographpic functions
- GAP: security level for Classic protocols (asides SDP) raised to 2 (encryption)

### Fixed
- HFP: fix answer call command
Expand Down
12 changes: 7 additions & 5 deletions README.md
Expand Up @@ -23,16 +23,16 @@ BTstack is free for non-commercial use. However, for commercial use, <a href="ma

### Supported Protocols and Profiles

**Protocols:** L2CAP, RFCOMM, SDP, BNEP, ATT, SM (incl. LE Secure Connections).
**Protocols:** L2CAP (incl. LE Data Channels), RFCOMM, SDP, BNEP, AVDTP, AVCTP, ATT, SM (incl. LE Secure Connections).

**Profiles:** GAP, IOP, HFP, HSP, SPP, PAN, GATT.
**Profiles:** GAP, IOP, HFP, HSP, SPP, PAN, A2DP, AVRCP, GATT.

**Beta Stage:** A2DP, AVRCP, HID, HOGP.
**Beta Stage:** HID, HOGP.

**In Development:** BLE Mesh, AVRCP Browsing and more.

It has been qualified with the the Bluetooth SIG for GAP, IOP, HFP, HSP, SPP, PAN profiles and
GATT, SM of the Bluetooth 4.2 LE Central and Peripheral roles (QD ID 25340). For information on MFi/iAP2 support, please <a href="mailto:contact@bluekitchen-gmbh.com">contact us</a>.
It has been qualified with the Bluetooth SIG (QDID 110883) for GAP, IOP, HFP, HSP, SPP, PAN, A2DP, AVRCP profiles and
GATT, SM of the Bluetooth 5 specification. For information on MFi/iAP2 support, please <a href="mailto:contact@bluekitchen-gmbh.com">contact us</a>.


## Evaluation Platforms
Expand All @@ -53,6 +53,7 @@ No build Server | [stm32-l053rb-em9304](https://github.com/bluekitchen/btstack/t
[<img src="http://buildbot.bluekitchen-gmbh.com/btstack/badges/port-wiced-h4-master.svg">](https://buildbot.bluekitchen-gmbh.com/btstack/#/builders/port-wiced-h4-master) | [wiced-h4](https://github.com/bluekitchen/btstack/tree/master/port/wiced-h4) | Broadcom platforms that support the WICED SDK via H4 UART, e.g. [RedBear Duo](https://redbear.cc/product/wifi-ble/redbear-duo.html) with Broadcom BCM43438 A1 or the [Inventek Systems ISM4334x](https://www.inventeksys.com/products-page/wifi-modules/serial-wifi/ism43341-m4g-l44-cu-embedded-serial-to-wifi-ble-nfc-module/) with Broadcom BCM43340
No build server | [wiced-h5](https://github.com/bluekitchen/btstack/tree/master/port/wiced-h5) | Broadcom platforms that support the WICED SDK via H5 UART


#### Other Platforms:
Status | Port | Platform
-------------------| ------|---------
Expand All @@ -69,6 +70,7 @@ No build server | [windows-winusb](https://github.com/bluekitchen/btstack/tree/m
[<img src="http://buildbot.bluekitchen-gmbh.com/btstack/badges/port-ios-master.svg">](https://buildbot.bluekitchen-gmbh.com/btstack/#/builders/port-ios-master) | [ios](https://github.com/bluekitchen/btstack/tree/master/port/ios) | daemon for iOS jailbreak devices, C client-server API
No build server | [freertos](https://github.com/bluekitchen/btstack/tree/master/platform/freertos) | [FreeRTOS](http://www.freertos.org): Run BTstack on a dedicated thread, not thread-safe.


## Supported Chipsets

Chipset | Type | HCI Transport | SCO over HCI | BTstack folder | Comment
Expand Down
80 changes: 80 additions & 0 deletions src/ble/att_db.c
Expand Up @@ -1247,6 +1247,86 @@ uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uui
return 0;
}

// returns 1 if service found. only primary service.
int gatt_server_get_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle){
uint16_t in_group = 0;
uint16_t prev_handle = 0;

uint8_t attribute_value[16];
int attribute_len = sizeof(attribute_value);
reverse_128(uuid128, attribute_value);

att_iterator_t it;
att_iterator_init(&it);
while (att_iterator_has_next(&it)){
att_iterator_fetch_next(&it);
int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);

// close current tag, if within a group and a new service definition starts or we reach end of att db
if (in_group &&
(it.handle == 0 || new_service_started)){
*end_handle = prev_handle;
return 1;
}

// keep track of previous handle
prev_handle = it.handle;

// check if found
if (it.handle && new_service_started && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
*start_handle = it.handle;
in_group = 1;
}
}
return 0;
}

// returns 0 if not found
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
uint8_t attribute_value[16];
reverse_128(uuid128, attribute_value);
att_iterator_t it;
att_iterator_init(&it);
while (att_iterator_has_next(&it)){
att_iterator_fetch_next(&it);
if (it.handle && it.handle < start_handle) continue;
if (it.handle > end_handle) break; // (1)
if (it.handle == 0) break;
if (att_iterator_match_uuid(&it, attribute_value, 16)) return it.handle;
}
return 0;
}

// returns 0 if not found
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
uint8_t attribute_value[16];
reverse_128(uuid128, attribute_value);
att_iterator_t it;
att_iterator_init(&it);
int characteristic_found = 0;
while (att_iterator_has_next(&it)){
att_iterator_fetch_next(&it);
if (it.handle && it.handle < start_handle) continue;
if (it.handle > end_handle) break; // (1)
if (it.handle == 0) break;
if (att_iterator_match_uuid(&it, attribute_value, 16)){
characteristic_found = 1;
continue;
}
if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
|| att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
|| att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
if (characteristic_found) break;
continue;
}
if (att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){
return it.handle;
}
}
return 0;
}


// 1-item cache to optimize query during write_callback
static void att_persistent_ccc_cache(att_iterator_t * it){
att_persistent_ccc_handle = it->handle;
Expand Down
10 changes: 10 additions & 0 deletions src/ble/att_db.h
Expand Up @@ -235,6 +235,16 @@ uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t st
// returns 0 if not found
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);


// returns 1 if service found. only primary service.
int gatt_server_get_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle);

// returns 0 if not found
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

// returns 0 if not found
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

// non-user functionality for att_server

/*
Expand Down
4 changes: 2 additions & 2 deletions src/ble/att_db_util.c
Expand Up @@ -181,13 +181,13 @@ static uint16_t att_db_util_encode_permissions(uint16_t properties, uint8_t read
if (read_permission & 1){
flags |= ATT_PROPERTY_READ_PERMISSION_BIT_0;
}
if (read_permission & 1){
if (read_permission & 2){
flags |= ATT_PROPERTY_READ_PERMISSION_BIT_1;
}
if (write_permission & 1){
flags |= ATT_PROPERTY_WRITE_PERMISSION_BIT_0;
}
if (write_permission & 1){
if (write_permission & 2){
flags |= ATT_PROPERTY_WRITE_PERMISSION_BIT_1;
}
return flags;
Expand Down
12 changes: 8 additions & 4 deletions src/ble/att_server.c
Expand Up @@ -856,10 +856,14 @@ void att_server_request_can_send_now_event(hci_con_handle_t con_handle){
}

void att_server_register_can_send_now_callback(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){
// check if can send already
if (att_dispatch_server_can_send_now(con_handle)){
callback_registration->callback(callback_registration->context);
return;
// check if valid con handle
switch (gap_get_connection_type(con_handle)){
case BD_ADDR_TYPE_LE_PUBLIC:
case BD_ADDR_TYPE_LE_RANDOM:
break;
default:
// con handle not valid for att send
return;
}
callback_registration->context = (void*)(uintptr_t) con_handle;
btstack_linked_list_add_tail(&can_send_now_clients, (btstack_linked_item_t*) callback_registration);
Expand Down
3 changes: 1 addition & 2 deletions src/classic/avdtp_sink.c
Expand Up @@ -106,7 +106,6 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
avdtp_packet_handler(packet_type, channel, packet, size, avdtp_sink_context);
}

// TODO: find out which security level is needed, and replace LEVEL_0 in avdtp_sink_init
void avdtp_sink_init(avdtp_context_t * avdtp_context){
if (!avdtp_context){
log_error("avdtp_source_context is NULL");
Expand All @@ -118,7 +117,7 @@ void avdtp_sink_init(avdtp_context_t * avdtp_context){
avdtp_sink_context->stream_endpoints_id_counter = 0;
avdtp_sink_context->packet_handler = packet_handler;

l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_2);
}

avdtp_stream_endpoint_t * avdtp_sink_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
Expand Down
2 changes: 1 addition & 1 deletion src/classic/avdtp_source.c
Expand Up @@ -172,6 +172,6 @@ void avdtp_source_init(avdtp_context_t * avdtp_context){
avdtp_source_context->stream_endpoints_id_counter = 0;
avdtp_source_context->packet_handler = packet_handler;

l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_2);
}

4 changes: 2 additions & 2 deletions src/classic/avrcp.c
Expand Up @@ -619,8 +619,8 @@ void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet

connection = get_avrcp_connection_for_bd_addr(event_addr, context);
if (!connection){
log_error("Failed to alloc AVRCP connection structure");
avrcp_emit_connection_established(context->avrcp_callback, connection->avrcp_cid, event_addr, BTSTACK_MEMORY_ALLOC_FAILED);
// TODO: validate if this cannot happen. If not, drop disconnect call
log_error("AVRCP connection lookup failed");
l2cap_disconnect(local_cid, 0); // reason isn't used
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/classic/avrcp_browsing_controller.c
Expand Up @@ -733,7 +733,7 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16

void avrcp_browsing_controller_init(void){
avrcp_controller_context.browsing_packet_handler = avrcp_browsing_controller_packet_handler;
l2cap_register_service(&avrcp_browsing_controller_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_0);
l2cap_register_service(&avrcp_browsing_controller_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2);
}

void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback){
Expand Down Expand Up @@ -985,4 +985,4 @@ uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_br
connection->get_total_nr_items_scope = scope;
avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
return ERROR_CODE_SUCCESS;
}
}
2 changes: 1 addition & 1 deletion src/classic/avrcp_browsing_target.c
Expand Up @@ -424,7 +424,7 @@ static void avrcp_browsing_target_packet_handler(uint8_t packet_type, uint16_t c

void avrcp_browsing_target_init(void){
avrcp_target_context.browsing_packet_handler = avrcp_browsing_target_packet_handler;
l2cap_register_service(&avrcp_browsing_target_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_0);
l2cap_register_service(&avrcp_browsing_target_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2);
}

void avrcp_browsing_target_register_packet_handler(btstack_packet_handler_t callback){
Expand Down
2 changes: 1 addition & 1 deletion src/classic/avrcp_controller.c
Expand Up @@ -904,7 +904,7 @@ void avrcp_controller_init(void){
avrcp_controller_context.role = AVRCP_CONTROLLER;
avrcp_controller_context.connections = NULL;
avrcp_controller_context.packet_handler = avrcp_controller_packet_handler;
l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0);
l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_2);
}

void avrcp_controller_register_packet_handler(btstack_packet_handler_t callback){
Expand Down
2 changes: 1 addition & 1 deletion src/classic/avrcp_target.c
Expand Up @@ -1236,7 +1236,7 @@ void avrcp_target_init(void){
avrcp_target_context.role = AVRCP_TARGET;
avrcp_target_context.connections = NULL;
avrcp_target_context.packet_handler = avrcp_target_packet_handler;
l2cap_register_service(&avrcp_target_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0);
l2cap_register_service(&avrcp_target_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_2);
}

void avrcp_target_register_packet_handler(btstack_packet_handler_t callback){
Expand Down
2 changes: 1 addition & 1 deletion src/classic/bnep.c
Expand Up @@ -1537,7 +1537,7 @@ static void bnep_handle_can_send_now(uint16_t l2cap_cid){
/* BNEP BTStack API */
void bnep_init(void)
{
bnep_security_level = LEVEL_0;
bnep_security_level = LEVEL_2;
}

void bnep_set_required_security_level(gap_security_level_t security_level)
Expand Down
4 changes: 2 additions & 2 deletions src/classic/hid_device.c
Expand Up @@ -329,8 +329,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack
void hid_device_init(void){
memset(hid_device, 0, sizeof(hid_device_t));
hid_device->cid = 1;
l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_0);
l2cap_register_service(packet_handler, PSM_HID_CONTROL, 100, LEVEL_0);
l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_2);
l2cap_register_service(packet_handler, PSM_HID_CONTROL, 100, LEVEL_2);
}

/**
Expand Down
22 changes: 19 additions & 3 deletions src/hci.c
Expand Up @@ -4052,12 +4052,28 @@ void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_
return;
}
gap_security_level_t current_level = gap_security_level(con_handle);
log_info("gap_request_security_level %u, current level %u", requested_level, current_level);
if (current_level >= requested_level){
log_info("gap_request_security_level requested level %u, planned level %u, current level %u",
requested_level, connection->requested_security_level, current_level);

// assumption: earlier requested security higher than current level => security request is active
if (current_level < connection->requested_security_level){
if (connection->requested_security_level < requested_level){
// increase requested level as new level is higher

// TODO: handle re-authentication when done

connection->requested_security_level = requested_level;
}
return;
}

// no request active, notify if security sufficient
if (requested_level <= current_level){
hci_emit_security_level(con_handle, current_level);
return;
}

// start pairing to increase security level
connection->requested_security_level = requested_level;

#if 0
Expand All @@ -4077,7 +4093,7 @@ void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_
}
#endif

// try to authenticate connection
// start to authenticate connection
connection->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
hci_run();
}
Expand Down
3 changes: 3 additions & 0 deletions src/l2cap.c
Expand Up @@ -794,10 +794,12 @@ uint8_t *l2cap_get_outgoing_buffer(void){
return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
}

// only for L2CAP Basic Channels
int l2cap_reserve_packet_buffer(void){
return hci_reserve_packet_buffer();
}

// only for L2CAP Basic Channels
void l2cap_release_packet_buffer(void){
hci_release_packet_buffer();
}
Expand Down Expand Up @@ -1097,6 +1099,7 @@ static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_
}

// assumption - only on Classic connections
// cannot be used for L2CAP ERTM
int l2cap_send_prepared(uint16_t local_cid, uint16_t len){

if (!hci_is_packet_buffer_reserved()){
Expand Down
4 changes: 4 additions & 0 deletions src/l2cap.h
Expand Up @@ -523,21 +523,25 @@ void l2cap_request_can_send_now_event(uint16_t local_cid);

/**
* @brief Reserve outgoing buffer
* @note Only for L2CAP Basic Mode Channels
*/
int l2cap_reserve_packet_buffer(void);

/**
* @brief Get outgoing buffer and prepare data.
* @note Only for L2CAP Basic Mode Channels
*/
uint8_t *l2cap_get_outgoing_buffer(void);

/**
* @brief Send L2CAP packet prepared in outgoing buffer to channel
* @note Only for L2CAP Basic Mode Channels
*/
int l2cap_send_prepared(uint16_t local_cid, uint16_t len);

/**
* @brief Release outgoing buffer (only needed if l2cap_send_prepared is not called)
* @note Only for L2CAP Basic Mode Channels
*/
void l2cap_release_packet_buffer(void);

Expand Down

0 comments on commit 62abb69

Please sign in to comment.