Hi,
The following set of patches introduces disabling/enabling sniff bit
in link policy settings. Further, the sniff mode is than disallowed
while SCO channel is open.
This helps to avoid problems in instability in some of TI controllers
firmware when sniff request comes from remote device during an active
call. Real impact is that controller becomes unconnectable eventhough
page scan is enabled.
Any comments, and possibly ideas, would be highly appreciated.
BR,
Dmitriy
Indeed, the kernel has already something to manage sniff mode
automatically, especially when SCO is part of the question:
get a look at:
/sys/class/bluetooth/hci0/idle_timeout
/sys/class/bluetooth/hci0/sniff_min_interval
/sys/class/bluetooth/hci0/sniff_max_interval
arnaud
On 01/24/2012 02:23 PM, Luiz Augusto von Dentz wrote:
> Hi Dmitriy,
>
> On Tue, Jan 24, 2012 at 2:58 PM, Dmitriy Paliy<[email protected]> wrote:
>> Hi,
>>
>> The following set of patches introduces disabling/enabling sniff bit
>> in link policy settings. Further, the sniff mode is than disallowed
>> while SCO channel is open.
>>
>> This helps to avoid problems in instability in some of TI controllers
>> firmware when sniff request comes from remote device during an active
>> call. Real impact is that controller becomes unconnectable eventhough
>> page scan is enabled.
>>
>> Any comments, and possibly ideas, would be highly appreciated.
> It looks like we would need a new command/operation to support it on
> mgmt which is not addressed by your patches, in the other hand perhaps
> this could be done automatically by the kernel when SCO is active.
>
Hi Dmitriy,
On Tue, Jan 24, 2012 at 2:58 PM, Dmitriy Paliy <[email protected]> wrote:
> Hi,
>
> The following set of patches introduces disabling/enabling sniff bit
> in link policy settings. Further, the sniff mode is than disallowed
> while SCO channel is open.
>
> This helps to avoid problems in instability in some of TI controllers
> firmware when sniff request comes from remote device during an active
> call. Real impact is that controller becomes unconnectable eventhough
> page scan is enabled.
>
> Any comments, and possibly ideas, would be highly appreciated.
It looks like we would need a new command/operation to support it on
mgmt which is not addressed by your patches, in the other hand perhaps
this could be done automatically by the kernel when SCO is active.
--
Luiz Augusto von Dentz
Add hciops_allow_sniff that disables sniff bit mode in link policy
settings or restores link policy to its default value allowing going
to sniff mode.
---
plugins/hciops.c | 34 ++++++++++++++++++++++++++++++++++
src/adapter.h | 1 +
2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/plugins/hciops.c b/plugins/hciops.c
index bc38c9b..d68fe00 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -128,6 +128,9 @@ static struct dev_info {
GSList *keys;
uint8_t pin_length;
+ /* default link policy */
+ uint16_t link_policy;
+
GSList *oob_data;
GSList *uuids;
@@ -461,6 +464,7 @@ static void start_adapter(int index)
if (!(dev->features[1] & LMP_PARK))
link_policy &= ~HCI_LP_PARK;
+ dev->link_policy = link_policy;
link_policy = htobs(link_policy);
hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
sizeof(link_policy), &link_policy);
@@ -3686,6 +3690,35 @@ static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
return 0;
}
+static int hciops_allow_sniff(int index, bdaddr_t *bdaddr, gboolean enable)
+{
+ struct dev_info *dev = &devs[index];
+ struct bt_conn *conn;
+ write_link_policy_cp cp;
+ char addr[18];
+
+ conn = find_connection(dev, bdaddr);
+ if (conn == NULL)
+ return -EINVAL;
+
+ if (enable)
+ cp.policy = dev->link_policy;
+ else
+ cp.policy = dev->link_policy & ~HCI_LP_SNIFF;
+
+ cp.handle = htobs(conn->handle);
+ cp.policy = htobs(cp.policy);
+
+ ba2str(bdaddr, addr);
+ DBG("hci%d bdaddr %s handle 0x%04x link_policy 0x%04x",
+ index, addr, cp.handle, cp.policy);
+ if (hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
+ WRITE_LINK_POLICY_CP_SIZE, &cp) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
static struct btd_adapter_ops hci_ops = {
.setup = hciops_setup,
.cleanup = hciops_cleanup,
@@ -3728,6 +3761,7 @@ static struct btd_adapter_ops hci_ops = {
.read_local_oob_data = hciops_read_local_oob_data,
.add_remote_oob_data = hciops_add_remote_oob_data,
.remove_remote_oob_data = hciops_remove_remote_oob_data,
+ .allow_sniff = hciops_allow_sniff,
};
static int hciops_init(void)
diff --git a/src/adapter.h b/src/adapter.h
index 308af75..6e57d17 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -241,6 +241,7 @@ struct btd_adapter_ops {
int (*add_remote_oob_data) (int index, bdaddr_t *bdaddr, uint8_t *hash,
uint8_t *randomizer);
int (*remove_remote_oob_data) (int index, bdaddr_t *bdaddr);
+ int (*allow_sniff) (int index, bdaddr_t *bdaddr, gboolean enable);
};
int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
--
1.7.5.4
This patch enables controlling permission to enter into sniff mode,
or to leave it, from audio manager through adapter's API.
---
audio/manager.c | 15 +++++++++++++++
audio/manager.h | 2 ++
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/audio/manager.c b/audio/manager.c
index 0b52520..33137ce 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -1418,3 +1418,18 @@ void manager_set_fast_connectable(gboolean enable)
adapter_get_dev_id(adapter->btd_adapter));
}
}
+
+void manager_allow_sniff(struct audio_device *dev, gboolean enable)
+{
+ struct btd_adapter *adapter;
+
+ adapter = manager_find_adapter(&dev->src);
+ if (!adapter)
+ return;
+
+ DBG("change link policy for hci%d", adapter_get_dev_id(adapter));
+
+ if (btd_adapter_allow_sniff(adapter, &dev->dst, enable))
+ error("Changing link policy for hci%d failed",
+ adapter_get_dev_id(adapter));
+}
diff --git a/audio/manager.h b/audio/manager.h
index 0bf7663..cd1c86d 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -54,3 +54,5 @@ gboolean manager_allow_headset_connection(struct audio_device *device);
/* TRUE to enable fast connectable and FALSE to disable fast connectable for all
* audio adapters. */
void manager_set_fast_connectable(gboolean enable);
+
+void manager_allow_sniff(struct audio_device *dev, gboolean enable);
--
1.7.5.4
This makes hciops_allow_sniff exposed as adapter's API.
---
src/adapter.c | 12 ++++++++++++
src/adapter.h | 3 +++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index cf21ab4..7d8a647 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3785,3 +3785,15 @@ int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
{
return adapter_ops->remove_remote_oob_data(adapter->dev_id, bdaddr);
}
+
+int btd_adapter_allow_sniff(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+ gboolean enable)
+{
+ if (!adapter_ops)
+ return -EINVAL;
+
+ if (!adapter->up)
+ return -EINVAL;
+
+ return adapter_ops->allow_sniff(adapter->dev_id, bdaddr, enable);
+}
diff --git a/src/adapter.h b/src/adapter.h
index 6e57d17..066f36e 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -301,3 +301,6 @@ int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
bdaddr_t *bdaddr);
+
+int btd_adapter_allow_sniff(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+ gboolean enable);
--
1.7.5.4
Some Bluetooth controllers do not handle well entering sniff mode
requests while SCO channel is active, which may result in instability
in firmware.
This patch disallows entering sniff mode while SCO channel is open, and
restores link policy settings back to its default value when SCO is
closed.
The real problem is in firmware but this workaround helps to avoid
related to it problems.
---
audio/headset.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index 819e0f8..2e5193d 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -581,6 +581,8 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
DBG("SCO socket opened for headset %s", dev->path);
+ manager_allow_sniff(dev, FALSE);
+
sk = g_io_channel_unix_get_fd(chan);
DBG("SCO fd=%d", sk);
@@ -1243,6 +1245,8 @@ static void close_sco(struct audio_device *device)
g_io_channel_shutdown(hs->sco, TRUE, NULL);
g_io_channel_unref(hs->sco);
hs->sco = NULL;
+
+ manager_allow_sniff(device, TRUE);
}
if (hs->sco_id) {
--
1.7.5.4