From: Andre Guedes <andre.guedes@openbossa.org>
To: linux-bluetooth@vger.kernel.org
Subject: [RFC v2 09/15] Bluetooth: Introduce LE auto connection infrastructure
Date: Tue, 29 Oct 2013 10:25:54 -0300 [thread overview]
Message-ID: <1383053160-10175-10-git-send-email-andre.guedes@openbossa.org> (raw)
In-Reply-To: <1383053160-10175-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.
The auto connection mechanism works as follows: When the first
device address is inserted into hdev->pending_auto_con list, we
start the background scanning. Once the target device is found
in range, the kernel creates the connection. If connection is
established successfully, the device address is removed from
hdev->pending_auto_conn list. Finally, when the last device
address is removed, the background scanning is stopped.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 2 +
net/bluetooth/hci_conn.c | 6 ++
net/bluetooth/hci_core.c | 115 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 43 +++++++++++++++
4 files changed, 166 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 0049036..322918f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -784,6 +784,8 @@ void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
bool hci_is_scan_and_conn_supported(struct hci_dev *hdev);
+void hci_check_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_conn.c b/net/bluetooth/hci_conn.c
index b52bcb2..bbe3cab 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -544,6 +544,12 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
done:
hci_dev_unlock(hdev);
+
+ /* Check the background scanning since it may have been temporarily
+ * stopped if the controller doesn't support scanning and creating
+ * connection at the same time.
+ */
+ hci_check_background_scan(hdev);
}
static int hci_create_le_conn(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 19624d1..79debc3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2923,6 +2923,72 @@ bool hci_has_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
return res;
}
+static void start_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+ if (status)
+ BT_DBG("HCI request failed to start background scanning: "
+ "status 0x%2.2x", status);
+}
+
+static int start_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;
+
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return 0;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_req_init(&req, hdev);
+
+ 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);
+
+ return hci_req_run(&req, start_background_scan_complete);
+}
+
+static void stop_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+ if (status)
+ BT_DBG("HCI request failed to stop background scanning: "
+ "status 0x%2.2x", status);
+}
+
+static int stop_background_scan(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_scan_enable cp;
+ struct hci_request req;
+
+ if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return 0;
+
+ /* If device discovery is running, background scanning is stopped so
+ * we return sucess.
+ */
+ if (hdev->discovery.state == DISCOVERY_FINDING)
+ return 0;
+
+ hci_req_init(&req, hdev);
+
+ memset(&cp, 0, sizeof(cp));
+ cp.enable = LE_SCAN_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+
+ return hci_req_run(&req, stop_background_scan_complete);
+}
+
/* This function requires the caller holds hdev->lock */
int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
u8 addr_type)
@@ -2940,6 +3006,19 @@ int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
bacpy(&entry->bdaddr, addr);
entry->bdaddr_type = addr_type;
+ /* If there is no pending auto connection, the background scanning
+ * is not runnning. So we should start it.
+ */
+ if (list_empty(&hdev->pending_auto_conn)) {
+ int err;
+
+ err = start_background_scan(hdev);
+ if (err) {
+ kfree(entry);
+ return err;
+ }
+ }
+
list_add(&entry->list, &hdev->pending_auto_conn);
return 0;
@@ -2957,6 +3036,14 @@ void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
list_del(&entry->list);
kfree(entry);
+
+ if (list_empty(&hdev->pending_auto_conn)) {
+ int err;
+
+ err = stop_background_scan(hdev);
+ if (err)
+ BT_ERR("Failed to run HCI request: err %d", err);
+ }
}
/* This function requires the caller holds hdev->lock */
@@ -2970,6 +3057,34 @@ static void __clear_pending_auto_conn(struct hci_dev *hdev)
}
}
+/* This function starts the background scanning in case there is still
+ * pending auto connections.
+ */
+void hci_check_background_scan(struct hci_dev *hdev)
+{
+ struct hci_conn *conn;
+ int err;
+
+ if (list_empty(&hdev->pending_auto_conn))
+ return;
+
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ /* If the controller is connecting but it doesn't support scanning
+ * scanning and connecting at the same time we don't start the
+ * background scanning now. It will be started once the connection
+ * is established.
+ */
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (conn && !hci_is_scan_and_conn_supported(hdev))
+ return;
+
+ err = start_background_scan(hdev);
+ if (err)
+ BT_ERR("Failed to start background scanning: err %d", err);
+}
+
static void inquiry_complete(struct hci_dev *hdev, u8 status)
{
if (status) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8b7cd37..e48601d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3547,8 +3547,49 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
+ __hci_remove_pending_auto_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
+
unlock:
hci_dev_unlock(hdev);
+
+ /* Check the background scanning since it may have been temporarily
+ * stopped if the controller doesn't support scanning and creating
+ * connection at the same time.
+ */
+ hci_check_background_scan(hdev);
+}
+
+static void check_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+ u8 addr_type)
+{
+ struct hci_conn *conn;
+ u8 bdaddr_type;
+
+ if (!hci_has_pending_auto_conn(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)) {
+ switch (PTR_ERR(conn)) {
+ case -EBUSY:
+ /* When hci_connect() returns EBUSY it means there is
+ * already an LE connection attempt going on. Since the
+ * controller supports only one connection attempt at
+ * the time, we simply return.
+ */
+ return;
+ default:
+ BT_ERR("Failed to auto connect: err %ld",
+ PTR_ERR(conn));
+ return;
+ }
+ }
}
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3560,6 +3601,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
+ check_pending_auto_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);
--
1.8.4
next prev parent reply other threads:[~2013-10-29 13:25 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-29 13:25 [RFC v2 00/15] LE auto connection and connection parameters Andre Guedes
2013-10-29 13:25 ` [RFC v2 01/15] Bluetooth: Refactor hci_disconn_complete_evt Andre Guedes
2013-10-29 22:52 ` Marcel Holtmann
2013-11-18 18:40 ` Andre Guedes
2013-10-29 13:25 ` [RFC v2 02/15] Bluetooth: Save connection interval parameters in hci_conn Andre Guedes
2013-10-29 22:55 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 03/15] Bluetooth: Stop scanning on connection Andre Guedes
2013-10-29 22:58 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 04/15] Bluetooth: Introduce connection parameters list Andre Guedes
2013-10-29 23:03 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 05/15] Bluetooth: Make find_conn_param() helper non-local Andre Guedes
2013-10-29 23:33 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 06/15] Bluetooth: Use connection parameters if any Andre Guedes
2013-10-29 23:04 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 07/15] Bluetooth: Introduce hdev->pending_auto_conn list Andre Guedes
2013-10-29 23:08 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 08/15] Bluetooth: Move is_scan_and_conn_supported() to hci_core Andre Guedes
2013-10-29 23:09 ` Marcel Holtmann
2013-10-29 13:25 ` Andre Guedes [this message]
2013-10-29 23:30 ` [RFC v2 09/15] Bluetooth: Introduce LE auto connection infrastructure Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 10/15] Bluetooth: Temporarily stop background scanning on discovery Andre Guedes
2013-10-29 23:19 ` Marcel Holtmann
2013-11-18 18:40 ` Andre Guedes
2013-10-29 13:25 ` [RFC v2 11/15] Bluetooth: Auto connection and power on Andre Guedes
2013-10-29 23:13 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 12/15] Bleutooth: Add support for auto connect options Andre Guedes
2013-10-29 23:15 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 13/15] Bluetooth: Add thread-safe version of helpers Andre Guedes
2013-10-29 23:16 ` Marcel Holtmann
2013-10-29 13:25 ` [RFC v2 14/15] Bluetooth: Mgmt command for adding connection parameters Andre Guedes
2013-10-29 13:26 ` [RFC v2 15/15] Bluetooth: Mgmt command for removing " Andre Guedes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1383053160-10175-10-git-send-email-andre.guedes@openbossa.org \
--to=andre.guedes@openbossa.org \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox