* [RFC v4 11/12] Bleutooth: Add support for auto connect options
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch adds support for the HCI_AUTO_CONN_ALWAYS and HCI_AUTO_
CONN_LINK_LOSS options from struct hci_conn_params.
The HCI_AUTO_CONN_ALWAYS option configures the kernel to always re-
establish the connection, no matter the reason the connection was
terminated. This feature is required by some LE profiles such as
HID over GATT, Health Thermometer and Blood Pressure. These profiles
require the host autonomously connect to the device as soon as it
enters in connectable mode (start advertising) so the device is able
to delivery notifications or indications.
The BT_AUTO_CONN_LINK_LOSS option configures the kernel to re-
establish the connection in case the connection was terminated due
to a link loss. This feature is required by the majority of LE
profiles such as Proximity, Find Me, Cycling Speed and Cadence and
Time.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_event.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e4f288a..a4ce922 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1780,6 +1780,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_disconn_complete *ev = (void *) skb->data;
u8 reason = hci_to_mgmt_reason(ev->reason);
+ struct hci_conn_params *params;
struct hci_conn *conn;
u8 type;
@@ -1806,6 +1807,23 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (conn->type == ACL_LINK && conn->flush_key)
hci_remove_link_key(hdev, &conn->dst);
+ params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+ if (params) {
+ switch (params->auto_connect) {
+ case HCI_AUTO_CONN_LINK_LOSS:
+ if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
+ break;
+ /* Fall through */
+
+ case HCI_AUTO_CONN_ALWAYS:
+ hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
+ break;
+
+ default:
+ break;
+ }
+ }
+
type = conn->type;
hci_proto_disconn_cfm(conn, ev->reason);
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 10/12] Bluetooth: Auto connection and power on
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
When hdev is closed (e.g. Mgmt power off command, RFKILL or controller
is reset), the ongoing active connections are silently dropped by the
controller (no Disconnection Complete Event is sent to host). For that
reason, the devices that require HCI_AUTO_CONN_ALWAYS are not added to
hdev->pend_le_conns list and they won't auto connect.
So to fix this issue, during hdev closing, we remove all pending LE
connections. After adapter is powered on, we add a pending LE connection
for each HCI_AUTO_CONN_ALWAYS address.
This way, the auto connection mechanism works propely after a power
off and power on sequence as well as RFKILL block/unblock.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_core.c | 1 +
net/bluetooth/mgmt.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5bb73cf..beb51ce 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1969,6 +1969,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock(hdev);
hci_inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
+ hci_pend_le_conns_clear(hdev);
hci_dev_unlock(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 81b8cfa..3fccb52 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4247,6 +4247,17 @@ void mgmt_index_removed(struct hci_dev *hdev)
mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
}
+/* This function requires the caller holds hdev->lock */
+static void restart_le_auto_conns(struct hci_dev *hdev)
+{
+ struct hci_conn_params *p;
+
+ list_for_each_entry(p, &hdev->le_conn_params, list) {
+ if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
+ hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
+ }
+}
+
static void powered_complete(struct hci_dev *hdev, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
@@ -4255,6 +4266,8 @@ static void powered_complete(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev);
+ restart_le_auto_conns(hdev);
+
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
new_settings(hdev, match.sk);
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 09/12] Bluetooth: Temporarily stop background scanning on discovery
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
If the user send a mgmt start discovery command while the background
scanning is running, we should temporarily stop it. Once the discovery
finishes, we start the background scanning again.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_core.c | 2 ++
net/bluetooth/mgmt.c | 12 ++++++++----
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 47d31bd..5bb73cf 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1498,6 +1498,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
switch (state) {
case DISCOVERY_STOPPED:
+ hci_update_background_scan(hdev);
+
if (hdev->discovery.state != DISCOVERY_STARTING)
mgmt_discovering(hdev, 0);
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a03ca3c..81b8cfa 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3280,11 +3280,15 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
+ /* If controller is scanning, it means the background scanning
+ * is running. Thus, we should temporarily stop it in order to
+ * set the discovery scanning parameters.
+ */
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
- MGMT_STATUS_BUSY);
- mgmt_pending_remove(cmd);
- goto failed;
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
+ sizeof(enable_cp), &enable_cp);
}
memset(¶m_cp, 0, sizeof(param_cp));
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 08/12] Bluetooth: Re-enable background scan in case of error
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
Since we temporarily stop the background scanning in favor of
connection, we should re-enable it in case something goes wrong
with connection establishment. So this patch adds a hci_update_
background_scan() call in create_le_conn_complete() and hci_le_
conn_complete_evt() error flow.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_conn.c | 2 ++
net/bluetooth/hci_event.c | 1 +
2 files changed, 3 insertions(+)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 750a39d..2ca34fa 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -548,6 +548,8 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
hci_conn_del(conn);
+ hci_update_background_scan(hdev);
+
done:
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 60ca708..e4f288a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3522,6 +3522,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
conn->state = BT_CLOSED;
hci_conn_del(conn);
+ hci_update_background_scan(hdev);
goto unlock;
}
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 07/12] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch introduces the LE auto connection infrastructure.
This infrastructure will be used to implement the auto_connect
options from hci_conn_params.
In summary, the auto connection mechanism works as follows: Once the
first pending LE connection is created, the background scanning is
started. When the target device is found in range, the kernel
autonomously starts the connection attempt. If connection is
established successfully, that pending LE connection is deleted and
the background is stopped.
To achieve that, this patch introduces the hci_update_background_scan()
which controls the background scanning state. This function starts or
stops the background scanning based on the hdev->pend_le_conns list. If
there is no pending LE connection, the background scanning is stopped.
Otherwise, we start the background scanning.
Then, every time a pending LE connection is added we call hci_update_
background_scan() so the background scanning is started (in case it is
not already running). Likewise, every time a pending LE connection is
deleted we call hci_update_background_scan() so the background scanning
is stopped (in case this was the last pending LE connection) or it is
started again (in case we have more pending LE connections). This way
the background scanning keeps running until all pending LE connection
are established.
When a device with pending connection is in range, we establish the
connection and delete the pending connection.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 2 +
net/bluetooth/hci_core.c | 86 +++++++++++++++++++++++++++++++++++++++-
net/bluetooth/hci_event.c | 41 +++++++++++++++++++
3 files changed, 127 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b85501d..72dc8f5 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -771,6 +771,8 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conns_clear(struct hci_dev *hdev);
+void hci_update_background_scan(struct hci_dev *hdev);
+
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 05e6073..47d31bd 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2873,7 +2873,7 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (entry)
- return;
+ goto done;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
@@ -2887,6 +2887,9 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
list_add(&entry->list, &hdev->pend_le_conns);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -2896,12 +2899,15 @@ void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (!entry)
- return;
+ goto done;
list_del(&entry->list);
kfree(entry);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -4443,3 +4449,79 @@ static void hci_cmd_work(struct work_struct *work)
}
}
}
+
+static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+ if (status)
+ BT_DBG("HCI request failed to update background scanning: "
+ "status 0x%2.2x", status);
+}
+
+/* This function controls the background scanning based on hdev->pend_le_conns
+ * list. If there are pending LE connection we start the background scanning,
+ * otherwise we stop it.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_update_background_scan(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_scan_param param_cp;
+ struct hci_cp_le_set_scan_enable enable_cp;
+ struct hci_request req;
+ struct hci_conn *conn;
+ int err;
+
+ hci_req_init(&req, hdev);
+
+ if (list_empty(&hdev->pend_le_conns)) {
+ /* If there is no pending LE connections, we should stop
+ * the background scanning.
+ */
+
+ /* If controller is not scanning we are done. */
+ if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+
+ BT_DBG("%s stopping background scanning", hdev->name);
+ } else {
+ /* If there is at least one pending LE connection, we should
+ * keep the background scan running.
+ */
+
+ /* If controller is already scanning we are done. */
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ /* If controller is connecting, we should not start scanning
+ * since some controllers are not able to scan and connect at
+ * the same time.
+ */
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (conn)
+ return;
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = LE_SCAN_PASSIVE;
+ param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
+ param_cp.window = cpu_to_le16(hdev->le_scan_window);
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+ ¶m_cp);
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_ENABLE;
+ enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+
+ BT_DBG("%s starting background scanning", hdev->name);
+ }
+
+ err = hci_req_run(&req, update_background_scan_complete);
+ if (err)
+ BT_ERR("Failed to run HCI request: err %d", err);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5fb3df6..60ca708 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3537,25 +3537,66 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
+ hci_pend_le_conn_del(hdev, &ev->bdaddr, ev->bdaddr_type);
+
unlock:
hci_dev_unlock(hdev);
}
+/* This function requires the caller holds hdev->lock */
+static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
+ u8 addr_type)
+{
+ struct hci_conn *conn;
+ u8 bdaddr_type;
+
+ if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
+ return;
+
+ if (addr_type == ADDR_LE_DEV_PUBLIC)
+ bdaddr_type = BDADDR_LE_PUBLIC;
+ else
+ bdaddr_type = BDADDR_LE_RANDOM;
+
+ conn = hci_connect(hdev, LE_LINK, addr, bdaddr_type, BT_SECURITY_LOW,
+ HCI_AT_NO_BONDING);
+ if (!IS_ERR(conn))
+ return;
+
+ switch (PTR_ERR(conn)) {
+ case -EBUSY:
+ /* If hci_connect() returns -EBUSY it means there is already
+ * an LE connection attempt going on. Since controllers don't
+ * support more than one connection attempt at the time, we
+ * don't consider this an error case.
+ */
+ break;
+ default:
+ BT_ERR("Failed to connect: err %ld", PTR_ERR(conn));
+ }
+}
+
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
s8 rssi;
+ hci_dev_lock(hdev);
+
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
+ check_pending_le_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
+
rssi = ev->data[ev->length];
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
NULL, rssi, 0, 1, ev->data, ev->length);
ptr += sizeof(*ev) + ev->length + 1;
}
+
+ hci_dev_unlock(hdev);
}
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 06/12] Bluetooth: Introduce hdev->pend_le_conn list
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch introduces the hdev->pend_le_conn list which holds the
device addresses the kernel should autonomously connect. It also
introduces some helper functions to manipulate the list.
The list and helper functions will be used by the next patch which
implements the LE auto connection infrastructure.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 7 +++++
net/bluetooth/hci_core.c | 68 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a35b90d..b85501d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -268,6 +268,7 @@ struct hci_dev {
struct list_head long_term_keys;
struct list_head remote_oob_data;
struct list_head le_conn_params;
+ struct list_head pend_le_conns;
struct hci_dev_stats stat;
@@ -764,6 +765,12 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_conn_params_clear(struct hci_dev *hdev);
+struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conns_clear(struct hci_dev *hdev);
+
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dd9a25c..05e6073 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2851,6 +2851,72 @@ void hci_conn_params_clear(struct hci_dev *hdev)
BT_DBG("All LE connection parameters were removed");
}
+/* This function requires the caller holds hdev->lock */
+struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr, u8 addr_type)
+{
+ struct bdaddr_list *entry;
+
+ list_for_each_entry(entry, &hdev->pend_le_conns, list) {
+ if (bacmp(&entry->bdaddr, addr) == 0 &&
+ entry->bdaddr_type == addr_type)
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
+{
+ struct bdaddr_list *entry;
+
+ entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
+ if (entry)
+ return;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ BT_ERR("Out of memory");
+ return;
+ }
+
+ bacpy(&entry->bdaddr, addr);
+ entry->bdaddr_type = addr_type;
+
+ list_add(&entry->list, &hdev->pend_le_conns);
+
+ BT_DBG("addr %pMR (type %u)", addr, addr_type);
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
+{
+ struct bdaddr_list *entry;
+
+ entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
+ if (!entry)
+ return;
+
+ list_del(&entry->list);
+ kfree(entry);
+
+ BT_DBG("addr %pMR (type %u)", addr, addr_type);
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conns_clear(struct hci_dev *hdev)
+{
+ struct bdaddr_list *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+
+ BT_DBG("All LE pending connections cleared");
+}
+
static void inquiry_complete(struct hci_dev *hdev, u8 status)
{
if (status) {
@@ -2962,6 +3028,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->long_term_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_LIST_HEAD(&hdev->le_conn_params);
+ INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->conn_hash.list);
INIT_WORK(&hdev->rx_work, hci_rx_work);
@@ -3148,6 +3215,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
hci_conn_params_clear(hdev);
+ hci_pend_le_conns_clear(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 05/12] Bluetooth: Stop scanning on LE connection
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
Some LE controllers don't support scanning and creating a connection
at the same time. So we should always stop scanning in order to
establish the connection.
Since we may prematurely stop the discovery procedure in favor of
the connection establishment, we should also cancel hdev->le_scan_
disable delayed work and set the discovery state to DISCOVERY_STOPPED.
This change does a small improvement since it is not mandatory the
user stops scanning before connecting anymore. Moreover, this change
is required by upcoming LE auto connection mechanism in order to work
properly with controllers that don't support background scanning and
connection establishment at the same time.
In future, we might want to do a small optimization by checking if
controller is able to scan and connect at the same time. For now,
we want the simplest approach so we always stop scanning (even if
the controller is able to carry out both operations).
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_conn.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b5c3ebff..750a39d 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -518,8 +518,17 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
{
struct hci_conn *conn;
- if (status == 0)
+ if (status == 0) {
+ /* If the discovery procedure was running, we prematurely
+ * stopped it. So we have to change the discovery state.
+ */
+ if (hdev->discovery.state == DISCOVERY_FINDING) {
+ cancel_delayed_work(&hdev->le_scan_disable);
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ }
+
return;
+ }
BT_ERR("HCI request failed to create LE connection: status 0x%2.2x",
status);
@@ -552,6 +561,18 @@ static int hci_create_le_conn(struct hci_conn *conn)
hci_req_init(&req, hdev);
+ /* If controller is scanning, we stop it since some controllers are
+ * not able to scan and connect at the same time.
+ */
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
+ struct hci_cp_le_set_scan_enable enable_cp;
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+ }
+
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 04/12] Bluetooth: Use connection parameters if any
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch changes hci_connect_le() so it uses the connection
parameters specified for the certain device. If no parameters
were configured, we use the default values.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_conn.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 15c689e..b5c3ebff 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -578,6 +578,7 @@ static int hci_create_le_conn(struct hci_conn *conn)
static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u8 auth_type)
{
+ struct hci_conn_params *params;
struct hci_conn *conn;
int err;
@@ -624,8 +625,15 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->sec_level = BT_SECURITY_LOW;
conn->pending_sec_level = sec_level;
conn->auth_type = auth_type;
- conn->le_conn_min_interval = hdev->le_conn_min_interval;
- conn->le_conn_max_interval = hdev->le_conn_max_interval;
+
+ params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+ if (params) {
+ conn->le_conn_min_interval = params->conn_min_interval;
+ conn->le_conn_max_interval = params->conn_max_interval;
+ } else {
+ conn->le_conn_min_interval = hdev->le_conn_min_interval;
+ conn->le_conn_max_interval = hdev->le_conn_max_interval;
+ }
err = hci_create_le_conn(conn);
if (err)
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 03/12] Bluetooth: Introduce connection parameters list
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch adds to hdev the connection parameters list (hdev->le_
conn_params). The elements from this list (struct hci_conn_params)
contains the connection parameters (for now, minimum and maximum
connection interval) that should be used during the connection
establishment.
The struct hci_conn_params also defines the 'auto_connect' field
which will be used to implement the auto connection mechanism.
Moreover, this patch adds helper functions to manipulate hdev->le_
conn_params list. Some of these functions are also declared in
hci_core.h since they will be used outside hci_core.c in upcoming
patches.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 25 +++++++++++++
net/bluetooth/hci_core.c | 80 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index daa6193..a35b90d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -267,6 +267,7 @@ struct hci_dev {
struct list_head link_keys;
struct list_head long_term_keys;
struct list_head remote_oob_data;
+ struct list_head le_conn_params;
struct hci_dev_stats stat;
@@ -371,6 +372,22 @@ struct hci_chan {
__u8 state;
};
+struct hci_conn_params {
+ struct list_head list;
+
+ bdaddr_t addr;
+ u8 addr_type;
+
+ enum {
+ HCI_AUTO_CONN_DISABLED,
+ HCI_AUTO_CONN_ALWAYS,
+ HCI_AUTO_CONN_LINK_LOSS,
+ } auto_connect;
+
+ u16 conn_min_interval;
+ u16 conn_max_interval;
+};
+
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock;
@@ -739,6 +756,14 @@ int hci_blacklist_clear(struct hci_dev *hdev);
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr, u8 addr_type);
+void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+ u8 auto_connect, u16 conn_min_interval,
+ u16 conn_max_interval);
+void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_conn_params_clear(struct hci_dev *hdev);
+
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 03e8355..dd9a25c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2773,6 +2773,84 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type);
}
+/* This function requires the caller holds hdev->lock */
+struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr, u8 addr_type)
+{
+ struct hci_conn_params *params;
+
+ list_for_each_entry(params, &hdev->le_conn_params, list) {
+ if (bacmp(¶ms->addr, addr) == 0 &&
+ params->addr_type == addr_type) {
+ return params;
+ }
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+ u8 auto_connect, u16 conn_min_interval,
+ u16 conn_max_interval)
+{
+ struct hci_conn_params *params;
+
+ params = hci_conn_params_lookup(hdev, addr, addr_type);
+ if (params) {
+ params->auto_connect = auto_connect;
+ params->conn_min_interval = conn_min_interval;
+ params->conn_max_interval = conn_max_interval;
+ return;
+ }
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ BT_ERR("Out of memory");
+ return;
+ }
+
+ bacpy(¶ms->addr, addr);
+ params->addr_type = addr_type;
+ params->auto_connect = auto_connect;
+ params->conn_min_interval = conn_min_interval;
+ params->conn_max_interval = conn_max_interval;
+
+ list_add(¶ms->list, &hdev->le_conn_params);
+
+ BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x "
+ "conn_max_interval 0x%.4x", addr, addr_type, auto_connect,
+ conn_min_interval, conn_max_interval);
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
+{
+ struct hci_conn_params *params;
+
+ params = hci_conn_params_lookup(hdev, addr, addr_type);
+ if (!params)
+ return;
+
+ list_del(¶ms->list);
+ kfree(params);
+
+ BT_DBG("addr %pMR (type %u)", addr, addr_type);
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_conn_params_clear(struct hci_dev *hdev)
+{
+ struct hci_conn_params *params, *tmp;
+
+ list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) {
+ list_del(¶ms->list);
+ kfree(params);
+ }
+
+ BT_DBG("All LE connection parameters were removed");
+}
+
static void inquiry_complete(struct hci_dev *hdev, u8 status)
{
if (status) {
@@ -2883,6 +2961,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->link_keys);
INIT_LIST_HEAD(&hdev->long_term_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
+ INIT_LIST_HEAD(&hdev->le_conn_params);
INIT_LIST_HEAD(&hdev->conn_hash.list);
INIT_WORK(&hdev->rx_work, hci_rx_work);
@@ -3068,6 +3147,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_link_keys_clear(hdev);
hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_conn_params_clear(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 02/12] Bluetooth: Group list_head fields from strcut hci_dev together
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch groups the list_head fields from struct hci_dev together
and removes empty lines between them.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 434ab31..daa6193 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -257,18 +257,15 @@ struct hci_dev {
__u32 req_status;
__u32 req_result;
- struct list_head mgmt_pending;
struct discovery_state discovery;
struct hci_conn_hash conn_hash;
- struct list_head blacklist;
+ struct list_head mgmt_pending;
+ struct list_head blacklist;
struct list_head uuids;
-
struct list_head link_keys;
-
struct list_head long_term_keys;
-
struct list_head remote_oob_data;
struct hci_dev_stats stat;
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 01/12] Bluetooth: Save connection interval parameters in hci_conn
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386367549-29136-1-git-send-email-andre.guedes@openbossa.org>
This patch creates two new fields in struct hci_conn to save the
minimum and maximum connection interval values used to establish
the connection this object represents.
This change is required in order to know what parameters the
connection is currently using.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_conn.c | 6 ++++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f8555ad7..434ab31 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -332,6 +332,8 @@ struct hci_conn {
__u8 passkey_entered;
__u16 disc_timeout;
__u16 setting;
+ __u16 le_conn_min_interval;
+ __u16 le_conn_max_interval;
unsigned long flags;
__u8 remote_cap;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ba5366c..15c689e 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -558,8 +558,8 @@ static int hci_create_le_conn(struct hci_conn *conn)
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.own_address_type = conn->src_type;
- cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval);
- cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval);
+ cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
+ cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
cp.min_ce_len = __constant_cpu_to_le16(0x0000);
cp.max_ce_len = __constant_cpu_to_le16(0x0000);
@@ -624,6 +624,8 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->sec_level = BT_SECURITY_LOW;
conn->pending_sec_level = sec_level;
conn->auth_type = auth_type;
+ conn->le_conn_min_interval = hdev->le_conn_min_interval;
+ conn->le_conn_max_interval = hdev->le_conn_max_interval;
err = hci_create_le_conn(conn);
if (err)
--
1.8.4.2
^ permalink raw reply related
* [RFC v4 00/12] LE auto connection and connection parameters
From: Andre Guedes @ 2013-12-06 22:05 UTC (permalink / raw)
To: linux-bluetooth
Hi all,
This v4 is the same patch set from v3 but rebased on top of current
bluetooth-next tree.
Below follows v3 cover letter:
The main changes from the previous version are:
* Debugfs interface to add auto connect address instead of new mgmt
commands.
* We always stop LE scanning in favor of connection establishment even if
the controller supports scanning and connection at the same time.
* Background scanning is now controlled in one single place (hci_update_
background_scan function).
* RCU was replaced by hdev->lock to protect hdev->le_conn_params list. After
all the changes since the original version of this patch set, I realized
we always operate on hdev->le_conn_params with hdev->lock held so there is
no point in use RCU to protect this list.
In order to test the LE auto connection mechanism please follow the
instructions below.
To add a new auto connection address we write on le_auto_conn file following
the format <address> <address type> <auto_connect>.
The <address type> values are:
* 0 for public address
* 1 for random address
The <auto_connect> values are (for more details see struct hci_conn_params):
* 0 for disabled
* 1 for always
* 2 for link loss
So for instance, if you want the kernel autonomously establishes connections
with device AA:BB:CC:DD:EE:FF (public address) every time the device enters in
connectable mode (starts advertising), you should run the command:
$ echo "AA:BB:CC:DD:EE:FF 0 1" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
To get the list of connection parameters configured in kernel, read the
le_auto_conn file:
$ cat /sys/kernel/debug/bluetooth/hci0/le_auto_conn
Finally, to clear the connection parameters list, write an empty string:
$ echo "" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
BR,
Andre
Andre Guedes (12):
Bluetooth: Save connection interval parameters in hci_conn
Bluetooth: Group list_head fields from strcut hci_dev together
Bluetooth: Introduce connection parameters list
Bluetooth: Use connection parameters if any
Bluetooth: Stop scanning on LE connection
Bluetooth: Introduce hdev->pend_le_conn list
Bluetooth: Introduce LE auto connection infrastructure
Bluetooth: Re-enable background scan in case of error
Bluetooth: Temporarily stop background scanning on discovery
Bluetooth: Auto connection and power on
Bleutooth: Add support for auto connect options
Bluetooth: Add le_auto_conn file on debugfs
include/net/bluetooth/hci_core.h | 43 +++++-
net/bluetooth/hci_conn.c | 39 ++++-
net/bluetooth/hci_core.c | 318 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 60 ++++++++
net/bluetooth/mgmt.c | 25 ++-
5 files changed, 473 insertions(+), 12 deletions(-)
--
1.8.4.2
^ permalink raw reply
* Re: SM: is BlueZ the Master/Initiator or Slave/Responder?
From: Scott James Remnant @ 2013-12-06 19:47 UTC (permalink / raw)
To: Vinicius Costa Gomes
Cc: linux-bluetooth@vger.kernel.org, Holtmann, Marcel, Johan Hedberg,
Brian Gix
In-Reply-To: <20131128165916.GA21429@molly.amr.corp.intel.com>
Great, sounds like I came to the right conclusion myself - after
reading the spec and examining the test case, we couldn't find a
reason to set this bit unless BlueZ can also behave as the Slave,
which is not only something we didn't expect it to do, but also not
something we had claimed in the PICS.
I filed a TSE with the SIG on 11/25 and it looks like they agree too,
and that this test should only be used when a IUT specifies that it
supports both the Master and Slave role, so looks like the TSE will be
approved along with the matching TCW.
Scott
On Thu, Nov 28, 2013 at 8:59 AM, Vinicius Costa Gomes <vcgomes@gmail.com> wrote:
> Hi Scott,
>
> On 13:17 Mon 25 Nov, Scott James Remnant wrote:
>> We are able to pass all qualification tests with BlueZ as the Master except one:
>>
>> TP/KDU/BV-06-C - Master Key Distribution - Encryption Key bit
>>
>> This test requires that BlueZ initiates pairing with the
>> SMP_DIST_ENC_KEY bit set in the init_key_dist member of struct
>> smp_cmd_pairing - however this member is always initialized to zero
>> and never changed.
>
> This test is in theory correct, but it doesn't test anything that does make
> sense at this point. Let me try to explain, setting the Encryption Key bit in
> the initiator key distribution field in the Pairing Request means that the
> Initiator wants to send its Encryption Key to the Responder.
>
> This is only useful in cases that both devices expect the roles to be reversed
> in future connections (The Master of this connection would become the Slave in
> future connections). And IIRC we weren't able to test this role reversal and
> it even offends the current GAP spec for Dual mode devices.
>
>>
>> This seems to have changed at some point in the past, 2b64d153 added
>> MITM mechanism and changed the init_key_dist member initialization
>> from dist_keys to 0
>>
>>
>> So two questions:
>>
>> 1) should BlueZ be able to behave as Master? It passes the majority
>> of the tests except this one.
>
> BlueZ should be able to bahave as Master, if not, it is a bug.
>
>>
>> 2) given the above, is this a bug that init_key_dist is 0 or is it a
>> test plan error that it requires this?
>
> I think it is a bit of both, for the current situation the Master distributing
> its keys doesn't make much sense and we should be able to change this value to
> be able to test the key distribution parts.
>
> What I suggest is adding a debugfs entry to change the value of init_key_dist
> for Pairing Requests, and keep the default being 0.
>
> (disclaimer: I am follwing development from the sidelines for some time, so
> feel free to correct me.)
>
>>
>> Scott
>> --
>> Scott James Remnant | Chrome OS Systems | keybuk@google.com | Google
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> Cheers,
> --
> Vinicius
--
Scott James Remnant | Chrome OS Systems | keybuk@google.com | Google
^ permalink raw reply
* Re: [PATCH RFC] tty_ldisc: add more limits to the @write_wakeup
From: Peter Hurley @ 2013-12-06 16:18 UTC (permalink / raw)
To: Huang Shijie; +Cc: gregkh, linux-serial, marcel, linux-bluetooth
In-Reply-To: <52A1A84B.80409@freescale.com>
On 12/06/2013 05:34 AM, Huang Shijie wrote:
> 于 2013年11月13日 15:30, Huang Shijie 写道:
>> In the uart_handle_cts_change(), uart_write_wakeup() is called after
>> we call @uart_port->ops->start_tx().
>>
>> The Documentation/serial/driver tells us:
>> -----------------------------------------------
>> start_tx(port)
>> Start transmitting characters.
>>
>> Locking: port->lock taken.
>> Interrupts: locally disabled.
>> -----------------------------------------------
>>
>> So when the uart_write_wakeup() is called, the port->lock is taken by
>> the upper. See the following callstack:
>>
>> |_ uart_write_wakeup
>> |_ tty_wakeup
>> |_ ld->ops->write_wakeup
>>
>> With the port->lock held, we call the @write_wakeup. Some implemetation of
>> the @write_wakeup does not notice that the port->lock is held, and it still
>> tries to send data with uart_write() which will try to grab the prot->lock.
>> A dead lock occurs, see the following log caught in the Bluetooth by uart:
>>
>> --------------------------------------------------------------------
>> BUG: spinlock lockup suspected on CPU#0, swapper/0/0
>> lock: 0xdc3f4410, .magic: dead4ead, .owner: swapper/0/0, .owner_cpu: 0
>> CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.10.17-16839-ge4a1bef #1320
>> [<80014cbc>] (unwind_backtrace+0x0/0x138) from [<8001251c>] (show_stack+0x10/0x14)
>> [<8001251c>] (show_stack+0x10/0x14) from [<802816ac>] (do_raw_spin_lock+0x108/0x184)
>> [<802816ac>] (do_raw_spin_lock+0x108/0x184) from [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60)
>> [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) from [<802f5754>] (uart_write+0x38/0xe0)
>> [<802f5754>] (uart_write+0x38/0xe0) from [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168)
>> [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) from [<802dab18>] (tty_wakeup+0x50/0x5c)
>> [<802dab18>] (tty_wakeup+0x50/0x5c) from [<802f81a4>] (imx_rtsint+0x50/0x80)
>> [<802f81a4>] (imx_rtsint+0x50/0x80) from [<802f88f4>] (imx_int+0x158/0x17c)
>> [<802f88f4>] (imx_int+0x158/0x17c) from [<8007abe0>] (handle_irq_event_percpu+0x50/0x194)
>> [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) from [<8007ad60>] (handle_irq_event+0x3c/0x5c)
>> --------------------------------------------------------------------
>>
>> This patch adds more limits to the @write_wakeup, the one who wants to
>> implemet the @write_wakeup should follow the limits which avoid the deadlock.
>>
>> Signed-off-by: Huang Shijie <b32955@freescale.com>
>> ---
>> include/linux/tty_ldisc.h | 5 ++++-
>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>
>> diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
>> index f15c898..539ccc5 100644
>> --- a/include/linux/tty_ldisc.h
>> +++ b/include/linux/tty_ldisc.h
>> @@ -91,7 +91,10 @@
>> * This function is called by the low-level tty driver to signal
>> * that line discpline should try to send more characters to the
>> * low-level driver for transmission. If the line discpline does
>> - * not have any more data to send, it can just return.
>> + * not have any more data to send, it can just return. If the line
>> + * discipline does have some data to send, please arise a tasklet
>> + * or workqueue to do the real data transfer. Do not send data in
>> + * this hook, it may leads to a deadlock.
>> *
>> * int (*hangup)(struct tty_struct *)
>> *
> just a ping.
>
> In actually, this is a BUG in the tty code or BT code.
hci_uart_tx_wakeup() should perform the actual tx in a work item.
Regards,
Peter Hurley
^ permalink raw reply
* [PATCHv2] android: Fix delayed adapter turn off
From: Jakub Tyszkowski @ 2013-12-06 15:30 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
We shouldn't care about pending actions being completed as we want to
turn BT off. This fixes Android UI controlls being locked when BT off
action waits in queue for to long.
---
android/bluetooth.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 6174b1f..e5d8b7a 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1290,17 +1290,24 @@ static void set_mode_complete(uint8_t status, uint16_t length,
new_settings_callback(adapter.index, length, param, NULL);
}
-static bool set_mode(uint16_t opcode, uint8_t mode)
+static bool set_mode(uint16_t opcode, uint8_t mode, bool unqueued)
{
struct mgmt_mode cp;
+ unsigned int mgmt_result;
memset(&cp, 0, sizeof(cp));
cp.val = mode;
DBG("opcode=0x%x mode=0x%x", opcode, mode);
- if (mgmt_send(mgmt_if, opcode, adapter.index, sizeof(cp), &cp,
- set_mode_complete, NULL, NULL) > 0)
+ if (unqueued)
+ mgmt_result = mgmt_reply(mgmt_if, opcode, adapter.index,
+ sizeof(cp), &cp, set_mode_complete, NULL, NULL);
+ else
+ mgmt_result = mgmt_send(mgmt_if, opcode, adapter.index,
+ sizeof(cp), &cp, set_mode_complete, NULL, NULL);
+
+ if (mgmt_result > 0)
return true;
error("Failed to set mode");
@@ -1462,10 +1469,10 @@ static void read_info_complete(uint8_t status, uint16_t length,
missing_settings = adapter.current_settings ^ supported_settings;
if (missing_settings & MGMT_SETTING_SSP)
- set_mode(MGMT_OP_SET_SSP, 0x01);
+ set_mode(MGMT_OP_SET_SSP, 0x01, false);
if (missing_settings & MGMT_SETTING_PAIRABLE)
- set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
+ set_mode(MGMT_OP_SET_PAIRABLE, 0x01, false);
return;
@@ -1926,7 +1933,8 @@ static uint8_t set_scan_mode(const void *buf, uint16_t len)
}
if (cur_conn != conn) {
- if (!set_mode(MGMT_OP_SET_CONNECTABLE, conn ? 0x01 : 0x00))
+ if (!set_mode(MGMT_OP_SET_CONNECTABLE, conn ? 0x01 : 0x00,
+ false))
return HAL_STATUS_FAILED;
}
@@ -2234,7 +2242,7 @@ static void handle_enable_cmd(const void *buf, uint16_t len)
goto failed;
}
- if (!set_mode(MGMT_OP_SET_POWERED, 0x01)) {
+ if (!set_mode(MGMT_OP_SET_POWERED, 0x01, false)) {
status = HAL_STATUS_FAILED;
goto failed;
}
@@ -2253,7 +2261,11 @@ static void handle_disable_cmd(const void *buf, uint16_t len)
goto failed;
}
- if (!set_mode(MGMT_OP_SET_POWERED, 0x00)) {
+ /*
+ * Prioritize BT turn off as not doing it in time makes Android
+ * unstable and locks Bluetooth UI controlls.
+ */
+ if (!set_mode(MGMT_OP_SET_POWERED, 0x00, true)) {
status = HAL_STATUS_FAILED;
goto failed;
}
--
1.8.5
^ permalink raw reply related
* Re: [PATCH RFC] tty_ldisc: add more limits to the @write_wakeup
From: Huang Shijie @ 2013-12-06 10:34 UTC (permalink / raw)
To: Huang Shijie; +Cc: gregkh, linux-serial, marcel, linux-bluetooth
In-Reply-To: <1384327803-5925-1-git-send-email-b32955@freescale.com>
=D3=DA 2013=C4=EA11=D4=C213=C8=D5 15:30, Huang Shijie =D0=B4=B5=C0:
> In the uart_handle_cts_change(), uart_write_wakeup() is called after
> we call @uart_port->ops->start_tx().
>
> The Documentation/serial/driver tells us:
> -----------------------------------------------
> start_tx(port)
> Start transmitting characters.
>
> Locking: port->lock taken.
> Interrupts: locally disabled.
> -----------------------------------------------
>
> So when the uart_write_wakeup() is called, the port->lock is taken by
> the upper. See the following callstack:
>
> |_ uart_write_wakeup
> |_ tty_wakeup
> |_ ld->ops->write_wakeup
>
> With the port->lock held, we call the @write_wakeup. Some implemetation=
of
> the @write_wakeup does not notice that the port->lock is held, and it s=
till
> tries to send data with uart_write() which will try to grab the prot->l=
ock.
> A dead lock occurs, see the following log caught in the Bluetooth by ua=
rt:
>
> --------------------------------------------------------------------
> BUG: spinlock lockup suspected on CPU#0, swapper/0/0
> lock: 0xdc3f4410, .magic: dead4ead, .owner: swapper/0/0, .owner_cpu: 0
> CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.10.17-16839-ge4a=
1bef #1320
> [<80014cbc>] (unwind_backtrace+0x0/0x138) from [<8001251c>] (show_stack=
+0x10/0x14)
> [<8001251c>] (show_stack+0x10/0x14) from [<802816ac>] (do_raw_spin_lock=
+0x108/0x184)
> [<802816ac>] (do_raw_spin_lock+0x108/0x184) from [<806a22b0>] (_raw_spi=
n_lock_irqsave+0x54/0x60)
> [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) from [<802f5754>] (uart=
_write+0x38/0xe0)
> [<802f5754>] (uart_write+0x38/0xe0) from [<80455270>] (hci_uart_tx_wake=
up+0xa4/0x168)
> [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) from [<802dab18>] (tty_wak=
eup+0x50/0x5c)
> [<802dab18>] (tty_wakeup+0x50/0x5c) from [<802f81a4>] (imx_rtsint+0x50/=
0x80)
> [<802f81a4>] (imx_rtsint+0x50/0x80) from [<802f88f4>] (imx_int+0x158/0x=
17c)
> [<802f88f4>] (imx_int+0x158/0x17c) from [<8007abe0>] (handle_irq_event_=
percpu+0x50/0x194)
> [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) from [<8007ad60>] (ha=
ndle_irq_event+0x3c/0x5c)
> --------------------------------------------------------------------
>
> This patch adds more limits to the @write_wakeup, the one who wants to
> implemet the @write_wakeup should follow the limits which avoid the dea=
dlock.
>
> Signed-off-by: Huang Shijie <b32955@freescale.com>
> ---
> include/linux/tty_ldisc.h | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
> index f15c898..539ccc5 100644
> --- a/include/linux/tty_ldisc.h
> +++ b/include/linux/tty_ldisc.h
> @@ -91,7 +91,10 @@
> * This function is called by the low-level tty driver to signal
> * that line discpline should try to send more characters to the
> * low-level driver for transmission. If the line discpline does
> - * not have any more data to send, it can just return.
> + * not have any more data to send, it can just return. If the line
> + * discipline does have some data to send, please arise a tasklet
> + * or workqueue to do the real data transfer. Do not send data in
> + * this hook, it may leads to a deadlock.
> *
> * int (*hangup)(struct tty_struct *)
> *
just a ping.
In actually, this is a BUG in the tty code or BT code.
thanks
Huang Shijie
^ permalink raw reply
* Re: [PATCH v2 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: Johan Hedberg @ 2013-12-06 5:55 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386306533-32239-1-git-send-email-johan.hedberg@gmail.com>
Hi,
On Fri, Dec 06, 2013, johan.hedberg@gmail.com wrote:
> Since there's a nice convenient helper for calculating the minimum of
> two values, let's use that one.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_core.c | 6 +-----
> 1 file changed, 1 insertion(+), 5 deletions(-)
Too early in the morning for me - sending a v3 with a proper subject
(with mps instead of imtu in it).
Johan
^ permalink raw reply
* [PATCH v3 2/2] Bluetooth: Fix valid LE PSM check
From: johan.hedberg @ 2013-12-06 5:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386309293-4708-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The range of valid LE PSMs is 0x0001-0x00ff so the check should be for
"less than or equal to" instead of "less than".
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 35feb9d6c322..ae0054ccee5b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1851,7 +1851,7 @@ static bool is_valid_psm(u16 psm, u8 dst_type)
return false;
if (bdaddr_type_is_le(dst_type))
- return (psm < 0x00ff);
+ return (psm <= 0x00ff);
/* PSM must be odd and lsb of upper byte must be 0 */
return ((psm & 0x0101) == 0x0001);
--
1.8.4.2
^ permalink raw reply related
* [PATCH v3 1/2] Bluetooth: Use min_t for calculating chan->mps
From: johan.hedberg @ 2013-12-06 5:54 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
Since there's a nice convenient helper for calculating the minimum of
two values, let's use that one.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6f308af036..35feb9d6c322 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
chan->sdu_len = 0;
chan->tx_credits = 0;
chan->rx_credits = le_max_credits;
-
- if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
- chan->mps = chan->imtu;
- else
- chan->mps = L2CAP_LE_DEFAULT_MPS;
+ chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
skb_queue_head_init(&chan->tx_q);
}
--
1.8.4.2
^ permalink raw reply related
* [PATCH v3 1/2] Bluetooth: Use min_t for calculating chan->mps
From: johan.hedberg @ 2013-12-06 5:53 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
Since there's a nice convenient helper for calculating the minimum of
two values, let's use that one.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6f308af036..35feb9d6c322 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
chan->sdu_len = 0;
chan->tx_credits = 0;
chan->rx_credits = le_max_credits;
-
- if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
- chan->mps = chan->imtu;
- else
- chan->mps = L2CAP_LE_DEFAULT_MPS;
+ chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
skb_queue_head_init(&chan->tx_q);
}
--
1.8.4.2
^ permalink raw reply related
* Re: [PATCH v2 2/2] Bluetooth: Fix valid LE PSM check
From: Marcel Holtmann @ 2013-12-06 5:52 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1386306533-32239-2-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> The range of valid LE PSMs is 0x0001-0x00ff so the check should be for
> "less than or equal to" instead of "less than".
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH v2 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: Marcel Holtmann @ 2013-12-06 5:51 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1386306533-32239-1-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> Since there's a nice convenient helper for calculating the minimum of
> two values, let's use that one.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_core.c | 6 +-----
> 1 file changed, 1 insertion(+), 5 deletions(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* [PATCH v2 2/2] Bluetooth: Fix valid LE PSM check
From: johan.hedberg @ 2013-12-06 5:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386306533-32239-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The range of valid LE PSMs is 0x0001-0x00ff so the check should be for
"less than or equal to" instead of "less than".
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 35feb9d6c322..ae0054ccee5b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1851,7 +1851,7 @@ static bool is_valid_psm(u16 psm, u8 dst_type)
return false;
if (bdaddr_type_is_le(dst_type))
- return (psm < 0x00ff);
+ return (psm <= 0x00ff);
/* PSM must be odd and lsb of upper byte must be 0 */
return ((psm & 0x0101) == 0x0001);
--
1.8.4.2
^ permalink raw reply related
* [PATCH v2 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: johan.hedberg @ 2013-12-06 5:08 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
Since there's a nice convenient helper for calculating the minimum of
two values, let's use that one.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6f308af036..35feb9d6c322 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
chan->sdu_len = 0;
chan->tx_credits = 0;
chan->rx_credits = le_max_credits;
-
- if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
- chan->mps = chan->imtu;
- else
- chan->mps = L2CAP_LE_DEFAULT_MPS;
+ chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
skb_queue_head_init(&chan->tx_q);
}
--
1.8.4.2
^ permalink raw reply related
* Re: [PATCH 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: Johan Hedberg @ 2013-12-06 5:07 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386306115-30686-1-git-send-email-johan.hedberg@gmail.com>
Hi,
On Fri, Dec 06, 2013, johan.hedberg@gmail.com wrote:
> Since there's a nice convenient helper for calculating the minimum of
> two values, let's use that one.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_core.c | 6 +-----
> 1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 6e6f308af036..8f42cae96dc3 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
> chan->sdu_len = 0;
> chan->tx_credits = 0;
> chan->rx_credits = le_max_credits;
> -
> - if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
> - chan->mps = chan->imtu;
> - else
> - chan->mps = L2CAP_LE_DEFAULT_MPS;
> + chan->imtu = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
Ignore this one. It should obviously be assigning to chan->mps and not
chan->imtu.
Johan
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox