Skip to content

Commit

Permalink
[nrf fromtree] bluetooth: gatt: add authorization callback API for ga…
Browse files Browse the repository at this point in the history
…tt operations

Added the GATT authorization callback API that allows the user to
define application-specific authorization logic for GATT operations.

Signed-off-by: Kamil Piszczek <[email protected]>
(cherry picked from commit 6852abf)
  • Loading branch information
kapi-no authored and rlubos committed Jan 23, 2024
1 parent d97e4bc commit e537e00
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 0 deletions.
51 changes: 51 additions & 0 deletions include/zephyr/bluetooth/gatt.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,37 @@ struct bt_gatt_cb {
sys_snode_t node;
};

/** @brief GATT authorization callback structure. */
struct bt_gatt_authorization_cb {
/** @brief Authorize the GATT read operation.
*
* This callback allows the application to authorize the GATT
* read operation for the attribute that is being read.
*
* @param conn Connection object.
* @param attr The attribute that is being read.
*
* @retval true Authorize the operation and allow it to execute.
* @retval false Reject the operation and prevent it from executing.
*/
bool (*read_operation_authorize)(struct bt_conn *conn,
const struct bt_gatt_attr *attr);

/** @brief Authorize the GATT write operation.
*
* This callback allows the application to authorize the GATT
* write operation for the attribute that is being written.
*
* @param conn Connection object.
* @param attr The attribute that is being written.
*
* @retval true Authorize the operation and allow it to execute.
* @retval false Reject the operation and prevent it from executing.
*/
bool (*write_operation_authorize)(struct bt_conn *conn,
const struct bt_gatt_attr *attr);
};

/** Characteristic Properties Bit field values */

/**
Expand Down Expand Up @@ -377,6 +408,26 @@ struct bt_gatt_cpf {
*/
void bt_gatt_cb_register(struct bt_gatt_cb *cb);

/** @brief Register GATT authorization callbacks.
*
* Register callbacks to perform application-specific authorization of GATT
* operations on all registered GATT attributes. The callback structure must
* remain valid throughout the entire duration of the Bluetooth subsys
* activity.
*
* The @kconfig{CONFIG_BT_GATT_AUTHORIZATION_CUSTOM} Kconfig must be enabled
* to make this API functional.
*
* This API allows the user to register only one callback structure
* concurrently. Passing NULL unregisters the previous set of callbacks
* and makes it possible to register a new one.
*
* @param cb Callback struct.
*
* @return Zero on success or negative error code otherwise
*/
int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb);

/** @brief Register GATT service.
*
* Register GATT service. Applications can make use of
Expand Down
9 changes: 9 additions & 0 deletions subsys/bluetooth/host/Kconfig.gatt
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,13 @@ config DEVICE_NAME_GATT_WRITABLE_AUTHEN

endif #BT_DEVICE_NAME_GATT_WRITABLE

config BT_GATT_AUTHORIZATION_CUSTOM
bool "Custom authorization of GATT operations [EXPERIMENTAL]"
select EXPERIMENTAL
help
This option allows the user to define application-specific
authorization logic for GATT operations that can be registered
with the bt_gatt_authorization_cb_register API. See the API
documentation for more details.

endmenu
83 changes: 83 additions & 0 deletions subsys/bluetooth/host/att.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ static uint16_t bt_att_mtu(struct bt_att_chan *chan)
return MIN(chan->chan.rx.mtu, chan->chan.tx.mtu);
}

/* Descriptor of application-specific authorization callbacks that are used
* with the CONFIG_BT_GATT_AUTHORIZATION_CUSTOM Kconfig enabled.
*/
const static struct bt_gatt_authorization_cb *authorization_cb;

/* ATT connection specific data */
struct bt_att {
struct bt_conn *conn;
Expand Down Expand Up @@ -1289,6 +1294,20 @@ struct read_type_data {
typedef bool (*attr_read_cb)(struct net_buf *buf, ssize_t read,
void *user_data);

static bool attr_read_authorize(struct bt_conn *conn,
const struct bt_gatt_attr *attr)
{
if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) {
return true;
}

if (!authorization_cb || !authorization_cb->read_operation_authorize) {
return true;
}

return authorization_cb->read_operation_authorize(conn, attr);
}

static bool attr_read_type_cb(struct net_buf *frag, ssize_t read,
void *user_data)
{
Expand Down Expand Up @@ -1398,6 +1417,12 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, uint16_t handle,
return BT_GATT_ITER_STOP;
}

/* Check the attribute authorization logic */
if (!attr_read_authorize(conn, attr)) {
data->err = BT_ATT_ERR_AUTHORIZATION;
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.
Expand Down Expand Up @@ -1526,6 +1551,12 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, uint16_t handle,
return BT_GATT_ITER_STOP;
}

/* Check the attribute authorization logic */
if (!attr_read_authorize(conn, attr)) {
data->err = BT_ATT_ERR_AUTHORIZATION;
return BT_GATT_ITER_STOP;
}

/* Read attribute value and store in the buffer */
ret = att_chan_read(chan, attr, data->buf, data->offset, NULL, NULL);
if (ret < 0) {
Expand Down Expand Up @@ -1693,6 +1724,12 @@ static uint8_t read_vl_cb(const struct bt_gatt_attr *attr, uint16_t handle,
return BT_GATT_ITER_STOP;
}

/* Check the attribute authorization logic */
if (!attr_read_authorize(conn, attr)) {
data->err = BT_ATT_ERR_AUTHORIZATION;
return BT_GATT_ITER_STOP;
}

/* The Length Value Tuple List may be truncated within the first two
* octets of a tuple due to the size limits of the current ATT_MTU.
*/
Expand Down Expand Up @@ -1940,6 +1977,20 @@ struct write_data {
uint8_t err;
};

static bool attr_write_authorize(struct bt_conn *conn,
const struct bt_gatt_attr *attr)
{
if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) {
return true;
}

if (!authorization_cb || !authorization_cb->write_operation_authorize) {
return true;
}

return authorization_cb->write_operation_authorize(conn, attr);
}

static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle,
void *user_data)
{
Expand All @@ -1956,6 +2007,12 @@ static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle,
return BT_GATT_ITER_STOP;
}

/* Check the attribute authorization logic */
if (!attr_write_authorize(data->conn, attr)) {
data->err = BT_ATT_ERR_AUTHORIZATION;
return BT_GATT_ITER_STOP;
}

/* Set command flag if not a request */
if (!data->req) {
flags |= BT_GATT_WRITE_FLAG_CMD;
Expand Down Expand Up @@ -2069,6 +2126,12 @@ static uint8_t prep_write_cb(const struct bt_gatt_attr *attr, uint16_t handle,
return BT_GATT_ITER_STOP;
}

/* Check the attribute authorization logic */
if (!attr_write_authorize(data->conn, attr)) {
data->err = BT_ATT_ERR_AUTHORIZATION;
return BT_GATT_ITER_STOP;
}

/* Check if attribute requires handler to accept the data */
if (!(attr->perm & BT_GATT_PERM_PREPARE_WRITE)) {
goto append;
Expand Down Expand Up @@ -3997,3 +4060,23 @@ bool bt_att_chan_opt_valid(struct bt_conn *conn, enum bt_att_chan_opt chan_opt)

return true;
}

int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb)
{
if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) {
return -ENOSYS;
}

if (!cb) {
authorization_cb = NULL;
return 0;
}

if (authorization_cb) {
return -EALREADY;
}

authorization_cb = cb;

return 0;
}

0 comments on commit e537e00

Please sign in to comment.