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:
parent
6c82a63e8b
commit
4197aa814c
7 changed files with 632 additions and 418 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue