Bluetooth: Refactor fixed channel data

This refactorer fixed channel data so that the channel itself carries
any extra context necessary.

Change-Id: Iea0f29fb7913a29dccdcbef72d92ec4cf4711bf3
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2015-10-02 16:21:18 +03:00 committed by Anas Nashif
commit 4197aa814c
7 changed files with 632 additions and 418 deletions

View file

@ -72,9 +72,8 @@ struct bt_att_req {
/* ATT channel specific context */
struct bt_att {
/* The connection this context is associated with */
struct bt_conn *conn;
uint16_t mtu;
/* The channel this context is associated with */
struct bt_l2cap_chan chan;
struct bt_att_req req;
/* TODO: Allow more than one pending request */
};
@ -128,9 +127,9 @@ static void send_err_rsp(struct bt_conn *conn, uint8_t req, uint16_t handle,
bt_l2cap_send(conn, BT_L2CAP_CID_ATT, buf);
}
static uint8_t att_mtu_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_mtu_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att *att = conn->att;
struct bt_conn *conn = att->chan.conn;
struct bt_att_exchange_mtu_req *req;
struct bt_att_exchange_mtu_rsp *rsp;
struct bt_buf *pdu;
@ -164,16 +163,21 @@ static uint8_t att_mtu_req(struct bt_conn *conn, struct bt_buf *buf)
bt_l2cap_send(conn, BT_L2CAP_CID_ATT, pdu);
att->mtu = min(mtu_client, mtu_server);
/* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part F] page 484:
*
* A device's Exchange MTU Request shall contain the same MTU as the
* device's Exchange MTU Response (i.e. the MTU shall be symmetric).
*/
att->chan.rx.mtu = min(mtu_client, mtu_server);
att->chan.tx.mtu = att->chan.rx.mtu;
BT_DBG("Negotiated MTU %u\n", att->mtu);
BT_DBG("Negotiated MTU %u\n", att->chan.rx.mtu);
return 0;
}
static uint8_t att_handle_rsp(struct bt_conn *conn, void *pdu, uint16_t len,
static uint8_t att_handle_rsp(struct bt_att *att, void *pdu, uint16_t len,
uint8_t err)
{
struct bt_att *att = conn->att;
struct bt_att_req req;
if (!att->req.func) {
@ -184,16 +188,15 @@ static uint8_t att_handle_rsp(struct bt_conn *conn, void *pdu, uint16_t len,
memcpy(&req, &att->req, sizeof(req));
att->req.func = NULL;
req.func(conn, err, pdu, len, req.user_data);
req.func(att->chan.conn, err, pdu, len, req.user_data);
att_req_destroy(&req);
return 0;
}
static uint8_t att_mtu_rsp(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_mtu_rsp(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att *att = conn->att;
struct bt_att_exchange_mtu_rsp *rsp;
uint16_t mtu;
@ -209,19 +212,28 @@ static uint8_t att_mtu_rsp(struct bt_conn *conn, struct bt_buf *buf)
/* Check if MTU is valid */
if (mtu < BT_ATT_DEFAULT_LE_MTU) {
return att_handle_rsp(conn, NULL, 0, BT_ATT_ERR_INVALID_PDU);
return att_handle_rsp(att, NULL, 0, BT_ATT_ERR_INVALID_PDU);
}
/* Clip MTU based on the maximum amount of data bt_buf can hold
* excluding L2CAP, ACL and driver headers.
*/
att->mtu = min(mtu, BT_BUF_MAX_DATA - (sizeof(struct bt_l2cap_hdr) +
att->chan.rx.mtu = min(mtu, BT_BUF_MAX_DATA -
(sizeof(struct bt_l2cap_hdr) +
sizeof(struct bt_hci_acl_hdr) +
bt_dev.drv->head_reserve));
BT_DBG("Negotiated MTU %u\n", att->mtu);
return att_handle_rsp(conn, rsp, buf->len, 0);
/* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part F] page 484:
*
* A device's Exchange MTU Request shall contain the same MTU as the
* device's Exchange MTU Response (i.e. the MTU shall be symmetric).
*/
att->chan.tx.mtu = att->chan.rx.mtu;
BT_DBG("Negotiated MTU %u\n", att->chan.rx.mtu);
return att_handle_rsp(att, rsp, buf->len, 0);
}
static bool range_is_valid(uint16_t start, uint16_t end, uint16_t *err)
@ -246,7 +258,7 @@ static bool range_is_valid(uint16_t start, uint16_t end, uint16_t *err)
}
struct find_info_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_buf *buf;
struct bt_att_find_info_rsp *rsp;
union {
@ -258,7 +270,7 @@ struct find_info_data {
static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct find_info_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
BT_DBG("handle 0x%04x\n", attr->handle);
@ -280,8 +292,9 @@ static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
data->info16->handle = sys_cpu_to_le16(attr->handle);
data->info16->uuid = sys_cpu_to_le16(attr->uuid->u16);
return att->mtu - data->buf->len > sizeof(*data->info16) ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
if (att->chan.tx.mtu - data->buf->len > sizeof(*data->info16)) {
return BT_GATT_ITER_CONTINUE;
}
case BT_ATT_INFO_128:
if (attr->uuid->type != BT_UUID_128) {
return BT_GATT_ITER_STOP;
@ -293,16 +306,19 @@ static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
memcpy(data->info128->uuid, attr->uuid->u128,
sizeof(data->info128->uuid));
return att->mtu - data->buf->len > sizeof(*data->info128) ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
if (att->chan.tx.mtu - data->buf->len >
sizeof(*data->info128)) {
return BT_GATT_ITER_CONTINUE;
}
}
return BT_GATT_ITER_STOP;
}
static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
static uint8_t att_find_info_rsp(struct bt_att *att, uint16_t start_handle,
uint16_t end_handle)
{
struct bt_conn *conn = att->chan.conn;
struct find_info_data data;
memset(&data, 0, sizeof(data));
@ -312,7 +328,7 @@ static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
bt_gatt_foreach_attr(start_handle, end_handle, find_info_cb, &data);
if (!data.rsp) {
@ -328,8 +344,9 @@ static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
return 0;
}
static uint8_t att_find_info_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_find_info_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_find_info_req *req;
uint16_t start_handle, end_handle, err_handle;
@ -347,11 +364,11 @@ static uint8_t att_find_info_req(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
return att_find_info_rsp(conn, start_handle, end_handle);
return att_find_info_rsp(att, start_handle, end_handle);
}
struct find_type_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_buf *buf;
struct bt_att_handle_group *group;
const void *value;
@ -361,7 +378,8 @@ struct find_type_data {
static uint8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct find_type_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
uint8_t uuid[16];
@ -376,11 +394,11 @@ static uint8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data)
BT_DBG("handle 0x%04x\n", attr->handle);
/* stop if there is no space left */
if (att->mtu - data->buf->len < sizeof(*data->group))
if (att->chan.tx.mtu - data->buf->len < sizeof(*data->group))
return BT_GATT_ITER_STOP;
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, uuid, sizeof(uuid), 0);
read = attr->read(conn, attr, uuid, sizeof(uuid), 0);
if (read < 0) {
/* TODO: Return an error if this fails */
return BT_GATT_ITER_STOP;
@ -432,8 +450,9 @@ static uint8_t att_find_type_rsp(struct bt_conn *conn, uint16_t start_handle,
return 0;
}
static uint8_t att_find_type_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_find_type_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_find_type_req *req;
uint16_t start_handle, end_handle, err_handle, type;
uint8_t *value;
@ -490,7 +509,7 @@ static bool uuid_create(struct bt_uuid *uuid, struct bt_buf *buf)
}
struct read_type_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_uuid *uuid;
struct bt_buf *buf;
struct bt_att_read_type_rsp *rsp;
@ -500,7 +519,8 @@ struct read_type_data {
static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_type_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
/* Skip if doesn't match */
@ -515,8 +535,8 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
data->item->handle = sys_cpu_to_le16(attr->handle);
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, 0);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, 0);
if (read < 0) {
/* TODO: Handle read errors */
return BT_GATT_ITER_STOP;
@ -534,13 +554,14 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
bt_buf_add(data->buf, read);
/* return true only if there are still space for more items */
return att->mtu - data->buf->len > data->rsp->len ?
return att->chan.tx.mtu - data->buf->len > data->rsp->len ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
}
static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
static uint8_t att_read_type_rsp(struct bt_att *att, struct bt_uuid *uuid,
uint16_t start_handle, uint16_t end_handle)
{
struct bt_conn *conn = att->chan.conn;
struct read_type_data data;
memset(&data, 0, sizeof(data));
@ -551,7 +572,7 @@ static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
data.uuid = uuid;
data.rsp = bt_buf_add(data.buf, sizeof(*data.rsp));
data.rsp->len = 0;
@ -571,8 +592,9 @@ static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return 0;
}
static uint8_t att_read_type_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_type_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_read_type_req *req;
uint16_t start_handle, end_handle, err_handle;
struct bt_uuid uuid;
@ -602,7 +624,7 @@ static uint8_t att_read_type_req(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
return att_read_type_rsp(conn, &uuid, start_handle, end_handle);
return att_read_type_rsp(att, &uuid, start_handle, end_handle);
}
static uint8_t err_to_att(int err)
@ -654,7 +676,7 @@ static uint8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
}
struct read_data {
struct bt_conn *conn;
struct bt_att *att;
uint16_t offset;
struct bt_buf *buf;
struct bt_att_read_rsp *rsp;
@ -664,7 +686,8 @@ struct read_data {
static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
BT_DBG("handle 0x%04x\n", attr->handle);
@ -683,14 +706,14 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
}
/* Check attribute permissions */
data->err = check_perm(data->conn, attr, BT_GATT_PERM_READ_MASK);
data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
if (data->err) {
return BT_GATT_ITER_STOP;
}
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, data->offset);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, data->offset);
if (read < 0) {
data->err = err_to_att(read);
return BT_GATT_ITER_STOP;
@ -701,9 +724,10 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
return BT_GATT_ITER_CONTINUE;
}
static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
static uint8_t att_read_rsp(struct bt_att *att, uint8_t op, uint8_t rsp,
uint16_t handle, uint16_t offset)
{
struct bt_conn *conn = att->chan.conn;
struct read_data data;
if (!handle) {
@ -717,7 +741,7 @@ static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
data.offset = offset;
/* Pre-set error if no attr will be found in handle */
@ -738,7 +762,7 @@ static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
return 0;
}
static uint8_t att_read_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att_read_req *req;
uint16_t handle;
@ -749,11 +773,11 @@ static uint8_t att_read_req(struct bt_conn *conn, struct bt_buf *buf)
BT_DBG("handle 0x%04x\n", handle);
return att_read_rsp(conn, BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP,
return att_read_rsp(att, BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP,
handle, 0);
}
static uint8_t att_read_blob_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_blob_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att_read_blob_req *req;
uint16_t handle, offset;
@ -765,12 +789,13 @@ static uint8_t att_read_blob_req(struct bt_conn *conn, struct bt_buf *buf)
BT_DBG("handle 0x%04x offset %u\n", handle, offset);
return att_read_rsp(conn, BT_ATT_OP_READ_BLOB_REQ,
return att_read_rsp(att, BT_ATT_OP_READ_BLOB_REQ,
BT_ATT_OP_READ_BLOB_RSP, handle, offset);
}
static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_mult_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct read_data data;
uint16_t handle;
@ -781,7 +806,7 @@ static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
while (buf->len >= sizeof(uint16_t)) {
handle = bt_buf_pull_le16(buf);
@ -815,7 +840,7 @@ static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
}
struct read_group_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_uuid *uuid;
struct bt_buf *buf;
struct bt_att_read_group_rsp *rsp;
@ -825,7 +850,8 @@ struct read_group_data {
static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_group_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
/* If UUID don't match update group end_handle */
@ -839,7 +865,8 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
BT_DBG("handle 0x%04x\n", attr->handle);
/* Stop if there is no space left */
if (data->rsp->len && att->mtu - data->buf->len < data->rsp->len)
if (data->rsp->len &&
att->chan.tx.mtu - data->buf->len < data->rsp->len)
return BT_GATT_ITER_STOP;
/* Fast foward to next group position */
@ -850,8 +877,8 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
data->group->end_handle = sys_cpu_to_le16(attr->handle);
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, 0);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, 0);
if (read < 0) {
/* TODO: Handle read errors */
return BT_GATT_ITER_STOP;
@ -872,9 +899,10 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
return BT_GATT_ITER_CONTINUE;
}
static uint8_t att_read_group_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
uint16_t start_handle, uint16_t end_handle)
static uint8_t att_read_group_rsp(struct bt_att *att, struct bt_uuid *uuid,
uint16_t start_handle, uint16_t end_handle)
{
struct bt_conn *conn = att->chan.conn;
struct read_group_data data;
memset(&data, 0, sizeof(data));
@ -885,7 +913,7 @@ static uint8_t att_read_group_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
data.uuid = uuid;
data.rsp = bt_buf_add(data.buf, sizeof(*data.rsp));
data.rsp->len = 0;
@ -905,8 +933,9 @@ static uint8_t att_read_group_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return 0;
}
static uint8_t att_read_group_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_group_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_read_group_req *req;
uint16_t start_handle, end_handle, err_handle;
struct bt_uuid uuid;
@ -950,7 +979,7 @@ static uint8_t att_read_group_req(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
return att_read_group_rsp(conn, &uuid, start_handle, end_handle);
return att_read_group_rsp(att, &uuid, start_handle, end_handle);
}
struct write_data {
@ -1061,8 +1090,9 @@ static uint8_t att_write_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
return 0;
}
static uint8_t att_write_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_write_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_write_req *req;
uint16_t handle;
@ -1077,8 +1107,9 @@ static uint8_t att_write_req(struct bt_conn *conn, struct bt_buf *buf)
handle, 0, buf->data, buf->len);
}
static uint8_t att_prepare_write_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_prepare_write_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_prepare_write_req *req;
uint16_t handle, offset;
@ -1154,8 +1185,9 @@ static uint8_t att_exec_write_rsp(struct bt_conn *conn, uint8_t flags)
return 0;
}
static uint8_t att_exec_write_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_exec_write_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_exec_write_req *req;
req = (void *)buf->data;
@ -1165,8 +1197,9 @@ static uint8_t att_exec_write_req(struct bt_conn *conn, struct bt_buf *buf)
return att_exec_write_rsp(conn, req->flags);
}
static uint8_t att_write_cmd(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_write_cmd(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_write_cmd *req;
uint16_t handle;
@ -1184,8 +1217,9 @@ static uint8_t att_write_cmd(struct bt_conn *conn, struct bt_buf *buf)
return att_write_rsp(conn, 0, 0, handle, 0, buf->data, buf->len);
}
static uint8_t att_signed_write_cmd(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_signed_write_cmd(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_signed_write_cmd *req;
uint16_t handle;
int err;
@ -1236,9 +1270,8 @@ static int att_change_security(struct bt_conn *conn, uint8_t err)
}
#endif /* CONFIG_BLUETOOTH_SMP */
static uint8_t att_error_rsp(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_error_rsp(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att *att = conn->att;
struct bt_att_req *req = &att->req;
struct bt_att_error_rsp *rsp;
struct bt_att_hdr *hdr;
@ -1262,7 +1295,7 @@ static uint8_t att_error_rsp(struct bt_conn *conn, struct bt_buf *buf)
goto done;
/* Check if security needs to be changed */
if (!att_change_security(conn, err)) {
if (!att_change_security(att->chan.conn, err)) {
req->retrying = true;
/* Wait security_changed: TODO: Handle fail case */
return 0;
@ -1270,83 +1303,84 @@ static uint8_t att_error_rsp(struct bt_conn *conn, struct bt_buf *buf)
#endif /* CONFIG_BLUETOOTH_SMP */
done:
return att_handle_rsp(conn, NULL, 0, err);
return att_handle_rsp(att, NULL, 0, err);
}
static uint8_t att_handle_find_info_rsp(struct bt_conn *conn,
static uint8_t att_handle_find_info_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_find_type_rsp(struct bt_conn *conn,
static uint8_t att_handle_find_type_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_read_type_rsp(struct bt_conn *conn,
static uint8_t att_handle_read_type_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_read_rsp(struct bt_conn *conn,
static uint8_t att_handle_read_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_read_blob_rsp(struct bt_conn *conn,
static uint8_t att_handle_read_blob_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_read_mult_rsp(struct bt_conn *conn,
static uint8_t att_handle_read_mult_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_write_rsp(struct bt_conn *conn,
struct bt_buf *buf)
static uint8_t att_handle_write_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_prepare_write_rsp(struct bt_conn *conn,
static uint8_t att_handle_prepare_write_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_handle_exec_write_rsp(struct bt_conn *conn,
static uint8_t att_handle_exec_write_rsp(struct bt_att *att,
struct bt_buf *buf)
{
BT_DBG("\n");
return att_handle_rsp(conn, buf->data, buf->len, 0);
return att_handle_rsp(att, buf->data, buf->len, 0);
}
static uint8_t att_notify(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_notify(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
uint16_t handle;
handle = bt_buf_pull_le16(buf);
@ -1358,8 +1392,9 @@ static uint8_t att_notify(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
static uint8_t att_indicate(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_indicate(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
uint16_t handle;
handle = bt_buf_pull_le16(buf);
@ -1380,7 +1415,7 @@ static uint8_t att_indicate(struct bt_conn *conn, struct bt_buf *buf)
static const struct {
uint8_t op;
uint8_t (*func)(struct bt_conn *conn, struct bt_buf *buf);
uint8_t (*func)(struct bt_att *att, struct bt_buf *buf);
uint8_t expect_len;
} handlers[] = {
{ BT_ATT_OP_ERROR_RSP, att_error_rsp,
@ -1435,13 +1470,14 @@ static const struct {
sizeof(struct bt_att_write_cmd) + sizeof(struct bt_att_signature) },
};
static void bt_att_recv(struct bt_conn *conn, struct bt_buf *buf)
static void bt_att_recv(struct bt_l2cap_chan *chan, struct bt_buf *buf)
{
struct bt_att *att = CONTAINER_OF(chan, struct bt_att, chan);
struct bt_att_hdr *hdr = (void *)buf->data;
uint8_t err = BT_ATT_ERR_NOT_SUPPORTED;
size_t i;
BT_ASSERT(conn->att);
BT_ASSERT(att);
if (buf->len < sizeof(*hdr)) {
BT_ERR("Too small ATT PDU received\n");
@ -1464,7 +1500,7 @@ static void bt_att_recv(struct bt_conn *conn, struct bt_buf *buf)
break;
}
err = handlers[i].func(conn, buf);
err = handlers[i].func(att, buf);
break;
}
@ -1475,21 +1511,40 @@ static void bt_att_recv(struct bt_conn *conn, struct bt_buf *buf)
if (err) {
BT_DBG("ATT error 0x%02x", err);
send_err_rsp(conn, hdr->code, 0, err);
send_err_rsp(chan->conn, hdr->code, 0, err);
}
done:
bt_buf_put(buf);
}
static struct bt_att *att_chan_get(struct bt_conn *conn)
{
struct bt_l2cap_chan *chan;
chan = bt_l2cap_lookup_rx_cid(conn, BT_L2CAP_CID_ATT);
if (!chan) {
BT_ERR("Unable to find ATT channel");
return NULL;
}
return CONTAINER_OF(chan, struct bt_att, chan);
}
struct bt_buf *bt_att_create_pdu(struct bt_conn *conn, uint8_t op, size_t len)
{
struct bt_att_hdr *hdr;
struct bt_buf *buf;
struct bt_att *att = conn->att;
struct bt_att *att;
if (len + sizeof(op) > att->mtu) {
BT_WARN("ATT MTU exceeded, max %u, wanted %u\n", att->mtu, len);
att = att_chan_get(conn);
if (!att) {
return NULL;
}
if (len + sizeof(op) > att->chan.tx.mtu) {
BT_WARN("ATT MTU exceeded, max %u, wanted %u\n",
att->chan.tx.mtu, len);
return NULL;
}
@ -1504,48 +1559,33 @@ struct bt_buf *bt_att_create_pdu(struct bt_conn *conn, uint8_t op, size_t len)
return buf;
}
static void bt_att_connected(struct bt_conn *conn)
static void bt_att_connected(struct bt_l2cap_chan *chan)
{
int i;
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
BT_DBG("conn %p handle %u\n", conn, conn->handle);
chan->tx.mtu = BT_ATT_DEFAULT_LE_MTU;
chan->rx.mtu = BT_ATT_DEFAULT_LE_MTU;
for (i = 0; i < ARRAY_SIZE(bt_att_pool); i++) {
struct bt_att *att = &bt_att_pool[i];
if (!att->conn) {
att->conn = conn;
conn->att = att;
att->mtu = BT_ATT_DEFAULT_LE_MTU;
bt_gatt_connected(conn);
return;
}
}
BT_ERR("No available ATT context for conn %p\n", conn);
bt_gatt_connected(chan->conn);
}
static void bt_att_disconnected(struct bt_conn *conn)
static void bt_att_disconnected(struct bt_l2cap_chan *chan)
{
struct bt_att *att = conn->att;
struct bt_att *att = CONTAINER_OF(chan, struct bt_att, chan);
if (!att) {
return;
}
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
BT_DBG("conn %p handle %u\n", conn, conn->handle);
conn->att = NULL;
memset(att, 0, sizeof(*att));
bt_gatt_disconnected(conn);
bt_gatt_disconnected(chan->conn);
}
#if defined(CONFIG_BLUETOOTH_SMP)
static void security_changed(struct bt_conn *conn, bt_security_t level)
{
struct bt_att *att = conn->att;
struct bt_att *att;
struct bt_att_req *req;
att = att_chan_get(conn);
if (!att) {
return;
}
@ -1568,16 +1608,44 @@ static struct bt_conn_cb conn_callbacks = {
};
#endif /* CONFIG_BLUETOOTH_SMP */
void bt_att_init(void)
static int bt_att_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
static struct bt_l2cap_chan chan = {
.cid = BT_L2CAP_CID_ATT,
.recv = bt_att_recv,
.connected = bt_att_connected,
.disconnected = bt_att_disconnected,
int i;
static struct bt_l2cap_chan_ops ops = {
.connected = bt_att_connected,
.disconnected = bt_att_disconnected,
.recv = bt_att_recv,
};
bt_l2cap_chan_register(&chan);
BT_DBG("conn %p handle %u\n", conn, conn->handle);
for (i = 0; i < ARRAY_SIZE(bt_att_pool); i++) {
struct bt_att *att = &bt_att_pool[i];
if (att->chan.conn) {
continue;
}
att->chan.ops = &ops;
*chan = &att->chan;
return 0;
}
BT_ERR("No available ATT context for conn %p\n", conn);
return -ENOMEM;
}
void bt_att_init(void)
{
static struct bt_l2cap_fixed_chan chan = {
.cid = BT_L2CAP_CID_ATT,
.accept = bt_att_accept,
};
bt_l2cap_fixed_chan_register(&chan);
#if defined(CONFIG_BLUETOOTH_SMP)
bt_conn_cb_register(&conn_callbacks);
@ -1587,9 +1655,15 @@ void bt_att_init(void)
#if defined(CONFIG_BLUETOOTH_GATT_CLIENT)
uint16_t bt_att_get_mtu(struct bt_conn *conn)
{
struct bt_att *att = conn->att;
struct bt_att *att;
return att->mtu;
att = att_chan_get(conn);
if (!att) {
return 0;
}
/* tx and rx MTU shall be symmetric */
return att->chan.tx.mtu;
}
int bt_att_send(struct bt_conn *conn, struct bt_buf *buf, bt_att_func_t func,
@ -1602,7 +1676,7 @@ int bt_att_send(struct bt_conn *conn, struct bt_buf *buf, bt_att_func_t func,
return -EINVAL;
}
att = conn->att;
att = att_chan_get(conn);
if (!att) {
return -ENOTCONN;
}
@ -1646,7 +1720,7 @@ void bt_att_cancel(struct bt_conn *conn)
return;
}
att = conn->att;
att = att_chan_get(conn);
if (!att) {
return;
}