2017-02-15 18:18:20

by Felipe Ferreri Tonello

[permalink] [raw]
Subject: [PATCH BlueZ 0/4] Improvements on connection parameters update

This is one of the parts of a series of patches related to connection
parameters update.

This initial implementation adds supports to GAP Peripheral Preferred
Connection Parameters (PPCP) characteristic

There is a problem described in #4 that due to a limitation of the BlueZ API
it is not possible to update the current connection with specific parameters.
I am working on a socket option API to allow something similar. Hopefully I
will be able to write something that covers this use-case as well.

Next step is to support connection parameters via the advertising data (AD).
On that case, hopefully it is possible to set this parameters before the
connection is actually established.

Felipe F. Tonello (4):
profiles/gap: Some code cleanup
src/adapter: Added connection parameter load/store functions
src/device: Added function to set connection parameters
profiles/gap: Added support for PPCP characteristic

profiles/gap/gas.c | 104 ++++++++++++++++++++++++++++++++++++++++++-----------
src/adapter.c | 24 +++++++++++--
src/adapter.h | 9 +++++
src/device.c | 16 +++++++++
src/device.h | 4 +++
5 files changed, 134 insertions(+), 23 deletions(-)

--
2.11.1



2017-02-15 18:18:24

by Felipe Ferreri Tonello

[permalink] [raw]
Subject: [PATCH BlueZ 4/4] profiles/gap: Added support for PPCP characteristic

The Peripheral Preferred Connection Parameters (PPCP) characteristic
contains the preferred connection parameters of a peripheral device.

These parameters are stored in the info file and loaded to Kernel using
MGMT's respective command.

IMPORTANT: The connection will only be updated upon next reconnection to
the peripheral device. This is a limitation of the current BlueZ API
that doesn't allow change specific parameters of current connection.
---
profiles/gap/gas.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)

diff --git a/profiles/gap/gas.c b/profiles/gap/gas.c
index 0d34503ad446..6de69f008767 100644
--- a/profiles/gap/gas.c
+++ b/profiles/gap/gas.c
@@ -162,6 +162,68 @@ static void handle_appearance(struct gas *gas, uint16_t value_handle)
DBG("Failed to send request to read appearance");
}

+static void read_ppcp_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
+{
+ struct gas *gas = user_data;
+ uint16_t min_interval, max_interval, latency, timeout, max_latency;
+
+ if (!success) {
+ DBG("Reading PPCP failed with ATT error: %u", att_ecode);
+ return;
+ }
+
+ if (length != 8) {
+ DBG("Malformed PPCP value");
+ return;
+ }
+
+ min_interval = get_le16(&value[0]);
+ max_interval = get_le16(&value[2]);
+ latency = get_le16(&value[4]);
+ timeout = get_le16(&value[6]);
+
+ DBG("GAP Peripheral Preferred Connection Parameters:");
+ DBG("\tMinimum connection interval: %u", min_interval);
+ DBG("\tMaximum connection interval: %u", max_interval);
+ DBG("\tSlave latency: %u", latency);
+ DBG("\tConnection Supervision timeout multiplier: %u", timeout);
+
+ /* avoid persisting connection parameters that are not valid */
+ if (min_interval > max_interval ||
+ min_interval < 6 || max_interval > 3200) {
+ warn("GAS PPCP: Invalid Connection Parameters values");
+ return;
+ }
+
+ if (timeout < 10 || timeout > 3200) {
+ warn("GAS PPCP: Invalid Connection Parameters values");
+ return;
+ }
+
+ if (max_interval >= timeout * 8) {
+ warn("GAS PPCP: Invalid Connection Parameters values");
+ return;
+ }
+
+ max_latency = (timeout * 4 / max_interval) - 1;
+ if (latency > 499 || latency > max_latency) {
+ warn("GAS PPCP: Invalid Connection Parameters values");
+ return;
+ }
+
+ btd_device_set_conn_param(gas->device, min_interval, max_interval,
+ latency, timeout);
+}
+
+static void handle_ppcp(struct gas *gas, uint16_t value_handle)
+{
+ if (!bt_gatt_client_read_value(gas->client, value_handle,
+ read_ppcp_cb, gas, NULL))
+ DBG("Failed to send request to read PPCP");
+}
+
static inline bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid)
{
bt_uuid_t lhs;
@@ -188,6 +250,8 @@ static void handle_characteristic(struct gatt_db_attribute *attr,
handle_device_name(gas, value_handle);
else if (uuid_cmp(GATT_CHARAC_APPEARANCE, &uuid))
handle_appearance(gas, value_handle);
+ else if (uuid_cmp(GATT_CHARAC_PERIPHERAL_PREF_CONN, &uuid))
+ handle_ppcp(gas, value_handle);
else {
char uuid_str[MAX_LEN_UUID_STR];

--
2.11.1


2017-02-15 18:18:21

by Felipe Ferreri Tonello

[permalink] [raw]
Subject: [PATCH BlueZ 1/4] profiles/gap: Some code cleanup

Just removing unecessary function and code duplication.
---
profiles/gap/gas.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/profiles/gap/gas.c b/profiles/gap/gas.c
index 43b7c3d0ef07..0d34503ad446 100644
--- a/profiles/gap/gas.c
+++ b/profiles/gap/gas.c
@@ -57,10 +57,18 @@ struct gas {
struct gatt_db_attribute *attr;
};

-static void gas_free(struct gas *gas)
+static void gas_reset(struct gas *gas)
{
+ gas->attr = NULL;
gatt_db_unref(gas->db);
+ gas->db = NULL;
bt_gatt_client_unref(gas->client);
+ gas->client = NULL;
+}
+
+static void gas_free(struct gas *gas)
+{
+ gas_reset(gas);
btd_device_unref(gas->device);
g_free(gas);
}
@@ -154,7 +162,7 @@ static void handle_appearance(struct gas *gas, uint16_t value_handle)
DBG("Failed to send request to read appearance");
}

-static bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid)
+static inline bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid)
{
bt_uuid_t lhs;

@@ -190,11 +198,6 @@ static void handle_characteristic(struct gatt_db_attribute *attr,
}
}

-static void handle_gap_service(struct gas *gas)
-{
- gatt_db_service_foreach_char(gas->attr, handle_characteristic, gas);
-}
-
static int gap_probe(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
@@ -248,16 +251,7 @@ static void foreach_gap_service(struct gatt_db_attribute *attr, void *user_data)
}

gas->attr = attr;
- handle_gap_service(gas);
-}
-
-static void gas_reset(struct gas *gas)
-{
- gas->attr = NULL;
- gatt_db_unref(gas->db);
- gas->db = NULL;
- bt_gatt_client_unref(gas->client);
- gas->client = NULL;
+ gatt_db_service_foreach_char(gas->attr, handle_characteristic, gas);
}

static int gap_accept(struct btd_service *service)
@@ -268,13 +262,15 @@ static int gap_accept(struct btd_service *service)
struct gas *gas = btd_service_get_user_data(service);
char addr[18];
bt_uuid_t gap_uuid;
+ int err = 0;

ba2str(device_get_address(device), addr);
DBG("GAP profile accept (%s)", addr);

if (!gas) {
error("GAP service not handled by profile");
- return -1;
+ err = -1;
+ goto _finish;
}

gas->db = gatt_db_ref(db);
@@ -287,12 +283,14 @@ static int gap_accept(struct btd_service *service)
if (!gas->attr) {
error("GAP attribute not found");
gas_reset(gas);
- return -1;
+ err = -1;
}

- btd_service_connecting_complete(service, 0);
+_finish:

- return 0;
+ btd_service_connecting_complete(service, err);
+
+ return err;
}

static int gap_disconnect(struct btd_service *service)
--
2.11.1


2017-02-15 18:18:23

by Felipe Ferreri Tonello

[permalink] [raw]
Subject: [PATCH BlueZ 3/4] src/device: Added function to set connection parameters

This function allows plugins to set the connection parameters of the
respective btd_device object.

It is useful for GAP Peripheral Preferred Connection Parameters
characteristic for example.
---
src/device.c | 16 ++++++++++++++++
src/device.h | 4 ++++
2 files changed, 20 insertions(+)

diff --git a/src/device.c b/src/device.c
index 8693eb826b54..080bd16153f4 100644
--- a/src/device.c
+++ b/src/device.c
@@ -6122,3 +6122,19 @@ void btd_device_cleanup(void)
{
btd_service_remove_state_cb(service_state_cb_id);
}
+
+void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval,
+ uint16_t max_interval, uint16_t latency,
+ uint16_t timeout)
+{
+ btd_assert(device != NULL);
+
+ adapter_store_conn_param(device->adapter, &device->bdaddr,
+ device->bdaddr_type, min_interval,
+ max_interval, latency,
+ timeout);
+ adapter_load_conn_params(device->adapter, &device->bdaddr,
+ device->bdaddr_type, min_interval,
+ max_interval, latency,
+ timeout);
+}
diff --git a/src/device.h b/src/device.h
index 3cab366eeaea..88076d2d196d 100644
--- a/src/device.h
+++ b/src/device.h
@@ -163,3 +163,7 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services);

void btd_device_init(void);
void btd_device_cleanup(void);
+
+void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval,
+ uint16_t max_interval, uint16_t latency,
+ uint16_t timeout);
--
2.11.1


2017-02-15 18:18:22

by Felipe Ferreri Tonello

[permalink] [raw]
Subject: [PATCH BlueZ 2/4] src/adapter: Added connection parameter load/store functions

It is interesting to let other parts of bluetoothd to access these
functions since there are few different use-cases where this updating
and loading connection parameters can happen.
---
src/adapter.c | 24 ++++++++++++++++++++++--
src/adapter.h | 9 +++++++++
2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 3dac7d6490d6..be22c6b1b046 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3609,6 +3609,26 @@ static void load_conn_params(struct btd_adapter *adapter, GSList *params)
btd_error(adapter->dev_id, "Load connection parameters failed");
}

+void adapter_load_conn_params(struct btd_adapter *adapter, const bdaddr_t *peer,
+ uint8_t bdaddr_type, uint16_t min_interval,
+ uint16_t max_interval, uint16_t latency,
+ uint16_t timeout)
+{
+ GSList *params = NULL;
+ struct conn_param param;
+
+ bacpy(&param.bdaddr, peer);
+ param.bdaddr_type = bdaddr_type;
+ param.max_interval = max_interval;
+ param.min_interval = min_interval;
+ param.latency = latency;
+ param.timeout = timeout;
+
+ params = g_slist_append(params, &param);
+ load_conn_params(adapter, params);
+ g_slist_free(params);
+}
+
static uint8_t get_le_addr_type(GKeyFile *keyfile)
{
uint8_t addr_type;
@@ -7251,7 +7271,7 @@ static void new_irk_callback(uint16_t index, uint16_t length,
btd_device_set_temporary(device, false);
}

-static void store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer,
+void adapter_store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer,
uint8_t bdaddr_type, uint16_t min_interval,
uint16_t max_interval, uint16_t latency,
uint16_t timeout)
@@ -7325,7 +7345,7 @@ static void new_conn_param(uint16_t index, uint16_t length,
if (!ev->store_hint)
return;

- store_conn_param(adapter, &ev->addr.bdaddr, ev->addr.type,
+ adapter_store_conn_param(adapter, &ev->addr.bdaddr, ev->addr.type,
ev->min_interval, ev->max_interval,
ev->latency, ev->timeout);
}
diff --git a/src/adapter.h b/src/adapter.h
index f9178d59e74a..a7cb87213635 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -227,3 +227,12 @@ void btd_adapter_for_each_device(struct btd_adapter *adapter,

bool btd_le_connect_before_pairing(void);

+void adapter_load_conn_params(struct btd_adapter *adapter, const bdaddr_t *peer,
+ uint8_t bdaddr_type, uint16_t min_interval,
+ uint16_t max_interval, uint16_t latency,
+ uint16_t timeout);
+
+void adapter_store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer,
+ uint8_t bdaddr_type, uint16_t min_interval,
+ uint16_t max_interval, uint16_t latency,
+ uint16_t timeout);
--
2.11.1