Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCHv4] hog: Use HoG device name as uHID input device name
From: Petri Gynther @ 2014-02-18 19:58 UTC (permalink / raw)
  To: linux-bluetooth

---
 profiles/input/hog.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/profiles/input/hog.c b/profiles/input/hog.c
index ded6303..7a54aa1 100644
--- a/profiles/input/hog.c
+++ b/profiles/input/hog.c
@@ -91,6 +91,7 @@ struct hog_device {
 	uint16_t		proto_mode_handle;
 	uint16_t		ctrlpt_handle;
 	uint8_t			flags;
+	char			*name;
 };
 
 struct report {
@@ -392,7 +393,8 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	/* create uHID device */
 	memset(&ev, 0, sizeof(ev));
 	ev.type = UHID_CREATE;
-	strcpy((char *) ev.u.create.name, "bluez-hog-device");
+	strncpy((char *) ev.u.create.name, hogdev->name,
+						sizeof(ev.u.create.name) - 1);
 	ev.u.create.vendor = vendor;
 	ev.u.create.product = product;
 	ev.u.create.version = version;
@@ -722,6 +724,7 @@ static struct hog_device *hog_new_device(struct btd_device *device,
 								uint16_t id)
 {
 	struct hog_device *hogdev;
+	char name[HCI_MAX_NAME_LENGTH + 1];
 
 	hogdev = g_try_new0(struct hog_device, 1);
 	if (!hogdev)
@@ -729,6 +732,12 @@ static struct hog_device *hog_new_device(struct btd_device *device,
 
 	hogdev->id = id;
 	hogdev->device = btd_device_ref(device);
+	device_get_name(device, name, HCI_MAX_NAME_LENGTH);
+	name[HCI_MAX_NAME_LENGTH] = '\0';
+	if (strlen(name) > 0)
+		hogdev->name = g_strdup(name);
+	else
+		hogdev->name = g_strdup("bluez-hog-device");
 
 	return hogdev;
 }
@@ -751,6 +760,7 @@ static void hog_free_device(struct hog_device *hogdev)
 	g_slist_free_full(hogdev->reports, report_free);
 	g_attrib_unref(hogdev->attrib);
 	g_free(hogdev->hog_primary);
+	g_free(hogdev->name);
 	g_free(hogdev);
 }
 
-- 
1.9.0.rc1.175.g0b1dcb5


^ permalink raw reply related

* Re: [RFC v9 01/10] Bluetooth: Create hci_req_add_le_scan_disable helper
From: Marcel Holtmann @ 2014-02-18 19:50 UTC (permalink / raw)
  To: Andre Guedes; +Cc: linux-bluetooth
In-Reply-To: <1392746101-5981-1-git-send-email-andre.guedes@openbossa.org>

Hi Andre,

> This patch moves stop LE scanning duplicate code to one single
> place and reuses it. This will avoid more duplicate code in
> upcoming patches.
> 
> Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> ---
> include/net/bluetooth/hci_core.h |  1 +
> net/bluetooth/hci_core.c         | 14 ++++++++++----
> net/bluetooth/mgmt.c             |  6 +-----
> 3 files changed, 12 insertions(+), 9 deletions(-)

can you please rebase this against bluetooth-next. Unfortunately you are conflicting with Johan’s work for resolving private addresses.

Regards

Marcel


^ permalink raw reply

* Re: [PATCHv2] adapter: Handle MGMT_SETTING_LE change
From: Johan Hedberg @ 2014-02-18 19:49 UTC (permalink / raw)
  To: Petri Gynther; +Cc: linux-bluetooth
In-Reply-To: <20140218185506.C44B81005C1@puck.mtv.corp.google.com>

Hi Petri,

On Tue, Feb 18, 2014, Petri Gynther wrote:
> On dual-mode Bluetooth adapters, BLE is not enabled by default. When bluetoothd
> starts, BLE is enabled in read_info_complete(), but this management action does
> not always complete before adapter_start() is called. Therefore, bluetoothd
> needs to handle the MGMT_SETTING_LE change correctly in settings_changed().
> Specifically, trigger_passive_scanning() needs to be called so that paired BLE
> devices (e.g. HoG devices) are able to reconnect back to host.
> 
> The trace below shows this case:
> bluetoothd[1087]: src/adapter.c:adapter_start() adapter /org/bluez/hci0 has been enabled
>  => adapter_start() is called, but BLE is not yet enabled
> bluetoothd[1087]: src/adapter.c:load_link_keys_complete() link keys loaded for hci0
> bluetoothd[1087]: src/adapter.c:load_ltks_complete() LTKs loaded for hci0
> bluetoothd[1087]: src/adapter.c:get_connections_complete() Connection count: 0
> bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000000c1
> bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000040
> bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002c1
> bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000200
>  => BLE got enabled, so need to call trigger_passive_scanning()
> bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002d1
> bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000010
> bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002d3
> bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000002
> 
> The issue is easily reproducible with this init sequence:
> hciconfig hci0 up
> bluetoothd -n -d
> ---
>  src/adapter.c | 7 +++++++
>  1 file changed, 7 insertions(+)

Applied (after reformatting the commit message a bit to follow the "less
than 76 chars wide" rule). Thanks.

Johan

^ permalink raw reply

* Re: [PATCH 0/7] Bluetooth: More privacy related patches
From: Marcel Holtmann @ 2014-02-18 19:49 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> Here are some updated patches from the previous set that still didn't
> make it upstream as well as some new ones. I'm now starting to be at the
> point where the next inevitable step is to add the New IRK mgmt event
> (which I've been postponing so far).
> 
> Johan
> 
> ----------------------------------------------------------------
> Johan Hedberg (7):
>      Bluetooth: Remove SMP data specific crypto context
>      Bluetooth: Track the LE Identity Address in struct hci_conn
>      Bluetooth: Fix updating Identity Address in L2CAP channels
>      Bluetooth: Wait for SMP key distribution completion when pairing
>      Bluetooth: Don't try to look up private addresses as Identity Address
>      Bluetooth: Look up RPA for connection requests with Identity Address
>      Bluetooth: Use Identity Address in Device Found event
> 
> include/net/bluetooth/hci_core.h |  1 +
> include/net/bluetooth/l2cap.h    |  1 +
> net/bluetooth/hci_conn.c         | 19 +++++++++++++-----
> net/bluetooth/hci_core.c         |  4 ++++
> net/bluetooth/hci_event.c        |  8 ++++++++
> net/bluetooth/l2cap_core.c       | 17 +++++++++++++++++
> net/bluetooth/mgmt.c             | 37 ++++++++++++++++++++++++++++--------
> net/bluetooth/smp.c              | 36 ++++++++++++++++++++++++-----------
> net/bluetooth/smp.h              |  2 +-
> 9 files changed, 100 insertions(+), 25 deletions(-)

all 7 patches have been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply

* [PATCH] Bluetooth: Print error when dropping L2CAP data
From: Szymon Janc @ 2014-02-18 19:48 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Silently dropping L2CAP data (i.e. due to remote device not obeying
negotiated MTU) is confusing and makes debugging harder.

Signed-off-by: Szymon Janc <szymon.janc@gmail.com>
---

I also wonder if kernel shouldn't just disconnect if data would be
dropped. This is reliable connection after all...

 net/bluetooth/l2cap_core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6b3a9..7e0c51a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -6759,8 +6759,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
 		 * But we don't have any other choice. L2CAP doesn't
 		 * provide flow control mechanism. */
 
-		if (chan->imtu < skb->len)
+		if (chan->imtu < skb->len) {
+			BT_ERR("Dropping L2CAP data: receive buffer overflow");
 			goto drop;
+		}
 
 		if (!chan->ops->recv(chan, skb))
 			goto done;
-- 
1.9.0.rc3


^ permalink raw reply related

* Re: [PATCH v2 10/10] Bluetooth: Wait for SMP key distribution completion when pairing
From: Johan Hedberg @ 2014-02-18 19:48 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <64342F55-7059-49C3-92FF-7ED23AB904D1@holtmann.org>

Hi Marcel,

On Tue, Feb 18, 2014, Marcel Holtmann wrote:
> > +	cmd = find_pairing(conn);
> > +	if (!cmd)
> > +		BT_DBG("Unable to find a pending command”);
> 
> why do we bother with the debug print here?
> 
> > +	else
> > +		pairing_complete(cmd, status);
> 
> I would just do this:
> 
> 	if (cmd)
> 		pairing_complete(cmd, status);
> 
> Unless you have future patches that do more work here.

The main reason was to get some idea how frequently this function gets
called unnecessarily, but you're right in that it's kind of useless.
I've removed it in my latest set.

Johan

^ permalink raw reply

* [PATCH 7/7] Bluetooth: Use Identity Address in Device Found event
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Whenever a device uses an RPA we want to have user space identify it by
its Identity Address if we've got an IRK available for it. This patch
updates the Device Found mgmt event to contain the Identity Address if
an IRK is available for the device in question.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/mgmt.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 24a85fe76cd8..747cb9bbc331 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5325,6 +5325,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 {
 	char buf[512];
 	struct mgmt_ev_device_found *ev = (void *) buf;
+	struct smp_irk *irk;
 	size_t ev_size;
 
 	if (!hci_discovery_active(hdev))
@@ -5336,8 +5337,15 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 
 	memset(buf, 0, sizeof(buf));
 
-	bacpy(&ev->addr.bdaddr, bdaddr);
-	ev->addr.type = link_to_bdaddr(link_type, addr_type);
+	irk = hci_get_irk(hdev, bdaddr, addr_type);
+	if (irk) {
+		bacpy(&ev->addr.bdaddr, &irk->bdaddr);
+		ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
+	} else {
+		bacpy(&ev->addr.bdaddr, bdaddr);
+		ev->addr.type = link_to_bdaddr(link_type, addr_type);
+	}
+
 	ev->rssi = rssi;
 	if (cfm_name)
 		ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 6/7] Bluetooth: Look up RPA for connection requests with Identity Address
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

We need to check whether there's a matching IRK and RPA when we're
requested to connect to a remote LE device based on its Identity
Address. This patch updates the hci_connect_le function to do an extra
call to hci_find_irk_by_addr and uses the RPA if it's cached. This is
particularly important once we start exposing the Identity Address to
user space instead of the RPA in events such as Device Connected and
Device Found.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_conn.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 67972928a623..40ec37355d6f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -588,6 +588,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 {
 	struct hci_conn_params *params;
 	struct hci_conn *conn;
+	struct smp_irk *irk;
 	int err;
 
 	if (test_bit(HCI_ADVERTISING, &hdev->flags))
@@ -616,15 +617,23 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 	if (conn)
 		return ERR_PTR(-EBUSY);
 
+	/* Convert from L2CAP channel address type to HCI address type */
+	if (dst_type == BDADDR_LE_PUBLIC)
+		dst_type = ADDR_LE_DEV_PUBLIC;
+	else
+		dst_type = ADDR_LE_DEV_RANDOM;
+
+	irk = hci_find_irk_by_addr(hdev, dst, dst_type);
+	if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
+		dst = &irk->rpa;
+		dst_type = ADDR_LE_DEV_RANDOM;
+	}
+
 	conn = hci_conn_add(hdev, LE_LINK, dst);
 	if (!conn)
 		return ERR_PTR(-ENOMEM);
 
-	if (dst_type == BDADDR_LE_PUBLIC)
-		conn->dst_type = ADDR_LE_DEV_PUBLIC;
-	else
-		conn->dst_type = ADDR_LE_DEV_RANDOM;
-
+	conn->dst_type = dst_type;
 	conn->src_type = hdev->own_addr_type;
 
 	conn->state = BT_CONNECT;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 5/7] Bluetooth: Don't try to look up private addresses as Identity Address
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Identity Addresses are either public or static random. When looking up
addresses based on the Identity Address it doesn't make sense to go
through the IRK list if we're given a private random address. This patch
fixes (or rather improves) the hci_find_irk_by_addr function to bail out
early if given a private random address.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cdba4709f012..e4c5b9d6083c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2662,6 +2662,10 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 {
 	struct smp_irk *irk;
 
+	/* Identity Address must be public or static random */
+	if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0)
+		return NULL;
+
 	list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
 		if (addr_type == irk->addr_type &&
 		    bacmp(bdaddr, &irk->bdaddr) == 0)
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 4/7] Bluetooth: Wait for SMP key distribution completion when pairing
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

When we initiate pairing through mgmt_pair_device the code has so far
been waiting for a successful HCI Encrypt Change event in order to
respond to the mgmt command. However, putting privacy into the play we
actually want the key distribution to be complete before replying so
that we can include the Identity Address in the mgmt response.

This patch updates the various hci_conn callbacks for LE in mgmt.c to
only respond in the case of failure, and adds a new mgmt_smp_complete
function that the SMP code will call once key distribution has been
completed.

Since the smp_chan_destroy function that's used to indicate completion
and clean up the SMP context can be called from various places,
including outside of smp.c, the easiest way to track failure vs success
is a new flag that we set once key distribution has been successfully
completed.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/mgmt.c             | 25 +++++++++++++++++++------
 net/bluetooth/smp.c              |  5 +++++
 net/bluetooth/smp.h              |  1 +
 4 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4461c0051228..64c4e3f0a515 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
 void mgmt_reenable_advertising(struct hci_dev *hdev);
+void mgmt_smp_complete(struct hci_conn *conn, bool complete);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 90aac905a98b..24a85fe76cd8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2655,6 +2655,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 	mgmt_pending_remove(cmd);
 }
 
+void mgmt_smp_complete(struct hci_conn *conn, bool complete)
+{
+	u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
+	struct pending_cmd *cmd;
+
+	cmd = find_pairing(conn);
+	if (cmd)
+		pairing_complete(cmd, status);
+}
+
 static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
 	struct pending_cmd *cmd;
@@ -2668,7 +2678,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 		pairing_complete(cmd, mgmt_status(status));
 }
 
-static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
+static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
 	struct pending_cmd *cmd;
 
@@ -2755,13 +2765,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	/* For LE, just connecting isn't a proof that the pairing finished */
-	if (cp->addr.type == BDADDR_BREDR)
+	if (cp->addr.type == BDADDR_BREDR) {
 		conn->connect_cfm_cb = pairing_complete_cb;
-	else
-		conn->connect_cfm_cb = le_connect_complete_cb;
+		conn->security_cfm_cb = pairing_complete_cb;
+		conn->disconn_cfm_cb = pairing_complete_cb;
+	} else {
+		conn->connect_cfm_cb = le_pairing_complete_cb;
+		conn->security_cfm_cb = le_pairing_complete_cb;
+		conn->disconn_cfm_cb = le_pairing_complete_cb;
+	}
 
-	conn->security_cfm_cb = pairing_complete_cb;
-	conn->disconn_cfm_cb = pairing_complete_cb;
 	conn->io_capability = cp->io_cap;
 	cmd->user_data = conn;
 
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index b6a2a8942b2d..27eebca260fa 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -565,9 +565,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 void smp_chan_destroy(struct l2cap_conn *conn)
 {
 	struct smp_chan *smp = conn->smp_chan;
+	bool complete;
 
 	BUG_ON(!smp);
 
+	complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
+	mgmt_smp_complete(conn->hcon, complete);
+
 	kfree(smp);
 	conn->smp_chan = NULL;
 	conn->hcon->smp_conn = NULL;
@@ -1187,6 +1191,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 	if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) {
 		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
 		cancel_delayed_work_sync(&conn->security_timer);
+		set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
 		smp_chan_destroy(conn);
 	}
 
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 8f54c9b152de..675fd3b21d2c 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -118,6 +118,7 @@ struct smp_cmd_security_req {
 #define SMP_FLAG_TK_VALID	1
 #define SMP_FLAG_CFM_PENDING	2
 #define SMP_FLAG_MITM_AUTH	3
+#define SMP_FLAG_COMPLETE	4
 
 struct smp_chan {
 	struct l2cap_conn *conn;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 3/7] Bluetooth: Fix updating Identity Address in L2CAP channels
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

When we receive a remote identity address during SMP key distribution we
should ensure that any associated L2CAP channel instances get their
address information correspondingly updated (so that e.g. doing
getpeername on associated sockets returns the correct address).

This patch adds a new L2CAP core function l2cap_conn_update_id_addr()
which is used to iterate through all L2CAP channels associated with a
connection and update their address information.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 17 +++++++++++++++++
 net/bluetooth/smp.c           |  2 ++
 3 files changed, 20 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 13bec91785f4..4abdcb220e3a 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -881,6 +881,7 @@ int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
+void l2cap_conn_update_id_addr(struct hci_conn *hcon);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
 void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6b3a9c8e6d..c3bda6445f3d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -609,6 +609,23 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 	return;
 }
 
+void l2cap_conn_update_id_addr(struct hci_conn *hcon)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct l2cap_chan *chan;
+
+	mutex_lock(&conn->chan_lock);
+
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		l2cap_chan_lock(chan);
+		bacpy(&chan->dst, &hcon->dst);
+		chan->dst_type = bdaddr_type(hcon, hcon->dst_type);
+		l2cap_chan_unlock(chan);
+	}
+
+	mutex_unlock(&conn->chan_lock);
+}
+
 static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index af29afed0cca..b6a2a8942b2d 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -991,6 +991,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
 	bacpy(&hcon->dst, &smp->id_addr);
 	hcon->dst_type = smp->id_addr_type;
 
+	l2cap_conn_update_id_addr(hcon);
+
 	smp_distribute_keys(conn, 1);
 
 	return 0;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 2/7] Bluetooth: Track the LE Identity Address in struct hci_conn
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Since we want user space to see and use the LE Identity Address whenever
interfacing with the kernel it makes sense to track that instead of the
real address (the two will only be different in the case of an RPA).
This patch adds the necessary updates to when an LE connection gets
established and when receiving the Identity Address from a remote
device.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_event.c | 8 ++++++++
 net/bluetooth/smp.c       | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d2c6878a9d6a..49a2d4d841df 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3568,6 +3568,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
+	struct smp_irk *irk;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -3600,6 +3601,13 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		}
 	}
 
+	/* Track the connection based on the Identity Address from now on */
+	irk = hci_get_irk(hdev, &ev->bdaddr, ev->bdaddr_type);
+	if (irk) {
+		bacpy(&conn->dst, &irk->bdaddr);
+		conn->dst_type = irk->addr_type;
+	}
+
 	if (ev->status) {
 		mgmt_connect_failed(hdev, &conn->dst, conn->type,
 				    conn->dst_type, ev->status);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 8517d1f0984d..af29afed0cca 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -987,6 +987,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
 	hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type,
 		    smp->irk, &rpa);
 
+	/* Track the connection based on the Identity Address from now on */
+	bacpy(&hcon->dst, &smp->id_addr);
+	hcon->dst_type = smp->id_addr_type;
+
 	smp_distribute_keys(conn, 1);
 
 	return 0;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 1/7] Bluetooth: Remove SMP data specific crypto context
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392752497-8696-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Now that each HCI device has its own AES crypto context we don't need
the one stored in the SMP data any more. This patch removes the variable
from struct smp_chan and updates the SMP code to use the per-hdev crypto
context.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 27 +++++++++++++++------------
 net/bluetooth/smp.h |  1 -
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 0c0dd1b52b66..8517d1f0984d 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -413,20 +413,16 @@ static void confirm_work(struct work_struct *work)
 {
 	struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
 	struct l2cap_conn *conn = smp->conn;
-	struct crypto_blkcipher *tfm;
+	struct hci_dev *hdev = conn->hcon->hdev;
+	struct crypto_blkcipher *tfm = hdev->tfm_aes;
 	struct smp_cmd_pairing_confirm cp;
 	int ret;
 	u8 res[16], reason;
 
 	BT_DBG("conn %p", conn);
 
-	tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(tfm)) {
-		reason = SMP_UNSPECIFIED;
-		goto error;
-	}
-
-	smp->tfm = tfm;
+	/* Prevent mutual access to hdev->tfm_aes */
+	hci_dev_lock(hdev);
 
 	if (conn->hcon->out)
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
@@ -436,6 +432,9 @@ static void confirm_work(struct work_struct *work)
 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
 			     conn->hcon->dst_type, &conn->hcon->dst,
 			     conn->hcon->src_type, &conn->hcon->src, res);
+
+	hci_dev_unlock(hdev);
+
 	if (ret) {
 		reason = SMP_UNSPECIFIED;
 		goto error;
@@ -457,7 +456,8 @@ static void random_work(struct work_struct *work)
 	struct smp_chan *smp = container_of(work, struct smp_chan, random);
 	struct l2cap_conn *conn = smp->conn;
 	struct hci_conn *hcon = conn->hcon;
-	struct crypto_blkcipher *tfm = smp->tfm;
+	struct hci_dev *hdev = hcon->hdev;
+	struct crypto_blkcipher *tfm = hdev->tfm_aes;
 	u8 reason, confirm[16], res[16], key[16];
 	int ret;
 
@@ -468,6 +468,9 @@ static void random_work(struct work_struct *work)
 
 	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
+	/* Prevent mutual access to hdev->tfm_aes */
+	hci_dev_lock(hdev);
+
 	if (hcon->out)
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
 			     hcon->src_type, &hcon->src,
@@ -476,6 +479,9 @@ static void random_work(struct work_struct *work)
 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
 			     hcon->dst_type, &hcon->dst,
 			     hcon->src_type, &hcon->src, res);
+
+	hci_dev_unlock(hdev);
+
 	if (ret) {
 		reason = SMP_UNSPECIFIED;
 		goto error;
@@ -562,9 +568,6 @@ void smp_chan_destroy(struct l2cap_conn *conn)
 
 	BUG_ON(!smp);
 
-	if (smp->tfm)
-		crypto_free_blkcipher(smp->tfm);
-
 	kfree(smp);
 	conn->smp_chan = NULL;
 	conn->hcon->smp_conn = NULL;
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 4f373bc56ad7..8f54c9b152de 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -133,7 +133,6 @@ struct smp_chan {
 	u8		id_addr_type;
 	u8		irk[16];
 	unsigned long	smp_flags;
-	struct crypto_blkcipher	*tfm;
 	struct work_struct confirm;
 	struct work_struct random;
 };
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 0/7] Bluetooth: More privacy related patches
From: johan.hedberg @ 2014-02-18 19:41 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

Here are some updated patches from the previous set that still didn't
make it upstream as well as some new ones. I'm now starting to be at the
point where the next inevitable step is to add the New IRK mgmt event
(which I've been postponing so far).

Johan

----------------------------------------------------------------
Johan Hedberg (7):
      Bluetooth: Remove SMP data specific crypto context
      Bluetooth: Track the LE Identity Address in struct hci_conn
      Bluetooth: Fix updating Identity Address in L2CAP channels
      Bluetooth: Wait for SMP key distribution completion when pairing
      Bluetooth: Don't try to look up private addresses as Identity Address
      Bluetooth: Look up RPA for connection requests with Identity Address
      Bluetooth: Use Identity Address in Device Found event

 include/net/bluetooth/hci_core.h |  1 +
 include/net/bluetooth/l2cap.h    |  1 +
 net/bluetooth/hci_conn.c         | 19 +++++++++++++-----
 net/bluetooth/hci_core.c         |  4 ++++
 net/bluetooth/hci_event.c        |  8 ++++++++
 net/bluetooth/l2cap_core.c       | 17 +++++++++++++++++
 net/bluetooth/mgmt.c             | 37 ++++++++++++++++++++++++++++--------
 net/bluetooth/smp.c              | 36 ++++++++++++++++++++++++-----------
 net/bluetooth/smp.h              |  2 +-
 9 files changed, 100 insertions(+), 25 deletions(-)



^ permalink raw reply

* [PATCHv2] adapter: Handle MGMT_SETTING_LE change
From: Petri Gynther @ 2014-02-18 18:55 UTC (permalink / raw)
  To: linux-bluetooth

On dual-mode Bluetooth adapters, BLE is not enabled by default. When bluetoothd
starts, BLE is enabled in read_info_complete(), but this management action does
not always complete before adapter_start() is called. Therefore, bluetoothd
needs to handle the MGMT_SETTING_LE change correctly in settings_changed().
Specifically, trigger_passive_scanning() needs to be called so that paired BLE
devices (e.g. HoG devices) are able to reconnect back to host.

The trace below shows this case:
bluetoothd[1087]: src/adapter.c:adapter_start() adapter /org/bluez/hci0 has been enabled
 => adapter_start() is called, but BLE is not yet enabled
bluetoothd[1087]: src/adapter.c:load_link_keys_complete() link keys loaded for hci0
bluetoothd[1087]: src/adapter.c:load_ltks_complete() LTKs loaded for hci0
bluetoothd[1087]: src/adapter.c:get_connections_complete() Connection count: 0
bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000000c1
bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000040
bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002c1
bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000200
 => BLE got enabled, so need to call trigger_passive_scanning()
bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002d1
bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000010
bluetoothd[1087]: src/adapter.c:new_settings_callback() Settings: 0x000002d3
bluetoothd[1087]: src/adapter.c:settings_changed() Changed settings: 0x00000002

The issue is easily reproducible with this init sequence:
hciconfig hci0 up
bluetoothd -n -d
---
 src/adapter.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 08296bd..596e1eb 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -405,6 +405,7 @@ static void store_adapter_info(struct btd_adapter *adapter)
 static void trigger_pairable_timeout(struct btd_adapter *adapter);
 static void adapter_start(struct btd_adapter *adapter);
 static void adapter_stop(struct btd_adapter *adapter);
+static void trigger_passive_scanning(struct btd_adapter *adapter);
 
 static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 {
@@ -434,6 +435,12 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 		}
 	}
 
+	if (changed_mask & MGMT_SETTING_LE) {
+		if ((adapter->current_settings & MGMT_SETTING_POWERED) &&
+				(adapter->current_settings & MGMT_SETTING_LE))
+			trigger_passive_scanning(adapter);
+	}
+
 	if (changed_mask & MGMT_SETTING_CONNECTABLE)
 		g_dbus_emit_property_changed(dbus_conn, adapter->path,
 					ADAPTER_INTERFACE, "Connectable");
-- 
1.9.0.rc1.175.g0b1dcb5


^ permalink raw reply related

* Re: [PATCH v2 10/10] Bluetooth: Wait for SMP key distribution completion when pairing
From: Marcel Holtmann @ 2014-02-18 18:28 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1392738285-12143-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> When we initiate pairing through mgmt_pair_device the code has so far
> been waiting for a successful HCI Encrypt Change event in order to
> respond to the mgmt command. However, putting privacy into the play we
> actually want the key distribution to be complete before replying so
> that we can include the Identity Address in the mgmt response.
> 
> This patch updates the various hci_conn callbacks for LE in mgmt.c to
> only respond in the case of failure, and adds a new mgmt_smp_complete
> function that the SMP code will call once key distribution has been
> completed.
> 
> Since the smp_chan_destroy function that's used to indicate completion
> and clean up the SMP context can be called from various places,
> including outside of smp.c, the easiest way to track failure vs success
> is a new flag that we set once key distribution has been successfully
> completed.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> v2: Fix passing correct status value to pairing_complete()
> 
> include/net/bluetooth/hci_core.h |  1 +
> net/bluetooth/mgmt.c             | 27 +++++++++++++++++++++------
> net/bluetooth/smp.c              |  5 +++++
> net/bluetooth/smp.h              |  1 +
> 4 files changed, 28 insertions(+), 6 deletions(-)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 4461c0051228..64c4e3f0a515 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
> int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
> void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
> void mgmt_reenable_advertising(struct hci_dev *hdev);
> +void mgmt_smp_complete(struct hci_conn *conn, bool complete);
> 
> /* HCI info for socket */
> #define hci_pi(sk) ((struct hci_pinfo *) sk)
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 90aac905a98b..f9ae72ca556d 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -2655,6 +2655,18 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
> 	mgmt_pending_remove(cmd);
> }
> 
> +void mgmt_smp_complete(struct hci_conn *conn, bool complete)
> +{
> +	u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
> +	struct pending_cmd *cmd;
> +
> +	cmd = find_pairing(conn);
> +	if (!cmd)
> +		BT_DBG("Unable to find a pending command”);

why do we bother with the debug print here?

> +	else
> +		pairing_complete(cmd, status);

I would just do this:

	if (cmd)
		pairing_complete(cmd, status);

Unless you have future patches that do more work here.

> +}
> +
> static void pairing_complete_cb(struct hci_conn *conn, u8 status)
> {
> 	struct pending_cmd *cmd;
> @@ -2668,7 +2680,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
> 		pairing_complete(cmd, mgmt_status(status));
> }
> 
> -static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
> +static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
> {
> 	struct pending_cmd *cmd;
> 
> @@ -2755,13 +2767,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
> 	}
> 
> 	/* For LE, just connecting isn't a proof that the pairing finished */
> -	if (cp->addr.type == BDADDR_BREDR)
> +	if (cp->addr.type == BDADDR_BREDR) {
> 		conn->connect_cfm_cb = pairing_complete_cb;
> -	else
> -		conn->connect_cfm_cb = le_connect_complete_cb;
> +		conn->security_cfm_cb = pairing_complete_cb;
> +		conn->disconn_cfm_cb = pairing_complete_cb;
> +	} else {
> +		conn->connect_cfm_cb = le_pairing_complete_cb;
> +		conn->security_cfm_cb = le_pairing_complete_cb;
> +		conn->disconn_cfm_cb = le_pairing_complete_cb;
> +	}
> 
> -	conn->security_cfm_cb = pairing_complete_cb;
> -	conn->disconn_cfm_cb = pairing_complete_cb;
> 	conn->io_capability = cp->io_cap;
> 	cmd->user_data = conn;
> 
> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> index faf04bd4263a..9741623de6e7 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -551,9 +551,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
> void smp_chan_destroy(struct l2cap_conn *conn)
> {
> 	struct smp_chan *smp = conn->smp_chan;
> +	bool complete;
> 
> 	BUG_ON(!smp);
> 
> +	complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
> +	mgmt_smp_complete(conn->hcon, complete);
> +
> 	kfree(smp);
> 	conn->smp_chan = NULL;
> 	conn->hcon->smp_conn = NULL;
> @@ -1172,6 +1176,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
> 	if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) {
> 		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
> 		cancel_delayed_work_sync(&conn->security_timer);
> +		set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
> 		smp_chan_destroy(conn);
> 	}
> 
> diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
> index 8f54c9b152de..675fd3b21d2c 100644
> --- a/net/bluetooth/smp.h
> +++ b/net/bluetooth/smp.h
> @@ -118,6 +118,7 @@ struct smp_cmd_security_req {
> #define SMP_FLAG_TK_VALID	1
> #define SMP_FLAG_CFM_PENDING	2
> #define SMP_FLAG_MITM_AUTH	3
> +#define SMP_FLAG_COMPLETE	4
> 
> struct smp_chan {
> 	struct l2cap_conn *conn;

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 09/10] Bluetooth: Fix updating Identity Address in L2CAP channels
From: Marcel Holtmann @ 2014-02-18 18:25 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1392736479-8808-10-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> When we receive a remote identity address during SMP key distribution we
> should ensure that any associated L2CAP channel instances get their
> address information correspondingly updated (so that e.g. doing
> getpeername on associated sockets returns the correct address).
> 
> This patch adds a new L2CAP core function l2cap_conn_update_id_addr()
> which is used to iterate through all L2CAP channels associated with a
> connection and update their address information.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> include/net/bluetooth/l2cap.h |  1 +
> net/bluetooth/l2cap_core.c    | 17 +++++++++++++++++
> net/bluetooth/smp.c           |  2 ++
> 3 files changed, 20 insertions(+)
> 
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 13bec91785f4..4abdcb220e3a 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -881,6 +881,7 @@ int l2cap_ertm_init(struct l2cap_chan *chan);
> void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> void l2cap_chan_del(struct l2cap_chan *chan, int err);
> +void l2cap_conn_update_id_addr(struct hci_conn *hcon);
> void l2cap_send_conn_req(struct l2cap_chan *chan);
> void l2cap_move_start(struct l2cap_chan *chan);
> void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 6e6b3a9c8e6d..d25fefcc0bb5 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -609,6 +609,23 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
> 	return;
> }
> 
> +void l2cap_conn_update_id_addr(struct hci_conn *hcon)
> +{
> +	struct l2cap_conn *conn = hcon->l2cap_data;
> +	struct l2cap_chan *chan;
> +
> +	mutex_lock(&conn->chan_lock);
> +
> +	list_for_each_entry(chan, &conn->chan_l, list) {
> +		l2cap_chan_lock(chan);
> +		bacpy(&chan->dst, &hcon->dst);
> +		chan->dst_type = hcon->dst_type;

this should use bdaddr_type(conn->hcon, conn->hcon->dst_type);

Remember that the L2CAP address type matches the mgmt one. While on hci_dev and hci_conn level we have the one from HCI specification.

> +		l2cap_chan_unlock(chan);
> +	}
> +
> +	mutex_unlock(&conn->chan_lock);
> +}
> +
> static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
> {
> 	struct l2cap_conn *conn = chan->conn;
> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> index 4d14ccc7b330..faf04bd4263a 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -976,6 +976,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
> 	bacpy(&hcon->dst, &smp->id_addr);
> 	hcon->dst_type = smp->id_addr_type;
> 
> +	l2cap_conn_update_id_addr(hcon);
> +
> 	smp_distribute_keys(conn, 1);
> 
> 	return 0;

Regards

Marcel


^ permalink raw reply

* Re: [PATCH BlueZ v6 00/18] GATT API: External Services
From: Marcel Holtmann @ 2014-02-18 18:17 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: bluez mailin list (linux-bluetooth@vger.kernel.org)
In-Reply-To: <CAKT1EBdeyQDXbgu5iv3CC=XAE0j-dKVTOp8HMNuA7=xyK8ri0g@mail.gmail.com>

Hi Claudio,

>>> This patchset implements the minimal support for adding local services
>>> declarations.
>>> 
>>> Limitation: Remove services and multiple services exported by the same
>>> remote will be implemented the next series.
>> 
>> what is the deal with this unix socket you are using for local access? I think we should remove that functionality and keep it simple in the beginning.
> 
> Testing purpose only to avoid breaking the current attribute server.
> The fact is, the current attribute server "architecture" is not
> flexible enough to support external services properly.
> The idea is to get rid of the "old" attribute server when we finish
> the new implementation.
> 
> Lizardo has some patches allowing compatibility between the two
> versions. We will send new patchsets to remove the unix socket, and
> introduce this compatibility.

that sounds better. I rather not have an extra unix socket based API around. We are still having a heard time to get rid of the SDP unix socket.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH BlueZ v6 00/18] GATT API: External Services
From: Claudio Takahasi @ 2014-02-18 18:08 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: bluez mailin list (linux-bluetooth@vger.kernel.org)
In-Reply-To: <B6CE0C86-8DC9-45D1-8022-78ED9D83B96F@holtmann.org>

Hi Marcel,

On Tue, Feb 18, 2014 at 2:44 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Claudio,
>
>> This patchset implements the minimal support for adding local services
>> declarations.
>>
>> Limitation: Remove services and multiple services exported by the same
>> remote will be implemented the next series.
>
> what is the deal with this unix socket you are using for local access? I think we should remove that functionality and keep it simple in the beginning.
>
> Regards
>
> Marcel

Testing purpose only to avoid breaking the current attribute server.
The fact is, the current attribute server "architecture" is not
flexible enough to support external services properly.
The idea is to get rid of the "old" attribute server when we finish
the new implementation.

Lizardo has some patches allowing compatibility between the two
versions. We will send new patchsets to remove the unix socket, and
introduce this compatibility.

Regards,
Claudio

^ permalink raw reply

* [RFC v9 10/10] Bluetooth: Add le_auto_conn file on debugfs
From: Andre Guedes @ 2014-02-18 17:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392746101-5981-1-git-send-email-andre.guedes@openbossa.org>

This patch adds to debugfs the le_auto_conn file. This file will be
used to test LE auto connection infrastructure.

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

This file is created only if LE is enabled.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_core.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0adc642..04560fa 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -728,6 +728,89 @@ static const struct file_operations lowpan_debugfs_fops = {
 	.llseek		= default_llseek,
 };
 
+static int le_auto_conn_show(struct seq_file *sf, void *ptr)
+{
+	struct hci_dev *hdev = sf->private;
+	struct hci_conn_params *p;
+
+	hci_dev_lock(hdev);
+
+	list_for_each_entry(p, &hdev->le_conn_params, list) {
+		seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type,
+			   p->auto_connect);
+	}
+
+	hci_dev_unlock(hdev);
+
+	return 0;
+}
+
+static int le_auto_conn_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, le_auto_conn_show, inode->i_private);
+}
+
+static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
+				  size_t count, loff_t *offset)
+{
+	struct seq_file *sf = file->private_data;
+	struct hci_dev *hdev = sf->private;
+	u8 auto_connect;
+	bdaddr_t addr;
+	u8 addr_type;
+	char *buf;
+	int n;
+
+	/* Don't allow partial write */
+	if (*offset != 0)
+		return -EINVAL;
+
+	/* If empty string, clear the connection parameters and pending LE
+	 * connection list.
+	 */
+	if (count == 1) {
+		hci_dev_lock(hdev);
+		hci_conn_params_clear(hdev);
+		hci_pend_le_conns_clear(hdev);
+		hci_dev_unlock(hdev);
+		return count;
+	}
+
+	buf = kzalloc(count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, data, count)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+
+	n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", &addr.b[5],
+		   &addr.b[4], &addr.b[3], &addr.b[2], &addr.b[1], &addr.b[0],
+		   &addr_type, &auto_connect);
+	if (n != 8) {
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	hci_dev_lock(hdev);
+	hci_conn_params_add(hdev, &addr, addr_type, auto_connect,
+			    hdev->le_conn_min_interval,
+			    hdev->le_conn_max_interval);
+	hci_dev_unlock(hdev);
+
+	kfree(buf);
+	return count;
+}
+
+static const struct file_operations le_auto_conn_fops = {
+	.open		= le_auto_conn_open,
+	.read		= seq_read,
+	.write		= le_auto_conn_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* ---- HCI requests ---- */
 
 static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -1520,6 +1603,8 @@ static int __hci_init(struct hci_dev *hdev)
 				    hdev, &conn_max_interval_fops);
 		debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
 				    &lowpan_debugfs_fops);
+		debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
+				    &le_auto_conn_fops);
 	}
 
 	return 0;
-- 
1.8.5.4


^ permalink raw reply related

* [RFC v9 09/10] Bluetooth: Auto connection and power on
From: Andre Guedes @ 2014-02-18 17:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392746101-5981-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 d215148..0adc642 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2088,6 +2088,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 1d35362..f9f0f69 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4497,6 +4497,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 };
@@ -4505,6 +4516,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.5.4


^ permalink raw reply related

* Re: [PATCH 2/2] Bluetooth: append new supported device to the list [0b05:17d0]
From: Marcel Holtmann @ 2014-02-18 17:54 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: linux-bluetooth, Heikki Krogerus
In-Reply-To: <1392740780-27372-2-git-send-email-andriy.shevchenko@linux.intel.com>

Hi Andy,

> The device found on Asus Z87 Expert motherboard requires firmware to work
> correctly.
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#=  3 Spd=12  MxCh= 0
> D:  Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=0b05 ProdID=17d0 Rev=00.02
> C:  #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
> I:  If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> I:  If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/bluetooth/ath3k.c | 2 ++
> drivers/bluetooth/btusb.c | 1 +
> 2 files changed, 3 insertions(+)

patch has been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply

* [RFC v9 08/10] Bluetooth: Introduce LE auto connect options
From: Andre Guedes @ 2014-02-18 17:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392746101-5981-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces the LE auto connection options: HCI_AUTO_CONN_
ALWAYS and HCI_AUTO_CONN_LINK_LOSS. Their working mechanism are
described as follows:

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>
---
 include/net/bluetooth/hci_core.h |  9 ++++++++-
 net/bluetooth/hci_core.c         | 11 +++++++----
 net/bluetooth/hci_event.c        | 18 ++++++++++++++++++
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d1f7784..119b055 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -393,6 +393,12 @@ struct hci_conn_params {
 
 	u16 conn_min_interval;
 	u16 conn_max_interval;
+
+	enum {
+		HCI_AUTO_CONN_DISABLED,
+		HCI_AUTO_CONN_ALWAYS,
+		HCI_AUTO_CONN_LINK_LOSS,
+	} auto_connect;
 };
 
 extern struct list_head hci_dev_list;
@@ -778,7 +784,8 @@ 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,
-			 u16 conn_min_interval, u16 conn_max_interval);
+			 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);
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d53e031..d215148 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3033,7 +3033,8 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
 
 /* This function requires the caller holds hdev->lock */
 void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
-			 u16 conn_min_interval, u16 conn_max_interval)
+			 u8 auto_connect, u16 conn_min_interval,
+			 u16 conn_max_interval)
 {
 	struct hci_conn_params *params;
 
@@ -3041,6 +3042,7 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 	if (params) {
 		params->conn_min_interval = conn_min_interval;
 		params->conn_max_interval = conn_max_interval;
+		params->auto_connect = auto_connect;
 		return;
 	}
 
@@ -3054,12 +3056,13 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 	params->addr_type = addr_type;
 	params->conn_min_interval = conn_min_interval;
 	params->conn_max_interval = conn_max_interval;
+	params->auto_connect = auto_connect;
 
 	list_add(&params->list, &hdev->le_conn_params);
 
-	BT_DBG("addr %pMR (type %u) conn_min_interval 0x%.4x "
-	       "conn_max_interval 0x%.4x", addr, addr_type, conn_min_interval,
-	       conn_max_interval);
+	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 */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5796c06..ac3cdaf 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1825,6 +1825,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;
 
@@ -1851,6 +1852,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.5.4


^ permalink raw reply related

* [RFC v9 07/10] Bluetooth: Temporarily stop background scanning on discovery
From: Andre Guedes @ 2014-02-18 17:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392746101-5981-1-git-send-email-andre.guedes@openbossa.org>

If the user sends 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, 8 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 219a5aa..d53e031 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1612,6 +1612,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 25a0c46..1d35362 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3330,12 +3330,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
 			goto failed;
 		}
 
-		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;
-		}
+		/* 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))
+			hci_req_add_le_scan_disable(&req);
 
 		memset(&param_cp, 0, sizeof(param_cp));
 		param_cp.type = LE_SCAN_ACTIVE;
-- 
1.8.5.4


^ permalink raw reply related

* [RFC v9 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2014-02-18 17:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1392746101-5981-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces the LE auto connection infrastructure which
will be used to implement the LE auto connection options.

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). Finally,
we also call hci_update_background_scan() in hci_le_conn_failed() so
the background scan is restarted in case the connection establishment
fails. This way the background scanning keeps running until all pending
LE connection are established.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  2 +
 net/bluetooth/hci_conn.c         |  5 +++
 net/bluetooth/hci_core.c         | 83 +++++++++++++++++++++++++++++++++++++++-
 net/bluetooth/hci_event.c        | 44 +++++++++++++++++++++
 4 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f60b2a7..d1f7784 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -788,6 +788,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);
+
 void hci_uuids_clear(struct hci_dev *hdev);
 
 void hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index da44390..a4dd033 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -527,6 +527,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
 	hci_proto_connect_cfm(conn, status);
 
 	hci_conn_del(conn);
+
+	/* Since we may have temporarily stopped the background scanning in
+	 * favor of connection establishment, we should restart it.
+	 */
+	hci_update_background_scan(hdev);
 }
 
 static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0002c62..219a5aa 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3110,7 +3110,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) {
@@ -3124,6 +3124,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 */
@@ -3133,12 +3136,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 */
@@ -4702,3 +4708,76 @@ void hci_req_add_le_scan_disable(struct hci_request *req)
 	cp.enable = LE_SCAN_DISABLE;
 	hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 }
+
+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;
+
+		hci_req_add_le_scan_disable(&req);
+
+		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(&param_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),
+			    &param_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 df58cde..5796c06 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3620,25 +3620,69 @@ 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_DBG("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;
 
+		if (ev->evt_type == LE_ADV_IND ||
+		    ev->evt_type == LE_ADV_DIRECT_IND)
+			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.5.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox