Bluetooth: ATT: Add support EATT bearer

This adds support for EATT bearer which was introduced in 5.2, they work
as extra channels to have GATT traffic, at the moment it is completely
transparent to application when they are in use since the allocation
happens automatically.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2020-02-26 17:14:20 -08:00 committed by Johan Hedberg
commit f4192bda26
6 changed files with 978 additions and 440 deletions

View file

@ -872,6 +872,17 @@ struct bt_gatt_notify_params {
int bt_gatt_notify_cb(struct bt_conn *conn,
struct bt_gatt_notify_params *params);
/** @brief Notify multiple attribute value change.
*
* @param conn Connection object.
* @param num_params Number of notification parameters.
* @param params Notification parameters.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_gatt_notify_multiple(struct bt_conn *conn, u16_t num_params,
struct bt_gatt_notify_params *params);
/** @brief Notify attribute value change.
*
* Send notification of attribute value change, if connection is NULL notify

View file

@ -34,6 +34,49 @@ config BT_ATT_TX_MAX
amount the calls will block until an existing queued PDU gets
sent.
config BT_EATT
bool "Enhanced ATT Bearers support [EXPERIMENTAL]"
depends on BT_L2CAP_DYNAMIC_CHANNEL
help
This option enables support for Enhanced ATT bearers support. When
enabled additional L2CAP channels can be connected as bearers enabling
multiple outstanding request.
if BT_EATT
config BT_EATT_MAX
int "Maximum number of Enhanced ATT bearers"
default 3
range 1 16
help
Number of Enhanced ATT bearers available.
config BT_EATT_RX_MTU
int "Maximum supported Enhanced ATT MTU for incoming data"
default 70
range 70 519
depends on BT_EATT
help
Maximum size incoming PDUs on EATT bearers, value shall include L2CAP
headers and SDU length, maximum is limited to 512 bytes payload, which
is the maximum size for a GATT attribute, plus 1 byte for ATT opcode.
This option influences the stack buffer size and by that may also
limit the outgoing MTU.
config BT_EATT_SEC_LEVEL
int "Enhanced ATT bearer security level"
default 1
range 1 4
help
L2CAP server required security level of EATT bearers:
Level 1 (BT_SECURITY_L1) = No encryption or authentication required
Level 2 (BT_SECURITY_L2) = Only encryption required
Level 3 (BT_SECURITY_L3) = Encryption and authentication required
Level 4 (BT_SECURITY_L4) = Secure connection required
endif # BT_EATT
config BT_GATT_SERVICE_CHANGED
bool "GATT Service Changed support"
default y

View file

@ -8,8 +8,10 @@ menu "L2CAP Options"
config BT_L2CAP_RX_MTU
int "Maximum supported L2CAP MTU for incoming data"
default 200 if BT_BREDR
default BT_EATT_RX_MTU if BT_EATT
default 65 if BT_SMP
default 23
range 70 1300 if BT_EATT
range 65 1300 if BT_SMP
range 23 1300
depends on BT_HCI_ACL_FLOW_CONTROL

File diff suppressed because it is too large Load diff

View file

@ -298,3 +298,9 @@ int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req);
/* Cancel ATT request */
void bt_att_req_cancel(struct bt_conn *conn, struct bt_att_req *req);
/* Connect EATT channels */
int bt_eatt_connect(struct bt_conn *conn, u8_t num_channels);
/* Disconnect EATT channels */
int bt_eatt_disconnect(struct bt_conn *conn);

View file

@ -71,6 +71,7 @@ struct gatt_sub {
#endif /* CONFIG_BT_GATT_CLIENT */
static struct gatt_sub subscriptions[SUB_MAX];
static const u16_t gap_appearance = CONFIG_BT_DEVICE_APPEARANCE;
#if defined(CONFIG_BT_GATT_DYNAMIC_DB)
@ -401,7 +402,14 @@ enum {
CF_NUM_FLAGS,
};
#define CF_ROBUST_CACHING(_cfg) (_cfg->data[0] & BIT(0))
#define CF_BIT_ROBUST_CACHING 0
#define CF_BIT_EATT 1
#define CF_BIT_LAST CF_BIT_EATT
#define CF_BYTE_LAST (CF_BIT_LAST % 8)
#define CF_ROBUST_CACHING(_cfg) (_cfg->data[0] & BIT(CF_BIT_ROBUST_CACHING))
#define CF_EATT(_cfg) (_cfg->data[0] & BIT(CF_BIT_EATT))
struct gatt_cf_cfg {
u8_t id;
@ -463,15 +471,15 @@ static ssize_t cf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
static bool cf_set_value(struct gatt_cf_cfg *cfg, const u8_t *value, u16_t len)
{
u16_t i;
u8_t last_byte = 1U;
u8_t last_bit = 1U;
u8_t last_byte = CF_BYTE_LAST;
u8_t last_bit = CF_BIT_LAST;
/* Validate the bits */
for (i = 0U; i < len && i < last_byte; i++) {
for (i = 0U; i < len && i <= last_byte; i++) {
u8_t chg_bits = value[i] ^ cfg->data[i];
u8_t bit;
for (bit = 0U; bit < last_bit; bit++) {
for (bit = 0U; bit <= last_bit; bit++) {
/* A client shall never clear a bit it has set */
if ((BIT(bit) & chg_bits) &&
(BIT(bit) & cfg->data[i])) {
@ -716,6 +724,20 @@ static void remove_cf_cfg(struct bt_conn *conn)
atomic_clear_bit(cfg->flags, CF_OUT_OF_SYNC);
}
}
#if defined(CONFIG_BT_EATT)
#define SF_BIT_EATT 0
#define SF_BIT_LAST SF_BIT_EATT
static ssize_t sf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, u16_t len, u16_t offset)
{
u8_t value = BIT(SF_BIT_EATT);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &value,
sizeof(value));
}
#endif /* CONFIG_BT_EATT */
#endif /* CONFIG_BT_GATT_CACHING */
BT_GATT_SERVICE_DEFINE(_1_gatt_svc,
@ -737,6 +759,11 @@ BT_GATT_SERVICE_DEFINE(_1_gatt_svc,
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_DB_HASH,
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
db_hash_read, NULL, NULL),
#if defined(CONFIG_BT_EATT)
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_SERVER_FEATURES,
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
sf_read, NULL, NULL),
#endif /* CONFIG_BT_EATT */
#endif /* CONFIG_BT_GATT_CACHING */
#endif /* CONFIG_BT_GATT_SERVICE_CHANGED */
);
@ -3270,9 +3297,8 @@ static int gatt_read_uuid(struct bt_conn *conn,
}
#if defined(CONFIG_BT_GATT_READ_MULTIPLE)
static void gatt_read_multiple_rsp(struct bt_conn *conn, u8_t err,
const void *pdu, u16_t length,
void *user_data)
static void gatt_read_mult_rsp(struct bt_conn *conn, u8_t err, const void *pdu,
u16_t length, void *user_data)
{
struct bt_gatt_read_params *params = user_data;
@ -3289,8 +3315,8 @@ static void gatt_read_multiple_rsp(struct bt_conn *conn, u8_t err,
params->func(conn, 0, params, NULL, 0);
}
static int gatt_read_multiple(struct bt_conn *conn,
struct bt_gatt_read_params *params)
static int gatt_read_mult(struct bt_conn *conn,
struct bt_gatt_read_params *params)
{
struct net_buf *buf;
u8_t i;
@ -3305,10 +3331,10 @@ static int gatt_read_multiple(struct bt_conn *conn,
net_buf_add_le16(buf, params->handles[i]);
}
return gatt_send(conn, buf, gatt_read_multiple_rsp, params, NULL);
return gatt_send(conn, buf, gatt_read_mult_rsp, params, NULL);
}
#else
static int gatt_read_multiple(struct bt_conn *conn,
static int gatt_read_mult(struct bt_conn *conn,
struct bt_gatt_read_params *params)
{
return -ENOTSUP;
@ -3332,7 +3358,7 @@ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
}
if (params->handle_count > 1) {
return gatt_read_multiple(conn, params);
return gatt_read_mult(conn, params);
}
if (params->single.offset) {
@ -3369,6 +3395,7 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, u16_t handle,
{
struct net_buf *buf;
struct bt_att_write_cmd *cmd;
size_t write;
__ASSERT(conn, "invalid parameters\n");
__ASSERT(handle, "invalid parameters\n");
@ -3397,8 +3424,14 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, u16_t handle,
cmd = net_buf_add(buf, sizeof(*cmd));
cmd->handle = sys_cpu_to_le16(handle);
memcpy(cmd->value, data, length);
net_buf_add(buf, length);
write = net_buf_append_bytes(buf, length, data, K_NO_WAIT, NULL, NULL);
if (write != length) {
BT_WARN("Unable to allocate length %u: only %zu written",
length, write);
net_buf_unref(buf);
return -ENOMEM;
}
BT_DBG("handle 0x%04x length %u", handle, length);
@ -3455,6 +3488,7 @@ static int gatt_prepare_write(struct bt_conn *conn,
struct net_buf *buf;
struct bt_att_prepare_write_req *req;
u16_t len;
size_t write;
len = MIN(params->length, bt_att_get_mtu(conn) - sizeof(*req) - 1);
@ -3467,13 +3501,15 @@ static int gatt_prepare_write(struct bt_conn *conn,
req = net_buf_add(buf, sizeof(*req));
req->handle = sys_cpu_to_le16(params->handle);
req->offset = sys_cpu_to_le16(params->offset);
memcpy(req->value, params->data, len);
net_buf_add(buf, len);
/* Append as much as possible */
write = net_buf_append_bytes(buf, len, params->data, K_NO_WAIT,
NULL, NULL);
/* Update params */
params->offset += len;
params->offset += write;
params->data = (const u8_t *)params->data + len;
params->length -= len;
params->length -= write;
BT_DBG("handle 0x%04x offset %u len %u", params->handle, params->offset,
params->length);
@ -3485,6 +3521,7 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
{
struct net_buf *buf;
struct bt_att_write_req *req;
size_t write;
__ASSERT(conn, "invalid parameters\n");
__ASSERT(params && params->func, "invalid parameters\n");
@ -3508,8 +3545,13 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
req = net_buf_add(buf, sizeof(*req));
req->handle = sys_cpu_to_le16(params->handle);
memcpy(req->value, params->data, params->length);
net_buf_add(buf, params->length);
write = net_buf_append_bytes(buf, params->length, params->data,
K_NO_WAIT, NULL, NULL);
if (write != params->length) {
net_buf_unref(buf);
return -ENOMEM;
}
BT_DBG("handle 0x%04x length %u", params->handle, params->length);