summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio_a2dp_hw/audio_a2dp_hw.c49
-rw-r--r--bta/dm/bta_dm_act.c12
-rw-r--r--bta/dm/bta_dm_cfg.c12
-rwxr-xr-xbta/gatt/bta_gattc_act.c92
-rw-r--r--bta/include/bta_api.h2
-rw-r--r--bta/pan/bta_pan_act.c59
-rw-r--r--btcore/src/counter.c8
-rw-r--r--btif/co/bta_hh_co.c55
-rw-r--r--btif/include/btif_common.h10
-rw-r--r--btif/include/btif_hh.h1
-rw-r--r--btif/src/btif_core.c41
-rw-r--r--btif/src/btif_dm.c2
-rw-r--r--btif/src/btif_gatt_client.c4
-rw-r--r--btif/src/btif_hh.c2
-rw-r--r--device/include/interop_database.h5
-rw-r--r--hci/src/btsnoop_net.c11
-rw-r--r--hci/src/hci_hal_h4.c52
-rw-r--r--hci/src/hci_inject.c8
-rw-r--r--hci/src/low_power_manager.c5
-rw-r--r--hci/test/hci_hal_h4_test.cpp7
-rw-r--r--osi/include/eager_reader.h5
-rw-r--r--osi/src/alarm.c9
-rw-r--r--osi/src/eager_reader.c6
-rw-r--r--stack/btm/btm_acl.c17
-rw-r--r--stack/btm/btm_ble_gap.c3
-rw-r--r--stack/btu/btu_init.c6
-rw-r--r--stack/gatt/gatt_auth.c5
-rw-r--r--stack/gatt/gatt_utils.c2
-rw-r--r--stack/include/bt_types.h1
-rw-r--r--stack/include/hcidefs.h3
-rw-r--r--stack/sdp/sdp_api.c13
-rw-r--r--stack/smp/smp_act.c15
-rw-r--r--utils/src/bt_utils.c3
33 files changed, 411 insertions, 114 deletions
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c
index 3e2bc2dde..19f7dfd04 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.c
+++ b/audio_a2dp_hw/audio_a2dp_hw.c
@@ -125,6 +125,8 @@ struct a2dp_stream_common {
struct a2dp_stream_out {
struct audio_stream_out stream;
struct a2dp_stream_common common;
+ uint64_t frames_presented; // frames written, never reset
+ uint64_t frames_rendered; // frames written, reset on standby
};
struct a2dp_stream_in {
@@ -720,6 +722,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
out->common.state = AUDIO_A2DP_STATE_STOPPED;
else
ERROR("write failed : stream suspended, avoid resetting state");
+ } else {
+ const size_t frames = bytes / audio_stream_out_frame_size(stream);
+ out->frames_rendered += frames;
+ out->frames_presented += frames;
}
DEBUG("wrote %d bytes out of %zu bytes", sent, bytes);
@@ -801,9 +807,9 @@ static int out_standby(struct audio_stream *stream)
DUT need to clear flag else start will not happen but
Do nothing in SUSPENDED state. */
if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
- retVal = suspend_audio_datapath(&out->common, true);
-
- pthread_mutex_unlock(&out->common.lock);
+ retVal = suspend_audio_datapath(&out->common, true);
+ out->frames_rendered = 0; // rendered is reset, presented is not
+ pthread_mutex_unlock (&out->common.lock);
return retVal;
}
@@ -972,16 +978,45 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
return -ENOSYS;
}
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+ uint64_t *frames, struct timespec *timestamp)
+{
+ struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+ FNLOG();
+ if (stream == NULL || frames == NULL || timestamp == NULL)
+ return -EINVAL;
+
+ int ret = -EWOULDBLOCK;
+ pthread_mutex_lock(&out->common.lock);
+ uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+ if (out->frames_presented >= latency_frames) {
+ *frames = out->frames_presented - latency_frames;
+ clock_gettime(CLOCK_MONOTONIC, timestamp); // could also be associated with out_write().
+ ret = 0;
+ }
+ pthread_mutex_unlock(&out->common.lock);
+ return ret;
+}
static int out_get_render_position(const struct audio_stream_out *stream,
uint32_t *dsp_frames)
{
- UNUSED(stream);
- UNUSED(dsp_frames);
+ struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
FNLOG();
- return -EINVAL;
+ if (stream == NULL || dsp_frames == NULL)
+ return -EINVAL;
+
+ pthread_mutex_lock(&out->common.lock);
+ uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+ if (out->frames_rendered >= latency_frames) {
+ *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
+ } else {
+ *dsp_frames = 0;
+ }
+ pthread_mutex_unlock(&out->common.lock);
+ return 0;
}
static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
@@ -1239,6 +1274,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->stream.set_volume = out_set_volume;
out->stream.write = out_write;
out->stream.get_render_position = out_get_render_position;
+ out->stream.get_presentation_position = out_get_presentation_position;
+
/* initialize a2dp specifics */
a2dp_stream_common_init(&out->common);
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index d81fb32dc..8d441c322 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -3565,7 +3565,6 @@ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle)
*******************************************************************************/
static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
{
-
UINT8 j;
tBTA_PREF_ROLES role;
tBTA_DM_PEER_DEVICE *p_dev;
@@ -3619,7 +3618,11 @@ static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id,
APPL_TRACE_WARNING("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status);
}
- bta_dm_adjust_roles(FALSE);
+ /* Don't adjust roles for each busy/idle state transition to avoid
+ excessive switch requests when individual profile busy/idle status
+ changes */
+ if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE))
+ bta_dm_adjust_roles(FALSE);
}
/*******************************************************************************
@@ -3734,7 +3737,7 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
}
if((bta_dm_cb.device_list.peer_device[i].pref_role == BTA_MASTER_ROLE_ONLY)
- || (bta_dm_cb.device_list.count > 1))
+ || (br_count > 1))
{
/* Initiating immediate role switch with certain remote devices
@@ -3743,7 +3746,8 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
versions are stored in a blacklist and role switch with these devices are
delayed to avoid the collision with link encryption setup */
- if (delay_role_switch == FALSE)
+ if (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_SLAVE_ROLE_ONLY &&
+ delay_role_switch == FALSE)
{
BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
HCI_ROLE_MASTER, NULL);
diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c
index 48b442bf3..b09c7afd6 100644
--- a/bta/dm/bta_dm_cfg.c
+++ b/bta/dm/bta_dm_cfg.c
@@ -86,7 +86,11 @@ const tBTA_DM_CFG bta_dm_cfg =
#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
#endif
-#define BTA_DM_NUM_RM_ENTRY 4
+#ifndef BTA_PANU_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY
+#endif
+#define BTA_DM_NUM_RM_ENTRY 6
/* appids for PAN used by insight sample application
these have to be same as defined in btui_int.h */
@@ -100,8 +104,10 @@ const tBTA_DM_CFG bta_dm_cfg =
const tBTA_DM_RM bta_dm_rm_cfg[] =
{
{BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
- {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_MASTER_ROLE_ONLY},
- {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_MASTER_ROLE_ONLY},
+ {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE},
+ {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE},
+ {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY},
+ {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE},
{BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE},
{BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE}
};
diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c
index 078de1271..4ec1f33ab 100755
--- a/bta/gatt/bta_gattc_act.c
+++ b/bta/gatt/bta_gattc_act.c
@@ -54,6 +54,9 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
tGATT_CL_COMPLETE *p_data);
+static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op,
+ tBTA_GATT_STATUS status,
+ tGATT_CL_COMPLETE *p_data);
static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg);
static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda);
@@ -934,7 +937,6 @@ void bta_gattc_restart_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data
*******************************************************************************/
void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
- tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status;
if (bta_gattc_enqueue(p_clcb, p_data))
@@ -944,13 +946,11 @@ void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
/* if failed, return callback here */
if (status != GATT_SUCCESS && status != GATT_CMD_STARTED)
{
- memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data)
+ p_clcb->p_q_cmd = NULL;
- op_cmpl.status = status;
- op_cmpl.op_code = GATTC_OPTYPE_CONFIG;
- op_cmpl.p_cmpl = NULL;
-
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status, NULL);
}
}
}
@@ -1094,10 +1094,9 @@ void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = 0;
tGATT_READ_PARAM read_param;
- tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATT_STATUS status;
memset (&read_param, 0 ,sizeof(tGATT_READ_PARAM));
- memset (&op_cmpl, 0 ,sizeof(tBTA_GATTC_OP_CMPL));
if (bta_gattc_enqueue(p_clcb, p_data))
{
@@ -1106,23 +1105,24 @@ void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
&p_data->api_read.char_id,
p_data->api_read.p_descr_type)) == 0)
{
- op_cmpl.status = BTA_GATT_ERROR;
+ status = BTA_GATT_ERROR;
}
else
{
read_param.by_handle.handle = handle;
read_param.by_handle.auth_req = p_data->api_read.auth_req;
- op_cmpl.status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param);
+ status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param);
}
/* read fail */
- if (op_cmpl.status != BTA_GATT_OK)
+ if (status != BTA_GATT_OK)
{
- op_cmpl.op_code = GATTC_OPTYPE_READ;
- op_cmpl.p_cmpl = NULL;
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data)
+ p_clcb->p_q_cmd = NULL;
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL);
}
}
}
@@ -1139,7 +1139,6 @@ void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
UINT16 i, handle;
tBTA_GATT_STATUS status = BTA_GATT_OK;
tGATT_READ_PARAM read_param;
- tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATTC_ATTR_ID *p_id;
if (bta_gattc_enqueue(p_clcb, p_data))
@@ -1188,13 +1187,11 @@ void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
/* read fail */
if (status != BTA_GATT_OK)
{
- memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
-
- op_cmpl.status = status;
- op_cmpl.op_code = GATTC_OPTYPE_READ;
- op_cmpl.p_cmpl = NULL;
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data)
+ p_clcb->p_q_cmd = NULL;
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL);
}
}
}
@@ -1211,7 +1208,6 @@ void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = 0;
tGATT_VALUE attr = {0};
- tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status = BTA_GATT_OK;
if (bta_gattc_enqueue(p_clcb, p_data))
@@ -1239,13 +1235,11 @@ void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
/* write fail */
if (status != BTA_GATT_OK)
{
- memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
-
- op_cmpl.status = status;
- op_cmpl.op_code = GATTC_OPTYPE_WRITE;
- op_cmpl.p_cmpl = NULL;
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data)
+ p_clcb->p_q_cmd = NULL;
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status, NULL);
}
}
}
@@ -1259,7 +1253,6 @@ void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
*********************************************************************************/
void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
- tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status;
if (bta_gattc_enqueue(p_clcb, p_data))
@@ -1268,13 +1261,11 @@ void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
if (status != BTA_GATT_OK)
{
- memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data)
+ p_clcb->p_q_cmd = NULL;
- op_cmpl.status = status;
- op_cmpl.op_code = GATTC_OPTYPE_EXE_WRITE;
- op_cmpl.p_cmpl = NULL;
-
- bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE, status, NULL);
}
}
}
@@ -1801,7 +1792,6 @@ static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg)
/*******************************************************************************
**
** Function bta_gattc_conn_cback
-** bta_gattc_cmpl_cback
**
** Description callback functions to GATT client stack.
**
@@ -2140,10 +2130,7 @@ void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPL
static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
tGATT_CL_COMPLETE *p_data)
{
- tBTA_GATTC_CLCB *p_clcb ;
- tBTA_GATTC_OP_CMPL *p_buf;
- UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
-
+ tBTA_GATTC_CLCB *p_clcb;
APPL_TRACE_DEBUG("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d",
conn_id, op, status);
p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
@@ -2169,7 +2156,26 @@ static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
}
- if ((p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len)) != NULL)
+ bta_gattc_cmpl_sendmsg(conn_id, op, status, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_gattc_cmpl_sendmsg
+**
+** Description client operation complete send message
+**
+** Returns None.
+**
+*******************************************************************************/
+static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op,
+ tBTA_GATT_STATUS status,
+ tGATT_CL_COMPLETE *p_data)
+{
+ const UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
+ tBTA_GATTC_OP_CMPL *p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len);
+
+ if (p_buf != NULL)
{
memset(p_buf, 0, len);
p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT;
@@ -2185,8 +2191,6 @@ static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS
bta_sys_sendmsg(p_buf);
}
-
- return;
}
/*******************************************************************************
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index b6446eecc..5f9d05536 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -187,6 +187,7 @@ typedef UINT16 tBTA_SEC;
/* Ignore for Discoverable, Connectable only for LE modes */
#define BTA_DM_LE_IGNORE 0xFF00
+#define BTA_APP_ID_PAN_MULTI 0xFE /* app id for pan multiple connection */
#define BTA_ALL_APP_ID 0xFF
/* Discoverable Modes */
@@ -254,6 +255,7 @@ typedef UINT8 tBTA_AUTH_RESP;
#define BTA_ANY_ROLE 0x00
#define BTA_MASTER_ROLE_PREF 0x01
#define BTA_MASTER_ROLE_ONLY 0x02
+#define BTA_SLAVE_ROLE_ONLY 0x03 /* Used for PANU only, skip role switch to master */
typedef UINT8 tBTA_PREF_ROLES;
diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
index 2256ae973..c81fe7173 100644
--- a/bta/pan/bta_pan_act.c
+++ b/bta/pan/bta_pan_act.c
@@ -318,6 +318,53 @@ static void bta_pan_mfilt_ind_cback(UINT16 handle, BOOLEAN indication,tBNEP_RESU
/*******************************************************************************
**
+** Function bta_pan_has_multiple_connections
+**
+** Description Check whether there are multiple GN/NAP connections to
+** different devices
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN bta_pan_has_multiple_connections(UINT8 app_id)
+{
+ tBTA_PAN_SCB *p_scb = NULL;
+ BOOLEAN found = FALSE;
+ BD_ADDR bd_addr;
+
+ for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+ {
+ p_scb = &bta_pan_cb.scb[index];
+ if (p_scb->in_use == TRUE && app_id == p_scb->app_id)
+ {
+ /* save temp bd_addr */
+ bdcpy(bd_addr, p_scb->bd_addr);
+ found = TRUE;
+ break;
+ }
+ }
+
+ /* If cannot find a match then there is no connection at all */
+ if (found == FALSE)
+ return FALSE;
+
+ /* Find whether there is another connection with different device other than PANU.
+ Could be same service or different service */
+ for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+ {
+ p_scb = &bta_pan_cb.scb[index];
+ if (p_scb->in_use == TRUE && p_scb->app_id != bta_pan_cb.app_id[0] &&
+ bdcmp(bd_addr, p_scb->bd_addr))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
** Function bta_pan_enable
**
** Description
@@ -592,6 +639,18 @@ void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
data.status = BTA_PAN_FAIL;
}
+ p_scb->pan_flow_enable = TRUE;
+ p_scb->app_flow_enable = TRUE;
+
+ /* If app_id is NAP/GN, check whether there are multiple connections.
+ If there are, provide a special app_id to dm to enforce master role only. */
+ if ((p_scb->app_id == bta_pan_cb.app_id[1] || p_scb->app_id == bta_pan_cb.app_id[2]) &&
+ bta_pan_has_multiple_connections(p_scb->app_id))
+ {
+ p_scb->app_id = BTA_APP_ID_PAN_MULTI;
+ }
+
+ bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);
diff --git a/btcore/src/counter.c b/btcore/src/counter.c
index 08aa518ae..b88c7a27e 100644
--- a/btcore/src/counter.c
+++ b/btcore/src/counter.c
@@ -257,6 +257,10 @@ static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context)
}
static bool counter_socket_open(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return true; // Disable using network sockets for security reasons
+#endif
+
assert(listen_socket_ == NULL);
assert(thread_ == NULL);
assert(clients_ == NULL);
@@ -294,6 +298,10 @@ error:;
}
static void counter_socket_close(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return; // Disable using network sockets for security reasons
+#endif
+
socket_free(listen_socket_);
thread_free(thread_);
list_free(clients_);
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c
index bbe11390d..66c43f764 100644
--- a/btif/co/bta_hh_co.c
+++ b/btif/co/bta_hh_co.c
@@ -43,7 +43,6 @@ const char *dev_path = "/dev/uhid";
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#endif
-
#define REPORT_DESC_REPORT_ID 0x05
#define REPORT_DESC_DIGITIZER_PAGE 0x0D
#define REPORT_DESC_START_COLLECTION 0xA1
@@ -169,12 +168,23 @@ static void remove_digitizer_descriptor(UINT8 **data, UINT16 *length)
}
}
}
+void uhid_set_non_blocking(int fd)
+{
+ int opts = fcntl(fd, F_GETFL);
+ if (opts < 0)
+ APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__, strerror(errno));
+
+ opts |= O_NONBLOCK;
+
+ if (fcntl(fd, F_SETFL, opts) < 0)
+ APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, strerror(errno));
+}
/*Internal function to perform UHID write and error checking*/
static int uhid_write(int fd, const struct uhid_event *ev)
{
- ssize_t ret;
- ret = write(fd, ev, sizeof(*ev));
+ ssize_t ret = write(fd, ev, sizeof(*ev));
+
if (ret < 0){
int rtn = -errno;
APPL_TRACE_ERROR("%s: Cannot write to uhid:%s",
@@ -184,9 +194,9 @@ static int uhid_write(int fd, const struct uhid_event *ev)
APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu",
__FUNCTION__, ret, sizeof(*ev));
return -EFAULT;
- } else {
- return 0;
}
+
+ return 0;
}
/* Internal function to parse the events received from UHID driver*/
@@ -209,24 +219,31 @@ static int uhid_event(btif_hh_device_t *p_dev)
APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __FUNCTION__,
strerror(errno));
return -errno;
- } else if (ret < (ssize_t)sizeof(ev.type)) {
- APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ } else if ((ev.type == UHID_OUTPUT) || (ev.type==UHID_OUTPUT_EV)) {
+ // Only these two types havae payload,
+ // ensure we read full event descriptor
+ if (ret < (ssize_t)sizeof(ev)) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %ld != %lu",
__FUNCTION__, ret, sizeof(ev.type));
- return -EFAULT;
+ return -EFAULT;
+ }
}
switch (ev.type) {
case UHID_START:
APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
+ p_dev->ready_for_data = TRUE;
break;
case UHID_STOP:
APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
+ p_dev->ready_for_data = FALSE;
break;
case UHID_OPEN:
APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
break;
case UHID_CLOSE:
APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
+ p_dev->ready_for_data = FALSE;
break;
case UHID_OUTPUT:
if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
@@ -335,14 +352,17 @@ static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg
*******************************************************************************/
static void *btif_hh_poll_event_thread(void *arg)
{
-
btif_hh_device_t *p_dev = arg;
APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
struct pollfd pfds[1];
int ret;
+
pfds[0].fd = p_dev->fd;
pfds[0].events = POLLIN;
+ // Set the uhid fd as non-blocking to ensure we never block the BTU thread
+ uhid_set_non_blocking(p_dev->fd);
+
while(p_dev->hh_keep_polling){
ret = poll(pfds, 1, 50);
if (ret < 0) {
@@ -384,7 +404,8 @@ void bta_hh_co_destroy(int fd)
int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
{
- APPL_TRACE_VERBOSE("bta_hh_co_data: UHID write");
+ APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len);
+
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_INPUT;
@@ -395,6 +416,7 @@ int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
return -1;
}
memcpy(ev.u.input.data, rpt, len);
+
return uhid_write(fd, &ev);
}
@@ -440,9 +462,11 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
+ return;
}else
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
}
+
p_dev->hh_keep_polling = 1;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
break;
@@ -467,6 +491,7 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
+ return;
}else{
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
p_dev->hh_keep_polling = 1;
@@ -557,11 +582,13 @@ void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MO
APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
return;
}
- // Send the HID report to the kernel.
- if (p_dev->fd >= 0) {
+
+ // Send the HID data to the kernel.
+ if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
bta_hh_co_write(p_dev->fd, p_rpt, len);
}else {
- APPL_TRACE_WARNING("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
+ APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __FUNCTION__, p_dev->fd,
+ p_dev->ready_for_data, len);
}
}
@@ -618,7 +645,7 @@ void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 ven
ev.u.create.country = ctry_code;
result = uhid_write(p_dev->fd, &ev);
- APPL_TRACE_WARNING("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
+ APPL_TRACE_WARNING("%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
p_dev->fd, dscp_len, result);
if (result) {
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index 2c4276d92..7e8c50640 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -145,6 +145,16 @@ enum
#define PERSIST_BDADDR_PROPERTY "persist.service.bdroid.bdaddr"
#endif
+/**
+ * FACTORY_BT_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH
+ * and there is no available persistent bdaddr available from
+ * PERSIST_BDADDR_PROPERTY use a factory set address
+ */
+#ifndef FACTORY_BT_ADDR_PROPERTY
+#define FACTORY_BT_ADDR_PROPERTY "ro.boot.btmacaddr"
+#endif
+
#define FACTORY_BT_BDADDR_STORAGE_LEN 17
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index dfe61fd42..1e80b0664 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -69,6 +69,7 @@ typedef struct
UINT8 sub_class;
UINT8 app_id;
int fd;
+ BOOLEAN ready_for_data;
pthread_t hh_poll_thread_id;
UINT8 hh_keep_polling;
BOOLEAN vup_timer_active;
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
index c1a7bdd24..1fc263c08 100644
--- a/btif/src/btif_core.c
+++ b/btif/src/btif_core.c
@@ -131,6 +131,7 @@ static BOOLEAN ssr_triggered = FALSE;
************************************************************************************/
static void btif_jni_associate(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param);
static void btif_jni_disassociate(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param);
+static bool btif_fetch_property(const char *key, bt_bdaddr_t *addr);
/* sends message to btif task */
static void btif_sendmsg(void *p_msg);
@@ -378,10 +379,22 @@ static bool fetch_vendor_addr (bt_bdaddr_t *local_addr)
close(addr_fd);
return status;
}
+static bool btif_fetch_property(const char *key, bt_bdaddr_t *addr) {
+ char val[PROPERTY_VALUE_MAX] = {0};
+
+ if (property_get(key, val, NULL)) {
+ if (string_to_bdaddr(val, addr)) {
+ BTIF_TRACE_DEBUG("%s: Got BDA %s", __func__, val);
+ return TRUE;
+ }
+ BTIF_TRACE_DEBUG("%s: System Property did not contain valid bdaddr", __func__);
+ }
+ return FALSE;
+}
static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr)
{
- char val[256];
+ char val[PROPERTY_VALUE_MAX] = {0};
uint8_t valid_bda = FALSE;
int val_size = 0;
const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
@@ -391,22 +404,19 @@ static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr)
{
int addr_fd;
- BTIF_TRACE_DEBUG("local bdaddr is stored in %s", val);
+ BTIF_TRACE_DEBUG("%s, local bdaddr is stored in %s", __func__, val);
if ((addr_fd = open(val, O_RDONLY)) != -1)
{
memset(val, 0, sizeof(val));
read(addr_fd, val, FACTORY_BT_BDADDR_STORAGE_LEN);
- string_to_bdaddr(val, local_addr);
/* If this is not a reserved/special bda, then use it */
- if (memcmp(local_addr->address, null_bdaddr, BD_ADDR_LEN) != 0)
+ if ((string_to_bdaddr(val, local_addr)) &&
+ (memcmp(local_addr->address, null_bdaddr, BD_ADDR_LEN) != 0))
{
valid_bda = TRUE;
- BTIF_TRACE_DEBUG("Got Factory BDA %02X:%02X:%02X:%02X:%02X:%02X",
- local_addr->address[0], local_addr->address[1], local_addr->address[2],
- local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ BTIF_TRACE_DEBUG("%s: Got Factory BDA %s", __func__, val);
}
-
close(addr_fd);
}
}
@@ -423,14 +433,13 @@ static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr)
}
/* No factory BDADDR found. Look for previously generated random BDA */
- if ((!valid_bda) && \
- (property_get(PERSIST_BDADDR_PROPERTY, val, NULL)))
- {
- string_to_bdaddr(val, local_addr);
- valid_bda = TRUE;
- BTIF_TRACE_DEBUG("Got prior random BDA %02X:%02X:%02X:%02X:%02X:%02X",
- local_addr->address[0], local_addr->address[1], local_addr->address[2],
- local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ if (!valid_bda) {
+ valid_bda = btif_fetch_property(PERSIST_BDADDR_PROPERTY, local_addr);
+ }
+
+ /* No BDADDR found in file. Look for BDA in factory property */
+ if (!valid_bda) {
+ valid_bda = btif_fetch_property(FACTORY_BT_ADDR_PROPERTY, local_addr);
}
/* No factory BDADDR found. Look for BDA in ro.boot.btmacaddr */
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index 93760582c..01a80fa23 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -3165,6 +3165,8 @@ static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
state = BT_BOND_STATE_NONE;
} else {
btif_dm_save_ble_bonding_keys();
+ BTA_GATTC_Refresh(bd_addr.address);
+ btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
}
BTA_GATTC_Refresh(bd_addr.address);
if(!p_auth_cmpl->smp_over_br)
diff --git a/btif/src/btif_gatt_client.c b/btif/src/btif_gatt_client.c
index 253ca2bd1..a959cdd73 100644
--- a/btif/src/btif_gatt_client.c
+++ b/btif/src/btif_gatt_client.c
@@ -458,8 +458,6 @@ static void btif_gattc_update_properties ( btif_gattc_cb_t *p_btif_cb )
btif_dm_update_ble_remote_properties( p_btif_cb->bd_addr.address, bdname.name,
p_btif_cb->device_type);
}
-
- btif_storage_set_remote_addr_type( &p_btif_cb->bd_addr, p_btif_cb->addr_type);
}
static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
@@ -646,6 +644,8 @@ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);
btif_storage_set_remote_device_property(&(p_btif_cb->bd_addr), &properties);
+ btif_storage_set_remote_addr_type( &p_btif_cb->bd_addr, p_btif_cb->addr_type);
+
HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb,
&p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value);
break;
diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c
index f8230241e..8188942b5 100644
--- a/btif/src/btif_hh.c
+++ b/btif/src/btif_hh.c
@@ -533,6 +533,8 @@ void btif_hh_remove_device(bt_bdaddr_t bd_addr)
p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ p_dev->ready_for_data = FALSE;
+
if (btif_hh_cb.device_num > 0) {
btif_hh_cb.device_num--;
}
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index e7e0da32c..a0bdae756 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -46,9 +46,6 @@ static const interop_addr_t interop_addr_database[] = {
{{0xac, 0x9e, 0x17, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
{{0xf0, 0x79, 0x59, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
- // Polar Heart Rate Monitor
- {{0x00, 0x22, 0xd0, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
-
// Motorola Key Link
{{0x1c, 0x96, 0x5a, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
@@ -56,6 +53,8 @@ static const interop_addr_t interop_addr_database[] = {
{{0x80, 0xea, 0xCa, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
// Xiaomi Mi Band
{{0x88, 0x0f, 0x10, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ // Flic smart button
+ {{0x80, 0xe4, 0xda, 0x70, 0,0}, 4, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
// BMW car kits (Harman/Becker)
{{0x9c, 0xdf, 0x03, 0,0,0}, 3, INTEROP_AUTO_RETRY_PAIRING},
diff --git a/hci/src/btsnoop_net.c b/hci/src/btsnoop_net.c
index 8c69b6732..077a4d432 100644
--- a/hci/src/btsnoop_net.c
+++ b/hci/src/btsnoop_net.c
@@ -77,6 +77,10 @@ static int local_socket_create(void) {
}
void btsnoop_net_open() {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return; // Disable using network sockets for security reasons
+#endif
+
listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
if (!listen_thread_valid_) {
LOG_ERROR("%s pthread_create failed: %s", __func__, strerror(errno));
@@ -86,6 +90,10 @@ void btsnoop_net_open() {
}
void btsnoop_net_close() {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return; // Disable using network sockets for security reasons
+#endif
+
if (listen_thread_valid_) {
shutdown(listen_socket_, SHUT_RDWR);
shutdown(listen_socket_local_, SHUT_RDWR);
@@ -97,6 +105,9 @@ void btsnoop_net_close() {
void btsnoop_net_write(const void *data, size_t length) {
ssize_t ret;
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return; // Disable using network sockets for security reasons
+#endif
pthread_mutex_lock(&client_socket_lock_);
if (client_socket_btsnoop != -1) {
diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
index 0a9333ced..332c1a2ba 100644
--- a/hci/src/hci_hal_h4.c
+++ b/hci/src/hci_hal_h4.c
@@ -27,9 +27,15 @@
#include "osi/include/osi.h"
#include "osi/include/log.h"
#include "osi/include/reactor.h"
+#include "osi/include/thread.h"
#include "vendor.h"
#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
+#define HCI_BLE_EVENT 0x3e
+
+// Increased HCI thread priority to keep up with the audio sub-system
+// when streaming time sensitive data (A2DP).
+#define HCI_THREAD_PRIORITY -19
// Our interface and modules we import
static const hci_hal_t interface;
@@ -42,6 +48,8 @@ static int uart_fd;
static eager_reader_t *uart_stream;
static serial_data_type_t current_data_type;
static bool stream_has_interpretation;
+static bool stream_corruption_detected;
+static uint8_t stream_corruption_bytes_to_ignore;
static void event_uart_has_bytes(eager_reader_t *reader, void *context);
@@ -81,8 +89,14 @@ static bool hal_open() {
}
stream_has_interpretation = false;
+ stream_corruption_detected = false;
+ stream_corruption_bytes_to_ignore = 0;
eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);
+ // Raise thread priorities to keep up with audio
+ thread_set_priority(thread, HCI_THREAD_PRIORITY);
+ thread_set_priority(eager_reader_get_read_thread(uart_stream), HCI_THREAD_PRIORITY);
+
return true;
error:
@@ -176,6 +190,40 @@ static bool hal_dev_in_reset()
// Internal functions
+// WORKAROUND:
+// As exhibited by b/23934838, during result-heavy LE scans, the UART byte
+// stream can get corrupted, leading to assertions caused by mis-interpreting
+// the bytes following the corruption.
+// This workaround looks for tell-tale signs of a BLE event and attempts to
+// skip the correct amount of bytes in the stream to re-synchronize onto
+// a packet boundary.
+// Function returns true if |byte_read| has been processed by the workaround.
+static bool stream_corrupted_during_le_scan_workaround(const uint8_t byte_read)
+{
+ if (!stream_corruption_detected && byte_read == HCI_BLE_EVENT) {
+ LOG_ERROR("%s HCI stream corrupted (message type 0x3E)!", __func__);
+ stream_corruption_detected = true;
+ return true;
+ }
+
+ if (stream_corruption_detected) {
+ if (stream_corruption_bytes_to_ignore == 0) {
+ stream_corruption_bytes_to_ignore = byte_read;
+ LOG_ERROR("%s About to skip %d bytes...", __func__, stream_corruption_bytes_to_ignore);
+ } else {
+ --stream_corruption_bytes_to_ignore;
+ }
+
+ if (stream_corruption_bytes_to_ignore == 0) {
+ LOG_ERROR("%s Back to our regularly scheduled program...", __func__);
+ stream_corruption_detected = false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
// See what data is waiting, and notify the upper layer
static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
if (stream_has_interpretation) {
@@ -186,6 +234,10 @@ static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *conte
LOG_ERROR("%s could not read HCI message type", __func__);
return;
}
+
+ if (stream_corrupted_during_le_scan_workaround(type_byte))
+ return;
+
if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
return;
diff --git a/hci/src/hci_inject.c b/hci/src/hci_inject.c
index a17a3d3b7..8ba5f989a 100644
--- a/hci/src/hci_inject.c
+++ b/hci/src/hci_inject.c
@@ -61,6 +61,10 @@ static void read_ready(socket_t *socket, void *context);
static void client_free(void *ptr);
bool hci_inject_open(const hci_t *hci_interface) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return true; // Disable using network sockets for security reasons
+#endif
+
assert(listen_socket == NULL);
assert(thread == NULL);
assert(clients == NULL);
@@ -92,6 +96,10 @@ error:;
}
void hci_inject_close(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+ return; // Disable using network sockets for security reasons
+#endif
+
socket_free(listen_socket);
list_free(clients);
thread_free(thread);
diff --git a/hci/src/low_power_manager.c b/hci/src/low_power_manager.c
index 9435e4fe1..00d0fae53 100644
--- a/hci/src/low_power_manager.c
+++ b/hci/src/low_power_manager.c
@@ -79,7 +79,6 @@ static void init(thread_t *post_thread) {
thread = post_thread;
vendor->set_callback(VENDOR_SET_LPM_MODE, vendor_enable_disable_callback);
- vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
idle_alarm = alarm_new();
if (!idle_alarm) {
@@ -121,7 +120,7 @@ static void wake_assert() {
static void transmit_done() {
transmit_is_done = true;
- if (wake_state == LPM_WAKE_W4_TX_DONE) {
+ if (wake_state == LPM_WAKE_W4_TX_DONE || wake_state == LPM_WAKE_ASSERTED) {
wake_state = LPM_WAKE_W4_TIMEOUT;
start_idle_timer();
}
@@ -147,6 +146,8 @@ static void enable(bool enable) {
} else {
uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
state = enable ? LPM_ENABLING : LPM_DISABLING;
+ if (state == LPM_ENABLING)
+ vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
vendor->send_async_command(VENDOR_SET_LPM_MODE, &command);
}
}
diff --git a/hci/test/hci_hal_h4_test.cpp b/hci/test/hci_hal_h4_test.cpp
index 2c4030d4f..d64e8c4d2 100644
--- a/hci/test/hci_hal_h4_test.cpp
+++ b/hci/test/hci_hal_h4_test.cpp
@@ -43,6 +43,9 @@ DECLARE_TEST_MODES(
type_byte_only
);
+// Use as packet type to test stream_corrupted_during_le_scan_workaround()
+static const uint8_t HCI_BLE_EVENT = 0x3e;
+
static char sample_data1[100] = "A point is that which has no part.";
static char sample_data2[100] = "A line is breadthless length.";
static char sample_data3[100] = "The ends of a line are points.";
@@ -50,6 +53,9 @@ static char acl_data[100] = "A straight line is a line which lies evenly wit
static char sco_data[100] = "A surface is that which has length and breadth only.";
static char event_data[100] = "The edges of a surface are lines.";
+// Test data for stream_corrupted_during_le_scan_workaround()
+static char corrupted_data[] = { 0x5 /* length of remaining data */, 'H', 'e', 'l', 'l', 'o' };
+
static const hci_hal_t *hal;
static int dummy_serial_fd;
static int reentry_i = 0;
@@ -221,6 +227,7 @@ TEST_F(HciHalH4Test, test_read_synchronous) {
reset_for(read_synchronous);
write_packet(sockfd[1], DATA_TYPE_ACL, acl_data);
+ write_packet(sockfd[1], HCI_BLE_EVENT, corrupted_data);
write_packet(sockfd[1], DATA_TYPE_SCO, sco_data);
write_packet(sockfd[1], DATA_TYPE_EVENT, event_data);
diff --git a/osi/include/eager_reader.h b/osi/include/eager_reader.h
index 3bf1e6edf..a172f06e8 100644
--- a/osi/include/eager_reader.h
+++ b/osi/include/eager_reader.h
@@ -23,6 +23,7 @@
#include <stdint.h>
#include "allocator.h"
+#include "osi/include/thread.h"
typedef struct eager_reader_t eager_reader_t;
typedef struct reactor_t reactor_t;
@@ -61,3 +62,7 @@ void eager_reader_unregister(eager_reader_t *reader);
// but you should probably only be reading from one thread anyway,
// otherwise the byte stream probably doesn't make sense.
size_t eager_reader_read(eager_reader_t *reader, uint8_t *buffer, size_t max_size, bool block);
+
+// Returns the inbound read thread for a given |reader| or NULL if the thread
+// is not running.
+thread_t* eager_reader_get_read_thread(const eager_reader_t *reader);
diff --git a/osi/src/alarm.c b/osi/src/alarm.c
index ff168297c..720020bfb 100644
--- a/osi/src/alarm.c
+++ b/osi/src/alarm.c
@@ -35,6 +35,12 @@
#include "osi/include/semaphore.h"
#include "osi/include/thread.h"
+// Make callbacks run at high thread priority. Some callbacks are used for audio
+// related timer tasks as well as re-transmissions etc. Since we at this point
+// cannot differentiate what callback we are dealing with, assume high priority
+// for now.
+// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?)
+static const int CALLBACK_THREAD_PRIORITY_HIGH = -19;
struct alarm_t {
// The lock is held while the callback for this alarm is being executed.
@@ -246,8 +252,7 @@ static bool lazy_initialize(void) {
// during a2dp music playback, media task/btu/hci/event threads are all high priority
// but actual callback thread is remaining normal which mean it's possible not to
// schedule alarm callback in-time if system is busy
- thread_set_priority(callback_thread, TIMER_CALLBACK_THREAD_PRIORITY);
-
+ thread_set_priority(callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
thread_post(callback_thread, callback_dispatch, NULL);
return true;
}
diff --git a/osi/src/eager_reader.c b/osi/src/eager_reader.c
index 63b190ea6..3ca8ad13c 100644
--- a/osi/src/eager_reader.c
+++ b/osi/src/eager_reader.c
@@ -30,7 +30,6 @@
#include "osi/include/osi.h"
#include "osi/include/log.h"
#include "osi/include/reactor.h"
-#include "osi/include/thread.h"
#if !defined(EFD_SEMAPHORE)
# define EFD_SEMAPHORE (1 << 0)
@@ -212,6 +211,11 @@ size_t eager_reader_read(eager_reader_t *reader, uint8_t *buffer, size_t max_siz
return bytes_consumed;
}
+thread_t* eager_reader_get_read_thread(const eager_reader_t *reader) {
+ assert(reader != NULL);
+ return reader->inbound_read_thread;
+}
+
static bool has_byte(const eager_reader_t *reader) {
assert(reader != NULL);
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
index e4dca3fb8..7f1ba27cb 100644
--- a/stack/btm/btm_acl.c
+++ b/stack/btm/btm_acl.c
@@ -1007,15 +1007,16 @@ void btm_read_remote_version_complete (UINT8 *p)
UINT16 handle;
int xx;
BTM_TRACE_DEBUG ("btm_read_remote_version_complete");
+
STREAM_TO_UINT8 (status, p);
- if (status == HCI_SUCCESS)
- {
- STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (handle, p);
- /* Look up the connection by handle and copy features */
- for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
{
- if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ if (status == HCI_SUCCESS)
{
STREAM_TO_UINT8 (p_acl_cb->lmp_version, p);
STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);
@@ -1028,6 +1029,10 @@ void btm_read_remote_version_complete (UINT8 *p)
btm_read_remote_features (p_acl_cb->hci_handle);
break;
}
+
+ if (p_acl_cb->transport == BT_TRANSPORT_LE)
+ l2cble_notify_le_connection (p_acl_cb->remote_addr);
+ break;
}
}
}
diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c
index 19ec9e75a..8c24e7da9 100644
--- a/stack/btm/btm_ble_gap.c
+++ b/stack/btm/btm_ble_gap.c
@@ -3215,8 +3215,7 @@ void btm_ble_read_remote_features_complete(UINT8 *p)
if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
{
STREAM_TO_ARRAY(p_acl_cb->peer_le_features, p, BD_FEATURES_LEN);
- /*notify link up here */
- l2cble_notify_le_connection (p_acl_cb->remote_addr);
+ btsnd_hcic_rmt_ver_req (p_acl_cb->hci_handle);
break;
}
}
diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
index 0888cb57e..250c1c43e 100644
--- a/stack/btu/btu_init.c
+++ b/stack/btu/btu_init.c
@@ -45,6 +45,10 @@
#endif
#endif
+// Increase BTU task thread priority to avoid pre-emption
+// of audio realated tasks.
+#define BTU_TASK_THREAD_PRIORITY -19
+
extern fixed_queue_t *btif_msg_queue;
// Communication queue from bta thread to bt_workqueue.
@@ -193,6 +197,8 @@ void BTU_StartUp(void)
if (bt_workqueue_thread == NULL)
goto error_exit;
+ thread_set_priority(bt_workqueue_thread, BTU_TASK_THREAD_PRIORITY);
+
// Continue startup on bt workqueue thread.
thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
return;
diff --git a/stack/gatt/gatt_auth.c b/stack/gatt/gatt_auth.c
index ae5214592..89e2cc1cd 100644
--- a/stack/gatt/gatt_auth.c
+++ b/stack/gatt/gatt_auth.c
@@ -103,6 +103,11 @@ void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
UINT8 *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
UINT32 counter;
+ if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
+ GATT_TRACE_ERROR("%s: Data length %u less than expected %u",
+ __func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4);
+ return;
+ }
cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
p = p_orig + cmd_len - 4;
STREAM_TO_UINT32(counter, p);
diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c
index 5030c5328..907862ff1 100644
--- a/stack/gatt/gatt_utils.c
+++ b/stack/gatt/gatt_utils.c
@@ -1497,7 +1497,7 @@ UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl)
case LEN_UUID_128:
UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
- ARRAY_TO_BE_STREAM (p, p_uuid->uu.uuid128, LEN_UUID_128);
+ ARRAY_TO_BE_STREAM_REVERSE (p, p_uuid->uu.uuid128, LEN_UUID_128);
SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE,
(UINT32) (p - buff), buff);
break;
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 4ea447eca..453aa38a3 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -286,6 +286,7 @@ typedef struct
#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);}
#define UINT8_TO_BE_STREAM(p, u8) {*(p)++ = (UINT8)(u8);}
#define ARRAY_TO_BE_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];}
+#define ARRAY_TO_BE_STREAM_REVERSE(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[len - ijk - 1];}
#define BE_STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;}
#define BE_STREAM_TO_UINT16(u16, p) {u16 = (UINT16)(((UINT16)(*(p)) << 8) + (UINT16)(*((p) + 1))); (p) += 2;}
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index 41dc936c0..4cd34852a 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -24,6 +24,9 @@
#define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */
#define HCI_PROTO_VERSION_2_1 0x04 /* Version for BT spec 2.1 [Lisbon] */
#define HCI_PROTO_VERSION_3_0 0x05 /* Version for BT spec 3.0 */
+#define HCI_PROTO_VERSION_4_0 0x06 /* Version for BT spec 4.0 */
+#define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */
+#define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */
#define HCI_PROTO_REVISION 0x000C /* Current implementation version */
/*
** Definitions for HCI groups
diff --git a/stack/sdp/sdp_api.c b/stack/sdp/sdp_api.c
index d96ace91d..720fad717 100644
--- a/stack/sdp/sdp_api.c
+++ b/stack/sdp/sdp_api.c
@@ -357,7 +357,8 @@ BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128)
{
p_uuid->len = LEN_UUID_128;
- memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, LEN_UUID_128);
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
}
else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32)
{
@@ -443,8 +444,9 @@ BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
/* only support 128 bits UUID for now */
if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)
{
- p_uuid->len = 16;
- memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, MAX_UUID_SIZE);
+ p_uuid->len = LEN_UUID_128;
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
}
return(TRUE);
}
@@ -457,8 +459,9 @@ BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
/* only support 128 bits UUID for now */
&& (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
{
- p_uuid->len = 16;
- memcpy(p_uuid->uu.uuid128, p_attr->attr_value.v.array, MAX_UUID_SIZE);
+ p_uuid->len = LEN_UUID_128;
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128-i-1];
return(TRUE);
}
}
diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
index 462b02dce..8f758890c 100644
--- a/stack/smp/smp_act.c
+++ b/stack/smp/smp_act.c
@@ -51,6 +51,18 @@ const tSMP_ACT smp_distribute_act [] =
smp_set_derive_link_key
};
+static bool lmp_version_below(BD_ADDR bda, uint8_t version)
+{
+ tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
+ if (acl == NULL || acl->lmp_version == 0)
+ {
+ SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
+ return false;
+ }
+ SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version, version);
+ return acl->lmp_version < version;
+}
+
/*******************************************************************************
** Function smp_update_key_mask
** Description This function updates the key mask for sending or receiving.
@@ -174,7 +186,8 @@ void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)
|| interop_addr_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
- (const bt_bdaddr_t *)&p_cb->pairing_bda))
+ (const bt_bdaddr_t *)&p_cb->pairing_bda)
+ || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2))
{
p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
diff --git a/utils/src/bt_utils.c b/utils/src/bt_utils.c
index 4bd4abdf6..38dd3d51b 100644
--- a/utils/src/bt_utils.c
+++ b/utils/src/bt_utils.c
@@ -170,8 +170,7 @@ void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
// its prio individually. All other threads can be dynamically adjusted voa
// adjust_priority_a2dp()
- if (high_task == TASK_HIGH_HCI_WORKER)
- priority = ANDROID_PRIORITY_URGENT_AUDIO;
+ priority = ANDROID_PRIORITY_URGENT_AUDIO;
if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
LOG_WARN("failed to change priority tid: %d to %d", tid, priority);