Bluetooth: GATT: Expose ATT error codes to application callbacks

Introduce BT_GATT_ERR macro to make it possible for application
callbacks to return exact ATT error codes.

Change-Id: I971536508e75036fbddc40b3f33e5201e11940bc
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2016-02-17 14:03:20 +02:00
commit a72d967d33
8 changed files with 55 additions and 51 deletions

View file

@ -301,7 +301,7 @@ int bt_gatt_attr_read_ccc(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
return -ENOSYS; return BT_GATT_ERR(BT_ATT_ERR_NOT_SUPPORTED);
} }
int bt_gatt_attr_write_ccc(struct bt_conn *conn, int bt_gatt_attr_write_ccc(struct bt_conn *conn,
@ -312,11 +312,11 @@ int bt_gatt_attr_write_ccc(struct bt_conn *conn,
const uint16_t *data = buf; const uint16_t *data = buf;
if (offset > sizeof(*data)) { if (offset > sizeof(*data)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
if (offset + len > sizeof(*data)) { if (offset + len > sizeof(*data)) {
return -EFBIG; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
/* We expect to receive this only when the has really changed */ /* We expect to receive this only when the has really changed */
@ -346,14 +346,14 @@ int bt_gatt_attr_read_cud(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
return -ENOSYS; return BT_GATT_ERR(BT_ATT_ERR_NOT_SUPPORTED);
} }
int bt_gatt_attr_read_cpf(struct bt_conn *conn, int bt_gatt_attr_read_cpf(struct bt_conn *conn,
const struct bt_gatt_attr *attr, void *buf, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset) uint16_t len, uint16_t offset)
{ {
return -ENOSYS; return BT_GATT_ERR(BT_ATT_ERR_NOT_SUPPORTED);
} }
int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr, int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,

View file

@ -88,6 +88,17 @@ extern "C" {
*/ */
#define BT_GATT_FLUSH_SYNC 0x01 #define BT_GATT_FLUSH_SYNC 0x01
/** @def BT_GATT_ERR
* @brief Construct error return value for attribute read, write and
* flush callbacks.
*
* @param _att_err ATT error code
*
* @return Appropriate error code for the attribute callbacks.
*
*/
#define BT_GATT_ERR(_att_err) (-(_att_err))
/** @brief GATT Attribute structure. */ /** @brief GATT Attribute structure. */
struct bt_gatt_attr { struct bt_gatt_attr {
/** Attribute UUID */ /** Attribute UUID */

View file

@ -571,16 +571,11 @@ static uint8_t err_to_att(int err)
{ {
BT_DBG("%d", err); BT_DBG("%d", err);
switch (err) { if (err < 0 && err >= -0xff) {
case -EINVAL: return -err;
return BT_ATT_ERR_INVALID_OFFSET;
case -EFBIG:
return BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
case -EACCES:
return BT_ATT_ERR_ENCRYPTION_KEY_SIZE;
default:
return BT_ATT_ERR_UNLIKELY;
} }
return BT_ATT_ERR_UNLIKELY;
} }
struct read_type_data { struct read_type_data {

View file

@ -316,11 +316,11 @@ int bt_gatt_attr_write_ccc(struct bt_conn *conn,
size_t i; size_t i;
if (offset > sizeof(*data)) { if (offset > sizeof(*data)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
if (offset + len > sizeof(*data)) { if (offset + len > sizeof(*data)) {
return -EFBIG; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
if (bt_keys_find_addr(&conn->le.dst)) if (bt_keys_find_addr(&conn->le.dst))
@ -348,7 +348,7 @@ int bt_gatt_attr_write_ccc(struct bt_conn *conn,
if (i == ccc->cfg_len) { if (i == ccc->cfg_len) {
BT_WARN("No space to store CCC cfg"); BT_WARN("No space to store CCC cfg");
return -ENOMEM; return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
} }
} }

View file

@ -141,7 +141,7 @@ static int write_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint8_t *value = attr->user_data; uint8_t *value = attr->user_data;
if (offset + len > sizeof(ct)) { if (offset + len > sizeof(ct)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
memcpy(value + offset, buf, len); memcpy(value + offset, buf, len);
@ -198,7 +198,7 @@ static int write_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint8_t *value = attr->user_data; uint8_t *value = attr->user_data;
if (offset + len > sizeof(vnd_value)) { if (offset + len > sizeof(vnd_value)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
memcpy(value + offset, buf, len); memcpy(value + offset, buf, len);
@ -233,7 +233,7 @@ static int write_long_vnd(struct bt_conn *conn,
struct vnd_long_value *value = attr->user_data; struct vnd_long_value *value = attr->user_data;
if (offset + len > sizeof(value->buf)) { if (offset + len > sizeof(value->buf)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
/* Copy to buffer */ /* Copy to buffer */
@ -258,7 +258,7 @@ static int flush_long_vnd(struct bt_conn *conn,
return 0; return 0;
} }
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
} }
static const struct bt_uuid_128 vnd_long_uuid = BT_UUID_INIT_128( static const struct bt_uuid_128 vnd_long_uuid = BT_UUID_INIT_128(
@ -286,7 +286,7 @@ static int write_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr,
uint8_t *value = attr->user_data; uint8_t *value = attr->user_data;
if (offset + len > sizeof(signed_value)) { if (offset + len > sizeof(signed_value)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
memcpy(value + offset, buf, len); memcpy(value + offset, buf, len);

View file

@ -238,12 +238,11 @@ static int write_ctrl_point(struct bt_conn *conn,
int i; int i;
if (!ctrl_point_configured) { if (!ctrl_point_configured) {
/* TODO: Return CSC_ERR_CCC_CONFIG */ return BT_GATT_ERR(CSC_ERR_CCC_CONFIG);
return -EINVAL;
} }
if (!len) { if (!len) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
switch (req->op) { switch (req->op) {

View file

@ -328,15 +328,16 @@ static int write_temp_trigger_setting(struct bt_conn *conn,
uint16_t offset) uint16_t offset)
{ {
const struct write_es_trigger_setting_req *req = buf; const struct write_es_trigger_setting_req *req = buf;
const struct es_trigger_setting_reference *ref;
struct temperature_sensor *sensor = attr->user_data; struct temperature_sensor *sensor = attr->user_data;
uint16_t ref_val;
if (!len) { if (!len) {
return -EFBIG; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
if (req->condition > 0x09) { if (req->condition > 0x09) {
/* TODO: Return ESS_ERR_COND_NOT_SUPP */ return BT_GATT_ERR(ESS_ERR_COND_NOT_SUPP);
return -EINVAL;
} }
switch (req->condition) { switch (req->condition) {
@ -345,7 +346,7 @@ static int write_temp_trigger_setting(struct bt_conn *conn,
/* fallthrough */ /* fallthrough */
case ESS_VALUE_CHANGED: case ESS_VALUE_CHANGED:
if (len != sizeof(sensor->condition)) { if (len != sizeof(sensor->condition)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
sensor->condition = req->condition; sensor->condition = req->condition;
@ -355,30 +356,28 @@ static int write_temp_trigger_setting(struct bt_conn *conn,
/* fallthrough */ /* fallthrough */
case ESS_NO_LESS_THAN_SPECIFIED_TIME: case ESS_NO_LESS_THAN_SPECIFIED_TIME:
if (len != sizeof(struct es_trigger_setting_seconds)) { if (len != sizeof(struct es_trigger_setting_seconds)) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
sensor->condition = req->condition; sensor->condition = req->condition;
sensor->seconds = le24_to_int(req->operand); sensor->seconds = le24_to_int(req->operand);
break; break;
/* Reference temperature */ /* Reference temperature */
default: { default:
const struct es_trigger_setting_reference *req = buf; if (len != sizeof(*ref)) {
uint16_t ref_val = sys_le16_to_cpu(req->ref_val); return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
if (len != sizeof(*req)) {
return -EINVAL;
}
if (sensor->lower_limit > ref_val ||
sensor->upper_limit < ref_val) {
/* TODO: Return ERR_OUT_OF_RANGE */
return -EINVAL;
}
sensor->condition = req->condition;
sensor->ref_val = ref_val;
} }
ref = buf;
ref_val = sys_le16_to_cpu(ref->ref_val);
if (sensor->lower_limit > ref_val ||
sensor->upper_limit < ref_val) {
return BT_GATT_ERR(BT_ATT_ERR_OUT_OF_RANGE);
}
sensor->condition = req->condition;
sensor->ref_val = ref_val;
} }
return len; return len;

View file

@ -231,7 +231,7 @@ static int read_value(struct bt_conn *conn, const struct bt_gatt_attr *attr,
if ((attr->perm & GATT_PERM_ENC_READ_MASK) && if ((attr->perm & GATT_PERM_ENC_READ_MASK) &&
(value->enc_key_size > bt_conn_enc_key_size(conn))) { (value->enc_key_size > bt_conn_enc_key_size(conn))) {
return -EACCES; return BT_GATT_ERR(BT_ATT_ERR_ENCRYPTION_KEY_SIZE);
} }
return bt_gatt_attr_read(conn, attr, buf, len, offset, value->data, return bt_gatt_attr_read(conn, attr, buf, len, offset, value->data,
@ -245,7 +245,7 @@ static int write_value(struct bt_conn *conn, const struct bt_gatt_attr *attr,
if ((attr->perm & GATT_PERM_ENC_WRITE_MASK) && if ((attr->perm & GATT_PERM_ENC_WRITE_MASK) &&
(value->enc_key_size > bt_conn_enc_key_size(conn))) { (value->enc_key_size > bt_conn_enc_key_size(conn))) {
return -EACCES; return BT_GATT_ERR(BT_ATT_ERR_ENCRYPTION_KEY_SIZE);
} }
/* /*
@ -254,11 +254,11 @@ static int write_value(struct bt_conn *conn, const struct bt_gatt_attr *attr,
* «Invalid Offset». * «Invalid Offset».
*/ */
if (offset > value->len) { if (offset > value->len) {
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
} }
if (offset + len > value->len) { if (offset + len > value->len) {
return -EFBIG; return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
} }
memcpy(value->prep_data + offset, buf, len); memcpy(value->prep_data + offset, buf, len);
@ -281,7 +281,7 @@ static int flush_value(struct bt_conn *conn,
return 0; return 0;
} }
return -EINVAL; return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
} }
static struct bt_gatt_attr chr = BT_GATT_CHARACTERISTIC(NULL, 0); static struct bt_gatt_attr chr = BT_GATT_CHARACTERISTIC(NULL, 0);