Bluetooth: Fix read by type request attr permissions handling

This patch fixes checking permissions and sending response to read by
type request. If multiple (or if one is found) attributess are found
within handle range and first of them don't have read permission,
error should be send. If any of attribute don't have read permission
but isn't first in set, the attributes before this attribute should
be returned.

Change-Id: I532a8701521505c02845de5db62c94f7edc9d567
Signed-off-by: Grzegorz Kolodziejczyk <grzegorz.kolodziejczyk@tieto.com>
This commit is contained in:
Grzegorz Kolodziejczyk 2015-10-29 15:50:17 +01:00 committed by Anas Nashif
commit 04c03c1a92

View file

@ -515,12 +515,52 @@ static bool uuid_create(struct bt_uuid *uuid, struct net_buf *buf)
return false; return false;
} }
static uint8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint8_t mask)
{
if ((mask & BT_GATT_PERM_READ) && !(attr->perm & BT_GATT_PERM_READ)) {
return BT_ATT_ERR_READ_NOT_PERMITTED;
}
if ((mask & BT_GATT_PERM_WRITE) && !(attr->perm & BT_GATT_PERM_WRITE)) {
return BT_ATT_ERR_WRITE_NOT_PERMITTED;
}
mask &= attr->perm;
if (mask & BT_GATT_PERM_AUTHEN_MASK) {
#if defined(CONFIG_BLUETOOTH_SMP)
if (conn->sec_level < BT_SECURITY_HIGH) {
return BT_ATT_ERR_AUTHENTICATION;
}
#else
return BT_ATT_ERR_AUTHENTICATION;
#endif /* CONFIG_BLUETOOTH_SMP */
}
if ((mask & BT_GATT_PERM_ENCRYPT_MASK)) {
#if defined(CONFIG_BLUETOOTH_SMP)
if (!conn->encrypt) {
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
}
#else
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
#endif /* CONFIG_BLUETOOTH_SMP */
}
if (mask & BT_GATT_PERM_AUTHOR) {
return BT_ATT_ERR_AUTHORIZATION;
}
return 0;
}
struct read_type_data { struct read_type_data {
struct bt_att *att; struct bt_att *att;
struct bt_uuid *uuid; struct bt_uuid *uuid;
struct net_buf *buf; struct net_buf *buf;
struct bt_att_read_type_rsp *rsp; struct bt_att_read_type_rsp *rsp;
struct bt_att_data *item; struct bt_att_data *item;
uint8_t err;
}; };
static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data) static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
@ -537,6 +577,30 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
BT_DBG("handle 0x%04x\n", attr->handle); BT_DBG("handle 0x%04x\n", attr->handle);
/*
* If an attribute in the set of requested attributes would cause an
* Error Response then this attribute cannot be included in a
* Read By Type Response and the attributes before this attribute
* shall be returned
*
* If the first attribute in the set of requested attributes would
* cause an Error Response then no other attributes in the requested
* attributes can be considered.
*/
data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
if (data->err) {
if (!data->rsp->len) {
data->err = 0x00;
}
return BT_GATT_ITER_STOP;
}
/*
* If any attribute is founded in handle range it means that error
* should be changed from pre-set: attr not found error to no error.
*/
data->err = 0x00;
/* Fast foward to next item position */ /* Fast foward to next item position */
data->item = net_buf_add(data->buf, sizeof(*data->item)); data->item = net_buf_add(data->buf, sizeof(*data->item));
data->item->handle = sys_cpu_to_le16(attr->handle); data->item->handle = sys_cpu_to_le16(attr->handle);
@ -584,13 +648,16 @@ static uint8_t att_read_type_rsp(struct bt_att *att, struct bt_uuid *uuid,
data.rsp = net_buf_add(data.buf, sizeof(*data.rsp)); data.rsp = net_buf_add(data.buf, sizeof(*data.rsp));
data.rsp->len = 0; data.rsp->len = 0;
/* Pre-set error if no attr will be found in handle */
data.err = BT_ATT_ERR_ATTRIBUTE_NOT_FOUND;
bt_gatt_foreach_attr(start_handle, end_handle, read_type_cb, &data); bt_gatt_foreach_attr(start_handle, end_handle, read_type_cb, &data);
if (!data.rsp->len) { if (data.err) {
net_buf_unref(data.buf); net_buf_unref(data.buf);
/* Response here since handle is set */ /* Response here since handle is set */
send_err_rsp(conn, BT_ATT_OP_READ_TYPE_REQ, start_handle, send_err_rsp(conn, BT_ATT_OP_READ_TYPE_REQ, start_handle,
BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); data.err);
return 0; return 0;
} }
@ -650,45 +717,6 @@ static uint8_t err_to_att(int err)
} }
} }
static uint8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint8_t mask)
{
if ((mask & BT_GATT_PERM_READ) && !(attr->perm & BT_GATT_PERM_READ)) {
return BT_ATT_ERR_READ_NOT_PERMITTED;
}
if ((mask & BT_GATT_PERM_WRITE) && !(attr->perm & BT_GATT_PERM_WRITE)) {
return BT_ATT_ERR_WRITE_NOT_PERMITTED;
}
mask &= attr->perm;
if (mask & BT_GATT_PERM_AUTHEN_MASK) {
#if defined(CONFIG_BLUETOOTH_SMP)
if (conn->sec_level < BT_SECURITY_HIGH) {
return BT_ATT_ERR_AUTHENTICATION;
}
#else
return BT_ATT_ERR_AUTHENTICATION;
#endif /* CONFIG_BLUETOOTH_SMP */
}
if ((mask & BT_GATT_PERM_ENCRYPT_MASK)) {
#if defined(CONFIG_BLUETOOTH_SMP)
if (!conn->encrypt) {
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
}
#else
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
#endif /* CONFIG_BLUETOOTH_SMP */
}
if (mask & BT_GATT_PERM_AUTHOR) {
return BT_ATT_ERR_AUTHORIZATION;
}
return 0;
}
struct read_data { struct read_data {
struct bt_att *att; struct bt_att *att;
uint16_t offset; uint16_t offset;