2019-02-20 10:14:53

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 1/5] Bluetooth: Expose supported LE states via debugfs

It may be useful for debugging purposes to quickly retrieve supported LE
stated bit mask for controller.

Signed-off-by: Andrzej Kaczmarek <[email protected]>
---
net/bluetooth/hci_debugfs.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
index 51f5b1efc3a5..c0b11ebacf7d 100644
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -679,6 +679,29 @@ static const struct file_operations force_static_address_fops = {
.llseek = default_llseek,
};

+static int le_states_show(struct seq_file *f, void *ptr)
+{
+ struct hci_dev *hdev = f->private;
+
+ hci_dev_lock(hdev);
+ seq_printf(f, "LE: %8ph\n", hdev->le_states);
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int le_states_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, le_states_show, inode->i_private);
+}
+
+static const struct file_operations le_states_fops = {
+ .open = le_states_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int white_list_show(struct seq_file *f, void *ptr)
{
struct hci_dev *hdev = f->private;
@@ -956,6 +979,8 @@ void hci_debugfs_create_le(struct hci_dev *hdev)
&random_address_fops);
debugfs_create_file("static_address", 0444, hdev->debugfs, hdev,
&static_address_fops);
+ debugfs_create_file("le_states", 0444, hdev->debugfs, hdev,
+ &le_states_fops);

/* For controllers with a public address, provide a debug
* option to force the usage of the configured static
--
2.20.1



2019-02-20 10:14:54

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 2/5] Bluetooth: Add le_state_supported helper macro

This allows for quickly checking if given LE states combination is
supported by controller. Combination is identified by bit number, as
defined in Core 5.0, Vol 2, Part E, 7.8.27.

Signed-off-by: Andrzej Kaczmarek <[email protected]>
---
include/net/bluetooth/hci_core.h | 4 ++++
net/bluetooth/hci_request.c | 14 +++++++-------
2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 094e61e07030..cdbab10fc4a6 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1207,6 +1207,10 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Extended advertising support */
#define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))

+/* LE supportes states and states combinations */
+#define le_state_supported(dev, bit) ((dev)->le_states[(bit) / 8] & \
+ (1 << ((bit) % 8)))
+
/* ----- HCI protocols ----- */
#define HCI_PROTO_DEFER 0x01

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index ca73d36cc149..71c138c56321 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1015,28 +1015,28 @@ static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
/* Check le_states if there is any connection in slave role. */
if (hdev->conn_hash.le_num_slave > 0) {
/* Slave connection state and non connectable mode bit 20. */
- if (!connectable && !(hdev->le_states[2] & 0x10))
+ if (!connectable && !le_state_supported(hdev, 20))
return false;

/* Slave connection state and connectable mode bit 38
* and scannable bit 21.
*/
- if (connectable && (!(hdev->le_states[4] & 0x40) ||
- !(hdev->le_states[2] & 0x20)))
+ if (connectable && (!le_state_supported(hdev, 21) ||
+ !le_state_supported(hdev, 38)))
return false;
}

/* Check le_states if there is any connection in master role. */
if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_slave) {
- /* Master connection state and non connectable mode bit 18. */
- if (!connectable && !(hdev->le_states[2] & 0x02))
+ /* Master connection state and non connectable mode bit 17. */
+ if (!connectable && !le_state_supported(hdev, 17))
return false;

/* Master connection state and connectable mode bit 35 and
* scannable 19.
*/
- if (connectable && (!(hdev->le_states[4] & 0x08) ||
- !(hdev->le_states[2] & 0x08)))
+ if (connectable && (!le_state_supported(hdev, 19) ||
+ !le_state_supported(hdev, 35)))
return false;
}

--
2.20.1


2019-02-20 10:14:54

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 3/5] Bluetooth: Allow new connection if already a slave

With this patch it is possible to initiate new connection when there are
already connections in slave role present. This requires support in the
controller so need to check LE supported stated bit mask.

Signed-off-by: Andrzej Kaczmarek <[email protected]>
---
net/bluetooth/hci_event.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 609fd6871c5a..d3ac83be0427 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5072,10 +5072,11 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type))
return NULL;

- /* Most controller will fail if we try to create new connections
- * while we have an existing one in slave role.
+ /* If we have existing connection in slave role, check if controller
+ * supports Initiating State and Connection State (Slave Role) states
+ * combination (bit #41 in states mask).
*/
- if (hdev->conn_hash.le_num_slave > 0)
+ if (hdev->conn_hash.le_num_slave > 0 && !(hdev->le_states[5] & 0x02))
return NULL;

/* If we're not connectable only connect devices that we have in
--
2.20.1


2019-02-20 10:14:56

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 4/5] Bluetooth: Fix set advertising while connected

__hci_req_enable_advertising() will check if advertising is allowed
while connected by checking states supported by controller so there is
no need to disallow this "by default" on all controller.

Signed-off-by: Andrzej Kaczmarek <[email protected]>
---
net/bluetooth/mgmt.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ccce954f8146..d44681c99341 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4334,7 +4334,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
if (!hdev_is_powered(hdev) ||
(val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
(cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
- hci_conn_num(hdev, LE_LINK) > 0 ||
(hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
hdev->le_scan_type == LE_SCAN_ACTIVE)) {
bool changed;
--
2.20.1


2019-02-20 10:14:58

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 5/5] Bluetooth: Fix set advertising while scanning

We can check states supported by controller to determine whether it is
allowed to advertise while scanning or not.

Signed-off-by: Andrzej Kaczmarek <[email protected]>
---
net/bluetooth/hci_request.c | 24 +++++++++++++++++++++---
net/bluetooth/mgmt.c | 4 +---
2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 71c138c56321..5498afec03fb 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1008,9 +1008,27 @@ static bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)

static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
{
- /* If there is no connection we are OK to advertise. */
- if (hci_conn_num(hdev, LE_LINK) == 0)
- return true;
+ /* Check le_states if there is active scanning ongoing */
+ if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
+ hdev->le_scan_type == LE_SCAN_ACTIVE) {
+ if (!connectable && !le_state_supported(hdev, 12))
+ return false;
+
+ if (connectable && (!le_state_supported(hdev, 13) ||
+ !le_state_supported(hdev, 14)))
+ return false;
+ }
+
+ /* Check le_states if there is passive scanning ongoing */
+ if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
+ hdev->le_scan_type == LE_SCAN_PASSIVE) {
+ if (!connectable && !le_state_supported(hdev, 8))
+ return false;
+
+ if (connectable && (!le_state_supported(hdev, 9) ||
+ !le_state_supported(hdev, 10)))
+ return false;
+ }

/* Check le_states if there is any connection in slave role. */
if (hdev->conn_hash.le_num_slave > 0) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d44681c99341..3072c104888e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4333,9 +4333,7 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
*/
if (!hdev_is_powered(hdev) ||
(val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
- (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
- (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
- hdev->le_scan_type == LE_SCAN_ACTIVE)) {
+ (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))) {
bool changed;

if (cp->val) {
--
2.20.1


2019-02-26 09:06:09

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 1/5] Bluetooth: Expose supported LE states via debugfs

Hi Andrzej,

> It may be useful for debugging purposes to quickly retrieve supported LE
> stated bit mask for controller.
>
> Signed-off-by: Andrzej Kaczmarek <[email protected]>
> ---
> net/bluetooth/hci_debugfs.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
> index 51f5b1efc3a5..c0b11ebacf7d 100644
> --- a/net/bluetooth/hci_debugfs.c
> +++ b/net/bluetooth/hci_debugfs.c
> @@ -679,6 +679,29 @@ static const struct file_operations force_static_address_fops = {
> .llseek = default_llseek,
> };
>
> +static int le_states_show(struct seq_file *f, void *ptr)
> +{
> + struct hci_dev *hdev = f->private;
> +
> + hci_dev_lock(hdev);
> + seq_printf(f, "LE: %8ph\n", hdev->le_states);
> + hci_dev_unlock(hdev);
> +
> + return 0;
> +}
> +
> +static int le_states_open(struct inode *inode, struct file *file)
> +{
> + return single_open(file, le_states_show, inode->i_private);
> +}
> +
> +static const struct file_operations le_states_fops = {
> + .open = le_states_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
> static int white_list_show(struct seq_file *f, void *ptr)
> {
> struct hci_dev *hdev = f->private;
> @@ -956,6 +979,8 @@ void hci_debugfs_create_le(struct hci_dev *hdev)
> &random_address_fops);
> debugfs_create_file("static_address", 0444, hdev->debugfs, hdev,
> &static_address_fops);
> + debugfs_create_file("le_states", 0444, hdev->debugfs, hdev,
> + &le_states_fops);

we have not used le_ prefixed files yet and so maybe better use supported_states here.

Regards

Marcel