Bluetooth: Refactor fixed channel data

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

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

View file

@ -72,9 +72,8 @@ struct bt_att_req {
/* ATT channel specific context */
struct bt_att {
/* The connection this context is associated with */
struct bt_conn *conn;
uint16_t mtu;
/* The channel this context is associated with */
struct bt_l2cap_chan chan;
struct bt_att_req req;
/* TODO: Allow more than one pending request */
};
@ -128,9 +127,9 @@ static void send_err_rsp(struct bt_conn *conn, uint8_t req, uint16_t handle,
bt_l2cap_send(conn, BT_L2CAP_CID_ATT, buf);
}
static uint8_t att_mtu_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_mtu_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att *att = conn->att;
struct bt_conn *conn = att->chan.conn;
struct bt_att_exchange_mtu_req *req;
struct bt_att_exchange_mtu_rsp *rsp;
struct bt_buf *pdu;
@ -164,16 +163,21 @@ static uint8_t att_mtu_req(struct bt_conn *conn, struct bt_buf *buf)
bt_l2cap_send(conn, BT_L2CAP_CID_ATT, pdu);
att->mtu = min(mtu_client, mtu_server);
/* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part F] page 484:
*
* A device's Exchange MTU Request shall contain the same MTU as the
* device's Exchange MTU Response (i.e. the MTU shall be symmetric).
*/
att->chan.rx.mtu = min(mtu_client, mtu_server);
att->chan.tx.mtu = att->chan.rx.mtu;
BT_DBG("Negotiated MTU %u\n", att->mtu);
BT_DBG("Negotiated MTU %u\n", att->chan.rx.mtu);
return 0;
}
static uint8_t att_handle_rsp(struct bt_conn *conn, void *pdu, uint16_t len,
static uint8_t att_handle_rsp(struct bt_att *att, void *pdu, uint16_t len,
uint8_t err)
{
struct bt_att *att = conn->att;
struct bt_att_req req;
if (!att->req.func) {
@ -184,16 +188,15 @@ static uint8_t att_handle_rsp(struct bt_conn *conn, void *pdu, uint16_t len,
memcpy(&req, &att->req, sizeof(req));
att->req.func = NULL;
req.func(conn, err, pdu, len, req.user_data);
req.func(att->chan.conn, err, pdu, len, req.user_data);
att_req_destroy(&req);
return 0;
}
static uint8_t att_mtu_rsp(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_mtu_rsp(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att *att = conn->att;
struct bt_att_exchange_mtu_rsp *rsp;
uint16_t mtu;
@ -209,19 +212,28 @@ static uint8_t att_mtu_rsp(struct bt_conn *conn, struct bt_buf *buf)
/* Check if MTU is valid */
if (mtu < BT_ATT_DEFAULT_LE_MTU) {
return att_handle_rsp(conn, NULL, 0, BT_ATT_ERR_INVALID_PDU);
return att_handle_rsp(att, NULL, 0, BT_ATT_ERR_INVALID_PDU);
}
/* Clip MTU based on the maximum amount of data bt_buf can hold
* excluding L2CAP, ACL and driver headers.
*/
att->mtu = min(mtu, BT_BUF_MAX_DATA - (sizeof(struct bt_l2cap_hdr) +
att->chan.rx.mtu = min(mtu, BT_BUF_MAX_DATA -
(sizeof(struct bt_l2cap_hdr) +
sizeof(struct bt_hci_acl_hdr) +
bt_dev.drv->head_reserve));
BT_DBG("Negotiated MTU %u\n", att->mtu);
return att_handle_rsp(conn, rsp, buf->len, 0);
/* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part F] page 484:
*
* A device's Exchange MTU Request shall contain the same MTU as the
* device's Exchange MTU Response (i.e. the MTU shall be symmetric).
*/
att->chan.tx.mtu = att->chan.rx.mtu;
BT_DBG("Negotiated MTU %u\n", att->chan.rx.mtu);
return att_handle_rsp(att, rsp, buf->len, 0);
}
static bool range_is_valid(uint16_t start, uint16_t end, uint16_t *err)
@ -246,7 +258,7 @@ static bool range_is_valid(uint16_t start, uint16_t end, uint16_t *err)
}
struct find_info_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_buf *buf;
struct bt_att_find_info_rsp *rsp;
union {
@ -258,7 +270,7 @@ struct find_info_data {
static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct find_info_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
BT_DBG("handle 0x%04x\n", attr->handle);
@ -280,8 +292,9 @@ static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
data->info16->handle = sys_cpu_to_le16(attr->handle);
data->info16->uuid = sys_cpu_to_le16(attr->uuid->u16);
return att->mtu - data->buf->len > sizeof(*data->info16) ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
if (att->chan.tx.mtu - data->buf->len > sizeof(*data->info16)) {
return BT_GATT_ITER_CONTINUE;
}
case BT_ATT_INFO_128:
if (attr->uuid->type != BT_UUID_128) {
return BT_GATT_ITER_STOP;
@ -293,16 +306,19 @@ static uint8_t find_info_cb(const struct bt_gatt_attr *attr, void *user_data)
memcpy(data->info128->uuid, attr->uuid->u128,
sizeof(data->info128->uuid));
return att->mtu - data->buf->len > sizeof(*data->info128) ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
if (att->chan.tx.mtu - data->buf->len >
sizeof(*data->info128)) {
return BT_GATT_ITER_CONTINUE;
}
}
return BT_GATT_ITER_STOP;
}
static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
static uint8_t att_find_info_rsp(struct bt_att *att, uint16_t start_handle,
uint16_t end_handle)
{
struct bt_conn *conn = att->chan.conn;
struct find_info_data data;
memset(&data, 0, sizeof(data));
@ -312,7 +328,7 @@ static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
bt_gatt_foreach_attr(start_handle, end_handle, find_info_cb, &data);
if (!data.rsp) {
@ -328,8 +344,9 @@ static uint8_t att_find_info_rsp(struct bt_conn *conn, uint16_t start_handle,
return 0;
}
static uint8_t att_find_info_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_find_info_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_find_info_req *req;
uint16_t start_handle, end_handle, err_handle;
@ -347,11 +364,11 @@ static uint8_t att_find_info_req(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
return att_find_info_rsp(conn, start_handle, end_handle);
return att_find_info_rsp(att, start_handle, end_handle);
}
struct find_type_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_buf *buf;
struct bt_att_handle_group *group;
const void *value;
@ -361,7 +378,8 @@ struct find_type_data {
static uint8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct find_type_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
uint8_t uuid[16];
@ -376,11 +394,11 @@ static uint8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data)
BT_DBG("handle 0x%04x\n", attr->handle);
/* stop if there is no space left */
if (att->mtu - data->buf->len < sizeof(*data->group))
if (att->chan.tx.mtu - data->buf->len < sizeof(*data->group))
return BT_GATT_ITER_STOP;
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, uuid, sizeof(uuid), 0);
read = attr->read(conn, attr, uuid, sizeof(uuid), 0);
if (read < 0) {
/* TODO: Return an error if this fails */
return BT_GATT_ITER_STOP;
@ -432,8 +450,9 @@ static uint8_t att_find_type_rsp(struct bt_conn *conn, uint16_t start_handle,
return 0;
}
static uint8_t att_find_type_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_find_type_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_find_type_req *req;
uint16_t start_handle, end_handle, err_handle, type;
uint8_t *value;
@ -490,7 +509,7 @@ static bool uuid_create(struct bt_uuid *uuid, struct bt_buf *buf)
}
struct read_type_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_uuid *uuid;
struct bt_buf *buf;
struct bt_att_read_type_rsp *rsp;
@ -500,7 +519,8 @@ struct read_type_data {
static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_type_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
/* Skip if doesn't match */
@ -515,8 +535,8 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
data->item->handle = sys_cpu_to_le16(attr->handle);
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, 0);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, 0);
if (read < 0) {
/* TODO: Handle read errors */
return BT_GATT_ITER_STOP;
@ -534,13 +554,14 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
bt_buf_add(data->buf, read);
/* return true only if there are still space for more items */
return att->mtu - data->buf->len > data->rsp->len ?
return att->chan.tx.mtu - data->buf->len > data->rsp->len ?
BT_GATT_ITER_CONTINUE : BT_GATT_ITER_STOP;
}
static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
static uint8_t att_read_type_rsp(struct bt_att *att, struct bt_uuid *uuid,
uint16_t start_handle, uint16_t end_handle)
{
struct bt_conn *conn = att->chan.conn;
struct read_type_data data;
memset(&data, 0, sizeof(data));
@ -551,7 +572,7 @@ static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
data.uuid = uuid;
data.rsp = bt_buf_add(data.buf, sizeof(*data.rsp));
data.rsp->len = 0;
@ -571,8 +592,9 @@ static uint8_t att_read_type_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
return 0;
}
static uint8_t att_read_type_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_type_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct bt_att_read_type_req *req;
uint16_t start_handle, end_handle, err_handle;
struct bt_uuid uuid;
@ -602,7 +624,7 @@ static uint8_t att_read_type_req(struct bt_conn *conn, struct bt_buf *buf)
return 0;
}
return att_read_type_rsp(conn, &uuid, start_handle, end_handle);
return att_read_type_rsp(att, &uuid, start_handle, end_handle);
}
static uint8_t err_to_att(int err)
@ -654,7 +676,7 @@ static uint8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
}
struct read_data {
struct bt_conn *conn;
struct bt_att *att;
uint16_t offset;
struct bt_buf *buf;
struct bt_att_read_rsp *rsp;
@ -664,7 +686,8 @@ struct read_data {
static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
BT_DBG("handle 0x%04x\n", attr->handle);
@ -683,14 +706,14 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
}
/* Check attribute permissions */
data->err = check_perm(data->conn, attr, BT_GATT_PERM_READ_MASK);
data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
if (data->err) {
return BT_GATT_ITER_STOP;
}
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, data->offset);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, data->offset);
if (read < 0) {
data->err = err_to_att(read);
return BT_GATT_ITER_STOP;
@ -701,9 +724,10 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
return BT_GATT_ITER_CONTINUE;
}
static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
static uint8_t att_read_rsp(struct bt_att *att, uint8_t op, uint8_t rsp,
uint16_t handle, uint16_t offset)
{
struct bt_conn *conn = att->chan.conn;
struct read_data data;
if (!handle) {
@ -717,7 +741,7 @@ static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
data.offset = offset;
/* Pre-set error if no attr will be found in handle */
@ -738,7 +762,7 @@ static uint8_t att_read_rsp(struct bt_conn *conn, uint8_t op, uint8_t rsp,
return 0;
}
static uint8_t att_read_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att_read_req *req;
uint16_t handle;
@ -749,11 +773,11 @@ static uint8_t att_read_req(struct bt_conn *conn, struct bt_buf *buf)
BT_DBG("handle 0x%04x\n", handle);
return att_read_rsp(conn, BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP,
return att_read_rsp(att, BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP,
handle, 0);
}
static uint8_t att_read_blob_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_blob_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_att_read_blob_req *req;
uint16_t handle, offset;
@ -765,12 +789,13 @@ static uint8_t att_read_blob_req(struct bt_conn *conn, struct bt_buf *buf)
BT_DBG("handle 0x%04x offset %u\n", handle, offset);
return att_read_rsp(conn, BT_ATT_OP_READ_BLOB_REQ,
return att_read_rsp(att, BT_ATT_OP_READ_BLOB_REQ,
BT_ATT_OP_READ_BLOB_RSP, handle, offset);
}
static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
static uint8_t att_read_mult_req(struct bt_att *att, struct bt_buf *buf)
{
struct bt_conn *conn = att->chan.conn;
struct read_data data;
uint16_t handle;
@ -781,7 +806,7 @@ static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
return BT_ATT_ERR_UNLIKELY;
}
data.conn = conn;
data.att = att;
while (buf->len >= sizeof(uint16_t)) {
handle = bt_buf_pull_le16(buf);
@ -815,7 +840,7 @@ static uint8_t att_read_mult_req(struct bt_conn *conn, struct bt_buf *buf)
}
struct read_group_data {
struct bt_conn *conn;
struct bt_att *att;
struct bt_uuid *uuid;
struct bt_buf *buf;
struct bt_att_read_group_rsp *rsp;
@ -825,7 +850,8 @@ struct read_group_data {
static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct read_group_data *data = user_data;
struct bt_att *att = data->conn->att;
struct bt_att *att = data->att;
struct bt_conn *conn = att->chan.conn;
int read;
/* If UUID don't match update group end_handle */
@ -839,7 +865,8 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
BT_DBG("handle 0x%04x\n", attr->handle);
/* Stop if there is no space left */
if (data->rsp->len && att->mtu - data->buf->len < data->rsp->len)
if (data->rsp->len &&
att->chan.tx.mtu - data->buf->len < data->rsp->len)
return BT_GATT_ITER_STOP;
/* Fast foward to next group position */
@ -850,8 +877,8 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
data->group->end_handle = sys_cpu_to_le16(attr->handle);
/* Read attribute value and store in the buffer */
read = attr->read(data->conn, attr, data->buf->data + data->buf->len,
att->mtu - data->buf->len, 0);
read = attr->read(conn, attr, data->buf->data + data->buf->len,
att->chan.tx.mtu - data->buf->len, 0);
if (read < 0) {
/* TODO: Handle read errors */
return BT_GATT_ITER_STOP;
@ -872,9 +899,10 @@ static uint8_t read_group_cb(const struct bt_gatt_attr *attr, void *user_data)
return BT_GATT_ITER_CONTINUE;
}
static uint8_t att_read_group_rsp(struct bt_conn *conn, struct bt_uuid *uuid,
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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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;
}