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,
|
||||
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,
|
||||
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_gatt_connected(chan->conn);
|
||||
}
|
||||
|
||||
BT_ERR("No available ATT context for conn %p\n", 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,
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ typedef enum {
|
|||
BT_CONN_DISCONNECT,
|
||||
} bt_conn_state_t;
|
||||
|
||||
/* L2CAP signaling channel specific context */
|
||||
struct bt_conn_l2cap {
|
||||
uint8_t ident;
|
||||
void *channels;
|
||||
};
|
||||
|
||||
/* bt_conn flags: the flags defined here represent connection parameters */
|
||||
enum {
|
||||
BT_CONN_AUTO_CONNECT,
|
||||
|
@ -63,10 +57,8 @@ struct bt_conn {
|
|||
|
||||
struct bt_keys *keys;
|
||||
|
||||
/* Fixed channel contexts */
|
||||
struct bt_conn_l2cap l2cap;
|
||||
void *att;
|
||||
void *smp;
|
||||
/* L2CAP channels */
|
||||
void *channels;
|
||||
|
||||
uint8_t le_conn_interval;
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@
|
|||
|
||||
#include "hci_core.h"
|
||||
#include "keys.h"
|
||||
#if defined(CONFIG_BLUETOOTH_CONN)
|
||||
#include "conn_internal.h"
|
||||
#include "l2cap_internal.h"
|
||||
#endif /* CONFIG_BLUETOOTH_CONN */
|
||||
#include "stack.h"
|
||||
|
||||
#if !defined(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
|
||||
|
|
|
@ -47,22 +47,53 @@
|
|||
#define L2CAP_CID_START 0x0040
|
||||
#define L2CAP_LE_CID_END 0x007f
|
||||
|
||||
static struct bt_l2cap_chan *channels;
|
||||
static struct bt_l2cap_fixed_chan *channels;
|
||||
static struct bt_l2cap_server *servers;
|
||||
|
||||
/* L2CAP signalling channel specific context */
|
||||
struct bt_l2cap {
|
||||
/* The channel this context is associated with */
|
||||
struct bt_l2cap_chan chan;
|
||||
|
||||
uint8_t ident;
|
||||
};
|
||||
|
||||
static struct bt_l2cap bt_l2cap_pool[CONFIG_BLUETOOTH_MAX_CONN];
|
||||
|
||||
static struct bt_l2cap *l2cap_chan_get(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
chan = bt_l2cap_lookup_rx_cid(conn, BT_L2CAP_CID_LE_SIG);
|
||||
if (!chan) {
|
||||
BT_ERR("Unable to find L2CAP Signalling channel");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CONTAINER_OF(chan, struct bt_l2cap, chan);
|
||||
}
|
||||
|
||||
static uint8_t get_ident(struct bt_conn *conn)
|
||||
{
|
||||
conn->l2cap.ident++;
|
||||
|
||||
struct bt_l2cap *l2cap;
|
||||
|
||||
l2cap = l2cap_chan_get(conn);
|
||||
if (!l2cap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
l2cap->ident++;
|
||||
|
||||
/* handle integer overflow (0 is not valid) */
|
||||
if (!conn->l2cap.ident) {
|
||||
conn->l2cap.ident++;
|
||||
if (!l2cap->ident) {
|
||||
l2cap->ident++;
|
||||
}
|
||||
|
||||
return conn->l2cap.ident;
|
||||
return l2cap->ident;
|
||||
}
|
||||
|
||||
void bt_l2cap_chan_register(struct bt_l2cap_chan *chan)
|
||||
void bt_l2cap_fixed_chan_register(struct bt_l2cap_fixed_chan *chan)
|
||||
{
|
||||
BT_DBG("CID 0x%04x\n", chan->cid);
|
||||
|
||||
|
@ -103,13 +134,58 @@ int bt_l2cap_server_register(struct bt_l2cap_server *server)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void l2cap_chan_alloc_cid(struct bt_conn *conn,
|
||||
struct bt_l2cap_chan *chan)
|
||||
{
|
||||
uint16_t cid;
|
||||
|
||||
if (chan->rx.cid > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try matching dcid first */
|
||||
if (!bt_l2cap_lookup_rx_cid(conn, chan->rx.cid)) {
|
||||
chan->rx.cid = chan->tx.cid;
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Check conn type before assigning cid */
|
||||
for (cid = L2CAP_CID_START; cid < L2CAP_LE_CID_END; cid++) {
|
||||
if (!bt_l2cap_lookup_rx_cid(conn, cid)) {
|
||||
chan->rx.cid = cid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan)
|
||||
{
|
||||
l2cap_chan_alloc_cid(conn, chan);
|
||||
|
||||
/* Attach channel to the connection */
|
||||
chan->_next = conn->channels;
|
||||
conn->channels = chan;
|
||||
chan->conn = conn;
|
||||
|
||||
BT_DBG("conn %p chan %p cid 0x%04x\n", conn, chan, chan->rx.cid);
|
||||
}
|
||||
|
||||
void bt_l2cap_connected(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_l2cap_fixed_chan *fchan;
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = channels; chan; chan = chan->_next) {
|
||||
if (chan->connected) {
|
||||
chan->connected(conn);
|
||||
for (fchan = channels; fchan; fchan = fchan->_next) {
|
||||
if (fchan->accept(conn, &chan) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
chan->rx.cid = fchan->cid;
|
||||
|
||||
l2cap_chan_add(conn, chan);
|
||||
|
||||
if (chan->ops->connected) {
|
||||
chan->ops->connected(chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,32 +194,30 @@ void bt_l2cap_disconnected(struct bt_conn *conn)
|
|||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = channels; chan; chan = chan->_next) {
|
||||
if (chan->disconnected) {
|
||||
chan->disconnected(conn);
|
||||
}
|
||||
for (chan = conn->channels; chan;) {
|
||||
struct bt_l2cap_chan *next;
|
||||
|
||||
/* prefetch since disconnected callback may cleanup */
|
||||
next = chan->_next;
|
||||
|
||||
if (chan->ops->disconnected) {
|
||||
chan->ops->disconnected(chan);
|
||||
}
|
||||
|
||||
for (chan = conn->l2cap.channels; chan; chan = chan->_next) {
|
||||
if (chan->disconnected) {
|
||||
chan->disconnected(conn);
|
||||
}
|
||||
chan->conn = NULL;
|
||||
chan = next;
|
||||
}
|
||||
|
||||
conn->channels = NULL;
|
||||
}
|
||||
|
||||
void bt_l2cap_encrypt_change(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = channels; chan; chan = chan->_next) {
|
||||
if (chan->encrypt_change) {
|
||||
chan->encrypt_change(conn);
|
||||
}
|
||||
}
|
||||
|
||||
for (chan = conn->l2cap.channels; chan; chan = chan->_next) {
|
||||
if (chan->encrypt_change) {
|
||||
chan->encrypt_change(conn);
|
||||
for (chan = conn->channels; chan; chan = chan->_next) {
|
||||
if (chan->ops->encrypt_change) {
|
||||
chan->ops->encrypt_change(chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +264,7 @@ static void rej_not_understood(struct bt_conn *conn, uint8_t ident)
|
|||
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||
}
|
||||
|
||||
static void le_conn_param_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static void le_conn_param_rsp(struct bt_l2cap *l2cap, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_l2cap_conn_param_rsp *rsp = (void *)buf->data;
|
||||
|
||||
|
@ -203,9 +277,10 @@ static void le_conn_param_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
static void le_conn_param_update_req(struct bt_conn *conn, uint8_t ident,
|
||||
static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||
struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = l2cap->chan.conn;
|
||||
uint16_t min, max, latency, timeout;
|
||||
bool params_valid;
|
||||
struct bt_l2cap_sig_hdr *hdr;
|
||||
|
@ -230,7 +305,7 @@ static void le_conn_param_update_req(struct bt_conn *conn, uint8_t ident,
|
|||
BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x timeout: 0x%4.4x",
|
||||
min, max, latency, timeout);
|
||||
|
||||
buf = bt_l2cap_create_pdu(conn);
|
||||
buf = bt_l2cap_create_pdu(l2cap->chan.conn);
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
@ -249,7 +324,7 @@ static void le_conn_param_update_req(struct bt_conn *conn, uint8_t ident,
|
|||
rsp->result = sys_cpu_to_le16(BT_L2CAP_CONN_PARAM_REJECTED);
|
||||
}
|
||||
|
||||
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||
bt_l2cap_send(l2cap->chan.conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||
|
||||
if (params_valid) {
|
||||
bt_conn_le_conn_update(conn, min, max, latency, timeout);
|
||||
|
@ -257,76 +332,16 @@ static void le_conn_param_update_req(struct bt_conn *conn, uint8_t ident,
|
|||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
static struct bt_l2cap_chan *l2cap_chan_lookup_dcid(struct bt_conn *conn,
|
||||
uint16_t dcid)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = conn->l2cap.channels; chan; chan = chan->_next) {
|
||||
if (chan->dcid == dcid)
|
||||
return chan;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct bt_l2cap_chan *l2cap_chan_lookup_scid(struct bt_conn *conn,
|
||||
uint16_t scid)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = conn->l2cap.channels; chan; chan = chan->_next) {
|
||||
if (chan->cid == scid) {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void l2cap_chan_alloc_cid(struct bt_conn *conn,
|
||||
struct bt_l2cap_chan *chan)
|
||||
{
|
||||
uint16_t cid;
|
||||
|
||||
if (chan->cid > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try matching dcid first */
|
||||
if (!l2cap_chan_lookup_scid(conn, chan->dcid)) {
|
||||
chan->cid = chan->dcid;
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Check conn type before assigning cid */
|
||||
for (cid = L2CAP_CID_START; cid < L2CAP_LE_CID_END; cid++) {
|
||||
if (!l2cap_chan_lookup_scid(conn, cid)) {
|
||||
chan->cid = cid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan)
|
||||
{
|
||||
l2cap_chan_alloc_cid(conn, chan);
|
||||
|
||||
/* Attach channel to the connection */
|
||||
chan->_next = conn->l2cap.channels;
|
||||
conn->l2cap.channels = chan;
|
||||
|
||||
BT_DBG("chan %p cid 0x%04x\n", chan, chan->cid);
|
||||
}
|
||||
|
||||
static void le_conn_req(struct bt_conn *conn, uint8_t ident, struct bt_buf *buf)
|
||||
static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||
struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = l2cap->chan.conn;
|
||||
struct bt_l2cap_chan *chan;
|
||||
struct bt_l2cap_server *server;
|
||||
struct bt_l2cap_le_conn_req *req = (void *)buf->data;
|
||||
struct bt_l2cap_le_conn_rsp *rsp;
|
||||
struct bt_l2cap_sig_hdr *hdr;
|
||||
uint16_t psm, scid, mtu, mps;
|
||||
uint16_t psm, scid, mtu, mps, credits;
|
||||
|
||||
if (buf->len < sizeof(*req)) {
|
||||
BT_ERR("Too small LE conn req packet size\n");
|
||||
|
@ -337,9 +352,10 @@ static void le_conn_req(struct bt_conn *conn, uint8_t ident, struct bt_buf *buf)
|
|||
scid = sys_le16_to_cpu(req->scid);
|
||||
mtu = sys_le16_to_cpu(req->mtu);
|
||||
mps = sys_le16_to_cpu(req->mps);
|
||||
credits = sys_le16_to_cpu(req->credits);
|
||||
|
||||
BT_DBG("psm 0x%02x scid 0x%04x mtu 0x%04x mps 0x%04x\n", psm, scid,
|
||||
mtu, mps);
|
||||
BT_DBG("psm 0x%02x scid 0x%04x mtu %u mps %u credits %u\n", psm, scid,
|
||||
mtu, mps, credits);
|
||||
|
||||
if (mtu < L2CAP_LE_MIN_MTU || mps < L2CAP_LE_MIN_MTU) {
|
||||
BT_ERR("Invalid LE-Conn Req params\n");
|
||||
|
@ -351,13 +367,13 @@ static void le_conn_req(struct bt_conn *conn, uint8_t ident, struct bt_buf *buf)
|
|||
return;
|
||||
}
|
||||
|
||||
mtu = min(mtu, bt_buf_tailroom(buf));
|
||||
|
||||
hdr = bt_buf_add(buf, sizeof(*hdr));
|
||||
hdr->code = BT_L2CAP_LE_CONN_RSP;
|
||||
hdr->ident = ident;
|
||||
hdr->len = sys_cpu_to_le16(sizeof(*rsp));
|
||||
|
||||
mtu = min(mtu, bt_buf_tailroom(buf));
|
||||
|
||||
rsp = bt_buf_add(buf, sizeof(*rsp));
|
||||
memset(rsp, 0, sizeof(*rsp));
|
||||
|
||||
|
@ -371,7 +387,7 @@ static void le_conn_req(struct bt_conn *conn, uint8_t ident, struct bt_buf *buf)
|
|||
|
||||
/* TODO: Add security check */
|
||||
|
||||
chan = l2cap_chan_lookup_dcid(conn, scid);
|
||||
chan = bt_l2cap_lookup_tx_cid(conn, scid);
|
||||
if (chan) {
|
||||
rsp->dcid = req->scid;
|
||||
rsp->result = BT_L2CAP_ERR_NO_RESOURCES;
|
||||
|
@ -389,30 +405,37 @@ static void le_conn_req(struct bt_conn *conn, uint8_t ident, struct bt_buf *buf)
|
|||
goto rsp;
|
||||
}
|
||||
|
||||
chan->dcid = scid;
|
||||
chan->mps = mps;
|
||||
chan->mtu = mtu;
|
||||
chan->credits_rx = L2CAP_LE_MAX_CREDITS;
|
||||
chan->credits_tx = sys_le16_to_cpu(req->credits);
|
||||
/* Init TX parameters */
|
||||
chan->tx.cid = scid;
|
||||
chan->tx.mps = mps;
|
||||
chan->tx.mtu = mtu;
|
||||
chan->tx.credits = credits;
|
||||
|
||||
/* Init RX parameters */
|
||||
chan->rx.mps = bt_buf_tailroom(buf) + sizeof(*rsp);
|
||||
/* TODO: Once segmentation is supported these can be different */
|
||||
chan->rx.mtu = chan->rx.mps;
|
||||
chan->rx.credits = L2CAP_LE_MAX_CREDITS;
|
||||
|
||||
l2cap_chan_add(conn, chan);
|
||||
|
||||
if (chan->connected) {
|
||||
chan->connected(conn);
|
||||
if (chan->ops->connected) {
|
||||
chan->ops->connected(chan);
|
||||
}
|
||||
|
||||
rsp->dcid = sys_cpu_to_le16(chan->cid);
|
||||
rsp->mps = sys_cpu_to_le16(chan->mps);
|
||||
rsp->mtu = sys_cpu_to_le16(chan->mtu);
|
||||
rsp->credits = sys_cpu_to_le16(chan->credits_rx);
|
||||
rsp->dcid = sys_cpu_to_le16(chan->rx.cid);
|
||||
rsp->mps = sys_cpu_to_le16(chan->rx.mps);
|
||||
rsp->mtu = sys_cpu_to_le16(chan->rx.mtu);
|
||||
rsp->credits = sys_cpu_to_le16(chan->rx.credits);
|
||||
rsp->result = BT_L2CAP_SUCCESS;
|
||||
|
||||
rsp:
|
||||
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
|
||||
}
|
||||
|
||||
static void le_sig(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static void l2cap_recv(struct bt_l2cap_chan *chan, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_l2cap *l2cap = CONTAINER_OF(chan, struct bt_l2cap, chan);
|
||||
struct bt_l2cap_sig_hdr *hdr = (void *)buf->data;
|
||||
uint16_t len;
|
||||
|
||||
|
@ -439,19 +462,19 @@ static void le_sig(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
switch (hdr->code) {
|
||||
case BT_L2CAP_CONN_PARAM_RSP:
|
||||
le_conn_param_rsp(conn, buf);
|
||||
le_conn_param_rsp(l2cap, buf);
|
||||
break;
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
case BT_L2CAP_CONN_PARAM_REQ:
|
||||
le_conn_param_update_req(conn, hdr->ident, buf);
|
||||
le_conn_param_update_req(l2cap, hdr->ident, buf);
|
||||
break;
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
case BT_L2CAP_LE_CONN_REQ:
|
||||
le_conn_req(conn, hdr->ident, buf);
|
||||
le_conn_req(l2cap, hdr->ident, buf);
|
||||
break;
|
||||
default:
|
||||
BT_WARN("Unknown L2CAP PDU code 0x%02x\n", hdr->code);
|
||||
rej_not_understood(conn, hdr->ident);
|
||||
rej_not_understood(chan->conn, hdr->ident);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -476,22 +499,14 @@ void bt_l2cap_recv(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
BT_DBG("Packet for CID %u len %u\n", cid, buf->len);
|
||||
|
||||
for (chan = channels; chan; chan = chan->_next) {
|
||||
if (chan->cid == cid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!chan) {
|
||||
chan = l2cap_chan_lookup_scid(conn, cid);
|
||||
chan = bt_l2cap_lookup_rx_cid(conn, cid);
|
||||
if (!chan) {
|
||||
BT_WARN("Ignoring data for unknown CID 0x%04x\n", cid);
|
||||
bt_buf_put(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chan->recv(conn, buf);
|
||||
chan->ops->recv(chan, buf);
|
||||
}
|
||||
|
||||
int bt_l2cap_update_conn_param(struct bt_conn *conn)
|
||||
|
@ -521,13 +536,53 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void l2cap_connected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
BT_DBG("chan %p cid 0x%04x\n", chan, chan->rx.cid);
|
||||
}
|
||||
|
||||
static void l2cap_disconnected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
BT_DBG("chan %p cid 0x%04x\n", chan, chan->rx.cid);
|
||||
}
|
||||
|
||||
static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
||||
{
|
||||
int i;
|
||||
static struct bt_l2cap_chan_ops ops = {
|
||||
.connected = l2cap_connected,
|
||||
.disconnected = l2cap_disconnected,
|
||||
.recv = l2cap_recv,
|
||||
};
|
||||
|
||||
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_l2cap_pool); i++) {
|
||||
struct bt_l2cap *l2cap = &bt_l2cap_pool[i];
|
||||
|
||||
if (l2cap->chan.conn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
l2cap->chan.ops = &ops;
|
||||
|
||||
*chan = &l2cap->chan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_ERR("No available L2CAP context for conn %p\n", conn);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int bt_l2cap_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
static struct bt_l2cap_chan chan = {
|
||||
static struct bt_l2cap_fixed_chan chan = {
|
||||
.cid = BT_L2CAP_CID_LE_SIG,
|
||||
.recv = le_sig,
|
||||
.accept = l2cap_accept,
|
||||
};
|
||||
|
||||
bt_att_init();
|
||||
|
@ -537,7 +592,34 @@ int bt_l2cap_init(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
bt_l2cap_chan_register(&chan);
|
||||
bt_l2cap_fixed_chan_register(&chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bt_l2cap_chan *bt_l2cap_lookup_tx_cid(struct bt_conn *conn,
|
||||
uint16_t cid)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = conn->channels; chan; chan = chan->_next) {
|
||||
if (chan->tx.cid == cid)
|
||||
return chan;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_l2cap_chan *bt_l2cap_lookup_rx_cid(struct bt_conn *conn,
|
||||
uint16_t cid)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
for (chan = conn->channels; chan; chan = chan->_next) {
|
||||
if (chan->rx.cid == cid) {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <bluetooth/l2cap.h>
|
||||
|
||||
#define BT_L2CAP_CID_ATT 0x0004
|
||||
#define BT_L2CAP_CID_LE_SIG 0x0005
|
||||
#define BT_L2CAP_CID_SMP 0x0006
|
||||
|
@ -87,41 +89,16 @@ struct bt_l2cap_le_conn_rsp {
|
|||
uint16_t result;
|
||||
};
|
||||
|
||||
struct bt_l2cap_chan {
|
||||
struct bt_l2cap_fixed_chan {
|
||||
uint16_t cid;
|
||||
|
||||
/* CoC fields */
|
||||
uint16_t dcid;
|
||||
|
||||
uint16_t mps;
|
||||
uint16_t mtu;
|
||||
|
||||
uint16_t credits_tx;
|
||||
uint16_t credits_rx;
|
||||
|
||||
void (*connected)(struct bt_conn *conn);
|
||||
void (*disconnected)(struct bt_conn *conn);
|
||||
void (*encrypt_change)(struct bt_conn *conn);
|
||||
|
||||
void (*recv)(struct bt_conn *conn,
|
||||
struct bt_buf *buf);
|
||||
|
||||
struct bt_l2cap_chan *_next;
|
||||
};
|
||||
|
||||
struct bt_l2cap_server {
|
||||
uint16_t psm;
|
||||
|
||||
int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan);
|
||||
|
||||
struct bt_l2cap_server *_next;
|
||||
struct bt_l2cap_fixed_chan *_next;
|
||||
};
|
||||
|
||||
/* Register a fixed L2CAP channel for L2CAP */
|
||||
void bt_l2cap_chan_register(struct bt_l2cap_chan *chan);
|
||||
|
||||
/* Register L2CAP Server */
|
||||
int bt_l2cap_server_register(struct bt_l2cap_server *server);
|
||||
void bt_l2cap_fixed_chan_register(struct bt_l2cap_fixed_chan *chan);
|
||||
|
||||
/* Notify L2CAP channels of a new connection */
|
||||
void bt_l2cap_connected(struct bt_conn *conn);
|
||||
|
@ -146,3 +123,11 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn);
|
|||
|
||||
/* Initialize L2CAP and supported channels */
|
||||
int bt_l2cap_init(void);
|
||||
|
||||
/* Lookup channel by Transmission CID */
|
||||
struct bt_l2cap_chan *bt_l2cap_lookup_tx_cid(struct bt_conn *conn,
|
||||
uint16_t cid);
|
||||
|
||||
/* Lookup channel by Receiver CID */
|
||||
struct bt_l2cap_chan *bt_l2cap_lookup_rx_cid(struct bt_conn *conn,
|
||||
uint16_t cid);
|
||||
|
|
|
@ -71,8 +71,8 @@ enum {
|
|||
|
||||
/* SMP channel specific context */
|
||||
struct bt_smp {
|
||||
/* The connection this context is associated with */
|
||||
struct bt_conn *conn;
|
||||
/* The channel this context is associated with */
|
||||
struct bt_l2cap_chan chan;
|
||||
|
||||
/* SMP Timeout fiber handle */
|
||||
void *timeout;
|
||||
|
@ -151,7 +151,7 @@ static uint8_t get_pair_method(struct bt_smp *smp, uint8_t remote_io)
|
|||
* and responder inputs
|
||||
*/
|
||||
if (method == PASSKEY_ROLE) {
|
||||
if (smp->conn->role == BT_HCI_ROLE_MASTER) {
|
||||
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
||||
method = PASSKEY_DISPLAY;
|
||||
} else {
|
||||
method = PASSKEY_INPUT;
|
||||
|
@ -408,6 +408,8 @@ static int smp_s1(const uint8_t k[16], const uint8_t r1[16],
|
|||
|
||||
static void smp_reset(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
|
||||
if (smp->timeout) {
|
||||
fiber_fiber_delayed_start_cancel(smp->timeout);
|
||||
smp->timeout = NULL;
|
||||
|
@ -420,13 +422,13 @@ static void smp_reset(struct bt_smp *smp)
|
|||
atomic_set(&smp->allowed_cmds, 0);
|
||||
atomic_set(&smp->flags, 0);
|
||||
|
||||
if (smp->conn->required_sec_level != smp->conn->sec_level) {
|
||||
if (conn->required_sec_level != conn->sec_level) {
|
||||
/* TODO report error */
|
||||
/* reset required security level in case of error */
|
||||
smp->conn->required_sec_level = smp->conn->sec_level;
|
||||
conn->required_sec_level = conn->sec_level;
|
||||
}
|
||||
|
||||
switch(smp->conn->role) {
|
||||
switch (conn->role) {
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
case BT_HCI_ROLE_MASTER:
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SECURITY_REQUEST);
|
||||
|
@ -502,10 +504,8 @@ static void send_err_rsp(struct bt_conn *conn, uint8_t reason)
|
|||
|
||||
static int smp_init(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_conn *conn = smp->conn;
|
||||
|
||||
/* Initialize SMP context */
|
||||
memset(smp, 0, sizeof(*smp));
|
||||
memset(smp + sizeof(smp->chan), 0, sizeof(*smp) - sizeof(smp->chan));
|
||||
|
||||
/* Generate local random number */
|
||||
if (le_rand(smp->prnd, 16)) {
|
||||
|
@ -514,8 +514,6 @@ static int smp_init(struct bt_smp *smp)
|
|||
|
||||
BT_DBG("prnd %s\n", h(smp->prnd, 16));
|
||||
|
||||
smp->conn = conn;
|
||||
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_FAIL);
|
||||
|
||||
return 0;
|
||||
|
@ -536,6 +534,7 @@ static uint8_t get_auth(uint8_t auth)
|
|||
|
||||
static uint8_t smp_request_tk(struct bt_smp *smp, uint8_t remote_io)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_keys *keys;
|
||||
uint32_t passkey;
|
||||
|
||||
|
@ -545,7 +544,7 @@ static uint8_t smp_request_tk(struct bt_smp *smp, uint8_t remote_io)
|
|||
* distributed in new pairing. This is to avoid replacing authenticated
|
||||
* keys with unauthenticated ones.
|
||||
*/
|
||||
keys = bt_keys_find_addr(&smp->conn->dst);
|
||||
keys = bt_keys_find_addr(&conn->dst);
|
||||
if (keys && keys->type == BT_KEYS_AUTHENTICATED &&
|
||||
smp->method == JUST_WORKS) {
|
||||
BT_ERR("JustWorks failed, authenticated keys present\n");
|
||||
|
@ -560,7 +559,7 @@ static uint8_t smp_request_tk(struct bt_smp *smp, uint8_t remote_io)
|
|||
|
||||
passkey %= 1000000;
|
||||
|
||||
auth_cb->passkey_display(smp->conn, passkey);
|
||||
auth_cb->passkey_display(conn, passkey);
|
||||
|
||||
passkey = sys_cpu_to_le32(passkey);
|
||||
memcpy(smp->tk, &passkey, sizeof(passkey));
|
||||
|
@ -568,7 +567,7 @@ static uint8_t smp_request_tk(struct bt_smp *smp, uint8_t remote_io)
|
|||
|
||||
break;
|
||||
case PASSKEY_INPUT:
|
||||
auth_cb->passkey_entry(smp->conn);
|
||||
auth_cb->passkey_entry(conn);
|
||||
break;
|
||||
case JUST_WORKS:
|
||||
atomic_set_bit(&smp->flags, SMP_FLAG_TK_VALID);
|
||||
|
@ -595,14 +594,31 @@ static bool sec_level_reachable(struct bt_conn *conn)
|
|||
}
|
||||
}
|
||||
|
||||
static struct bt_smp *smp_chan_get(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_l2cap_chan *chan;
|
||||
|
||||
chan = bt_l2cap_lookup_rx_cid(conn, BT_L2CAP_CID_SMP);
|
||||
if (!chan) {
|
||||
BT_ERR("Unable to find SMP channel");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
||||
int bt_smp_send_security_req(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_smp *smp;
|
||||
struct bt_smp_security_request *req;
|
||||
struct bt_buf *req_buf;
|
||||
|
||||
BT_DBG("\n");
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* SMP Timeout */
|
||||
if (atomic_test_bit(&smp->flags, SMP_FLAG_TIMEOUT)) {
|
||||
|
@ -640,12 +656,12 @@ int bt_smp_send_security_req(struct bt_conn *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_pairing_req(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_req(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_pairing *req = (void *)buf->data;
|
||||
struct bt_smp_pairing *rsp;
|
||||
struct bt_buf *rsp_buf;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
int ret;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -693,16 +709,16 @@ static uint8_t smp_pairing_req(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return smp_request_tk(smp, req->io_capability);
|
||||
}
|
||||
#else
|
||||
static uint8_t smp_pairing_req(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_req(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
return BT_SMP_ERR_CMD_NOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
||||
|
||||
static uint8_t smp_send_pairing_confirm(struct bt_conn *conn)
|
||||
static uint8_t smp_send_pairing_confirm(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_pairing_confirm *req;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_buf *rsp_buf;
|
||||
int err;
|
||||
|
||||
|
@ -733,12 +749,17 @@ static uint8_t smp_send_pairing_confirm(struct bt_conn *conn)
|
|||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
int bt_smp_send_pairing_req(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_smp *smp;
|
||||
struct bt_smp_pairing *req;
|
||||
struct bt_buf *req_buf;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* SMP Timeout */
|
||||
if (atomic_test_bit(&smp->flags, SMP_FLAG_TIMEOUT)) {
|
||||
return -EIO;
|
||||
|
@ -789,10 +810,9 @@ int bt_smp_send_pairing_req(struct bt_conn *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_pairing_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_rsp(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_smp_pairing *rsp = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
uint8_t ret;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -816,7 +836,7 @@ static uint8_t smp_pairing_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
if (atomic_test_bit(&smp->flags, SMP_FLAG_TK_VALID)) {
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
|
||||
return smp_send_pairing_confirm(conn);
|
||||
return smp_send_pairing_confirm(smp);
|
||||
}
|
||||
|
||||
atomic_set_bit(&smp->flags, SMP_FLAG_CFM_DELAYED);
|
||||
|
@ -824,17 +844,17 @@ static uint8_t smp_pairing_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
static uint8_t smp_pairing_rsp(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_rsp(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
return BT_SMP_ERR_CMD_NOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
static uint8_t smp_send_pairing_random(struct bt_conn *conn)
|
||||
static uint8_t smp_send_pairing_random(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_pairing_random *req;
|
||||
struct bt_buf *rsp_buf;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
|
||||
rsp_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_RANDOM,
|
||||
sizeof(*req));
|
||||
|
@ -852,26 +872,25 @@ static uint8_t smp_send_pairing_random(struct bt_conn *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_pairing_confirm(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_confirm(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_smp_pairing_confirm *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
||||
memcpy(smp->pcnf, req->val, sizeof(smp->pcnf));
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
if (conn->role == BT_HCI_ROLE_MASTER) {
|
||||
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
||||
return smp_send_pairing_random(conn);
|
||||
return smp_send_pairing_random(smp);
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
||||
if (atomic_test_bit(&smp->flags, SMP_FLAG_TK_VALID)) {
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
||||
return smp_send_pairing_confirm(conn);
|
||||
return smp_send_pairing_confirm(smp);
|
||||
}
|
||||
|
||||
atomic_set_bit(&smp->flags, SMP_FLAG_CFM_DELAYED);
|
||||
|
@ -905,10 +924,10 @@ static uint8_t get_encryption_key_size(struct bt_smp *smp)
|
|||
return min(req->max_key_size, rsp->max_key_size);
|
||||
}
|
||||
|
||||
static uint8_t smp_pairing_random(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_random(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_pairing_random *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
uint8_t cfm[16];
|
||||
int err;
|
||||
|
@ -992,16 +1011,16 @@ static uint8_t smp_pairing_random(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
||||
|
||||
smp_send_pairing_random(conn);
|
||||
smp_send_pairing_random(smp);
|
||||
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_pairing_failed(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_pairing_failed(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_pairing_fail *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
|
||||
BT_ERR("reason 0x%x\n", req->reason);
|
||||
|
||||
|
@ -1026,9 +1045,9 @@ static uint8_t smp_pairing_failed(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bt_smp_distribute_keys(struct bt_conn *conn)
|
||||
static void bt_smp_distribute_keys(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_keys *keys;
|
||||
struct bt_buf *buf;
|
||||
|
||||
|
@ -1123,10 +1142,10 @@ static void bt_smp_distribute_keys(struct bt_conn *conn)
|
|||
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
||||
}
|
||||
|
||||
static uint8_t smp_encrypt_info(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_encrypt_info(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_encrypt_info *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -1145,10 +1164,10 @@ static uint8_t smp_encrypt_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_master_ident(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_master_ident(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_master_ident *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -1173,7 +1192,7 @@ static uint8_t smp_master_ident(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
||||
bt_smp_distribute_keys(conn);
|
||||
bt_smp_distribute_keys(smp);
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
|
@ -1185,10 +1204,10 @@ static uint8_t smp_master_ident(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_ident_info(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_ident_info(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_ident_info *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -1207,10 +1226,10 @@ static uint8_t smp_ident_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t smp_ident_addr_info(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_ident_addr_info(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_ident_addr_info *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
const bt_addr_le_t *dst;
|
||||
struct bt_keys *keys;
|
||||
|
||||
|
@ -1264,7 +1283,7 @@ static uint8_t smp_ident_addr_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
||||
bt_smp_distribute_keys(conn);
|
||||
bt_smp_distribute_keys(smp);
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
|
@ -1277,10 +1296,10 @@ static uint8_t smp_ident_addr_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_SIGNING)
|
||||
static uint8_t smp_signing_info(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_signing_info(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_signing_info *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("\n");
|
||||
|
@ -1298,7 +1317,7 @@ static uint8_t smp_signing_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
||||
bt_smp_distribute_keys(conn);
|
||||
bt_smp_distribute_keys(smp);
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
|
@ -1310,17 +1329,17 @@ static uint8_t smp_signing_info(struct bt_conn *conn, struct bt_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
static uint8_t smp_signing_info(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_signing_info(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
return BT_SMP_ERR_CMD_NOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
||||
static uint8_t smp_security_request(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_security_request(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.conn;
|
||||
struct bt_smp_security_request *req = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_keys *keys;
|
||||
uint8_t auth;
|
||||
|
||||
|
@ -1361,14 +1380,14 @@ pair:
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
static uint8_t smp_security_request(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static uint8_t smp_security_request(struct bt_smp *smp, struct bt_buf *buf)
|
||||
{
|
||||
return BT_SMP_ERR_CMD_NOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
static const struct {
|
||||
uint8_t (*func)(struct bt_conn *conn, struct bt_buf *buf);
|
||||
uint8_t (*func)(struct bt_smp *smp, struct bt_buf *buf);
|
||||
uint8_t expect_len;
|
||||
} handlers[] = {
|
||||
{ }, /* No op-code defined for 0x00 */
|
||||
|
@ -1385,10 +1404,10 @@ static const struct {
|
|||
{ smp_security_request, sizeof(struct bt_smp_security_request) },
|
||||
};
|
||||
|
||||
static void bt_smp_recv(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static void bt_smp_recv(struct bt_l2cap_chan *chan, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
struct bt_smp_hdr *hdr = (void *)buf->data;
|
||||
struct bt_smp *smp = conn->smp;
|
||||
uint8_t err;
|
||||
|
||||
if (buf->len < sizeof(*hdr)) {
|
||||
|
@ -1425,12 +1444,12 @@ static void bt_smp_recv(struct bt_conn *conn, struct bt_buf *buf)
|
|||
hdr->code);
|
||||
err = BT_SMP_ERR_INVALID_PARAMS;
|
||||
} else {
|
||||
err = handlers[hdr->code].func(conn, buf);
|
||||
err = handlers[hdr->code].func(smp, buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
send_err_rsp(conn, err);
|
||||
send_err_rsp(chan->conn, err);
|
||||
|
||||
smp_reset(smp);
|
||||
}
|
||||
|
@ -1439,41 +1458,20 @@ done:
|
|||
bt_buf_put(buf);
|
||||
}
|
||||
|
||||
static void bt_smp_connected(struct bt_conn *conn)
|
||||
static void bt_smp_connected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
int i;
|
||||
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
|
||||
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
|
||||
struct bt_smp *smp = &bt_smp_pool[i];
|
||||
|
||||
if (smp->conn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
smp->conn = conn;
|
||||
conn->smp = smp;
|
||||
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
|
||||
|
||||
smp_reset(smp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BT_ERR("No available SMP context for conn %p\n", conn);
|
||||
}
|
||||
|
||||
static void bt_smp_disconnected(struct bt_conn *conn)
|
||||
static void bt_smp_disconnected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
|
||||
if (!smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
||||
|
||||
conn->smp = NULL;
|
||||
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
|
||||
|
||||
if (smp->timeout) {
|
||||
fiber_fiber_delayed_start_cancel(smp->timeout);
|
||||
|
@ -1482,13 +1480,14 @@ static void bt_smp_disconnected(struct bt_conn *conn)
|
|||
memset(smp, 0, sizeof(*smp));
|
||||
}
|
||||
|
||||
static void bt_smp_encrypt_change(struct bt_conn *conn)
|
||||
static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
struct bt_conn *conn = chan->conn;
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("conn %p handle %u encrypt 0x%02x\n", conn, conn->handle,
|
||||
conn->encrypt);
|
||||
BT_DBG("chan %p conn %p handle %u encrypt 0x%02x\n", chan, conn,
|
||||
conn->handle, conn->encrypt);
|
||||
|
||||
if (!smp || !conn->encrypt) {
|
||||
return;
|
||||
|
@ -1534,7 +1533,7 @@ static void bt_smp_encrypt_change(struct bt_conn *conn)
|
|||
}
|
||||
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
||||
|
||||
bt_smp_distribute_keys(conn);
|
||||
bt_smp_distribute_keys(smp);
|
||||
|
||||
/* if all keys were distributed, pairing is done */
|
||||
if (!smp->local_dist && !smp->remote_dist) {
|
||||
|
@ -2085,7 +2084,12 @@ int bt_auth_cb_register(const struct bt_auth_cb *cb)
|
|||
|
||||
void bt_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
|
||||
{
|
||||
struct bt_smp *smp = conn->smp;
|
||||
struct bt_smp *smp;
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
passkey = sys_cpu_to_le32(passkey);
|
||||
memcpy(smp->tk, &passkey, sizeof(passkey));
|
||||
|
@ -2096,7 +2100,7 @@ void bt_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
|
|||
}
|
||||
|
||||
/* if confirm failed ie. due to invalid passkey, cancel pairing */
|
||||
if (smp_send_pairing_confirm(conn) ) {
|
||||
if (smp_send_pairing_confirm(smp)) {
|
||||
bt_auth_cancel(conn);
|
||||
return;
|
||||
}
|
||||
|
@ -2120,21 +2124,57 @@ void bt_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
|
|||
|
||||
void bt_auth_cancel(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
send_err_rsp(conn, BT_SMP_ERR_PASSKEY_ENTRY_FAILED);
|
||||
smp_reset(conn->smp);
|
||||
|
||||
smp_reset(smp);
|
||||
}
|
||||
|
||||
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
||||
{
|
||||
int i;
|
||||
static struct bt_l2cap_chan_ops ops = {
|
||||
.connected = bt_smp_connected,
|
||||
.disconnected = bt_smp_disconnected,
|
||||
.encrypt_change = bt_smp_encrypt_change,
|
||||
.recv = bt_smp_recv,
|
||||
};
|
||||
|
||||
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
|
||||
struct bt_smp *smp = &bt_smp_pool[i];
|
||||
|
||||
if (smp->chan.conn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
smp->chan.ops = &ops;
|
||||
|
||||
*chan = &smp->chan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_ERR("No available SMP context for conn %p\n", conn);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int bt_smp_init(void)
|
||||
{
|
||||
static struct bt_l2cap_chan chan = {
|
||||
static struct bt_l2cap_fixed_chan chan = {
|
||||
.cid = BT_L2CAP_CID_SMP,
|
||||
.recv = bt_smp_recv,
|
||||
.connected = bt_smp_connected,
|
||||
.disconnected = bt_smp_disconnected,
|
||||
.encrypt_change = bt_smp_encrypt_change,
|
||||
.accept = bt_smp_accept,
|
||||
};
|
||||
|
||||
bt_l2cap_chan_register(&chan);
|
||||
bt_l2cap_fixed_chan_register(&chan);
|
||||
|
||||
return smp_self_test();
|
||||
}
|
||||
|
|
|
@ -19,18 +19,29 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <nanokernel.h>
|
||||
#include <errno.h>
|
||||
#include <atomic.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#include <bluetooth/log.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
|
||||
#include "hci_core.h"
|
||||
#include "conn_internal.h"
|
||||
#include "l2cap_internal.h"
|
||||
#include "smp.h"
|
||||
|
||||
static struct bt_l2cap_chan bt_smp_pool[CONFIG_BLUETOOTH_MAX_CONN];
|
||||
|
||||
int bt_smp_sign_verify(struct bt_conn *conn, struct bt_buf *buf)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static void bt_smp_recv(struct bt_conn *conn, struct bt_buf *buf)
|
||||
static void bt_smp_recv(struct bt_l2cap_chan *chan, struct bt_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = chan->conn;
|
||||
struct bt_smp_pairing_fail *rsp;
|
||||
struct bt_smp_hdr *hdr;
|
||||
|
||||
|
@ -56,14 +67,42 @@ static void bt_smp_recv(struct bt_conn *conn, struct bt_buf *buf)
|
|||
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
|
||||
}
|
||||
|
||||
int bt_smp_init(void)
|
||||
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
||||
{
|
||||
static struct bt_l2cap_chan chan = {
|
||||
.cid = BT_L2CAP_CID_SMP,
|
||||
int i;
|
||||
static struct bt_l2cap_chan_ops ops = {
|
||||
.recv = bt_smp_recv,
|
||||
};
|
||||
|
||||
bt_l2cap_chan_register(&chan);
|
||||
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
|
||||
struct bt_l2cap_chan *smp = &bt_smp_pool[i];
|
||||
|
||||
if (smp->conn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
smp->ops = &ops;
|
||||
|
||||
*chan = smp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_ERR("No available SMP context for conn %p\n", conn);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int bt_smp_init(void)
|
||||
{
|
||||
static struct bt_l2cap_fixed_chan chan = {
|
||||
.cid = BT_L2CAP_CID_SMP,
|
||||
.accept = bt_smp_accept,
|
||||
};
|
||||
|
||||
bt_l2cap_fixed_chan_register(&chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue