Bluetooth: GATT: Use check_perm to check CCC permission
This moves check_perm code under GAT and make use of it to check if CCC write permission can be attended by the connection security level or if it needs to be increased. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
03b9ce487c
commit
4f3892c0eb
5 changed files with 92 additions and 61 deletions
|
@ -334,6 +334,12 @@ typedef enum __packed {
|
|||
*/
|
||||
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec);
|
||||
|
||||
/** @brief Get security level for a connection.
|
||||
*
|
||||
* @return Connection security level
|
||||
*/
|
||||
bt_security_t bt_conn_get_security(struct bt_conn *conn);
|
||||
|
||||
static inline int __deprecated bt_conn_security(struct bt_conn *conn,
|
||||
bt_security_t sec)
|
||||
{
|
||||
|
|
|
@ -34,16 +34,6 @@
|
|||
#define ATT_CHAN(_ch) CONTAINER_OF(_ch, struct bt_att, chan.chan)
|
||||
#define ATT_REQ(_node) CONTAINER_OF(_node, struct bt_att_req, node)
|
||||
|
||||
#define BT_GATT_PERM_READ_MASK (BT_GATT_PERM_READ | \
|
||||
BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_READ_AUTHEN)
|
||||
#define BT_GATT_PERM_WRITE_MASK (BT_GATT_PERM_WRITE | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
#define BT_GATT_PERM_ENCRYPT_MASK (BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT)
|
||||
#define BT_GATT_PERM_AUTHEN_MASK (BT_GATT_PERM_READ_AUTHEN | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
#define ATT_CMD_MASK 0x40
|
||||
|
||||
#define ATT_TIMEOUT K_SECONDS(30)
|
||||
|
@ -722,43 +712,6 @@ static u8_t att_find_type_req(struct bt_att *att, struct net_buf *buf)
|
|||
buf->len);
|
||||
}
|
||||
|
||||
static u8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
u8_t mask)
|
||||
{
|
||||
if ((mask & BT_GATT_PERM_READ) &&
|
||||
(!(attr->perm & BT_GATT_PERM_READ_MASK) || !attr->read)) {
|
||||
return BT_ATT_ERR_READ_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
if ((mask & BT_GATT_PERM_WRITE) &&
|
||||
(!(attr->perm & BT_GATT_PERM_WRITE_MASK) || !attr->write)) {
|
||||
return BT_ATT_ERR_WRITE_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
mask &= attr->perm;
|
||||
if (mask & BT_GATT_PERM_AUTHEN_MASK) {
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
if (conn->sec_level < BT_SECURITY_L3) {
|
||||
return BT_ATT_ERR_AUTHENTICATION;
|
||||
}
|
||||
#else
|
||||
return BT_ATT_ERR_AUTHENTICATION;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
}
|
||||
|
||||
if ((mask & BT_GATT_PERM_ENCRYPT_MASK)) {
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
if (!conn->encrypt) {
|
||||
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
|
||||
}
|
||||
#else
|
||||
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8_t err_to_att(int err)
|
||||
{
|
||||
BT_DBG("%d", err);
|
||||
|
@ -803,7 +756,7 @@ static u8_t read_type_cb(const struct bt_gatt_attr *attr, void *user_data)
|
|||
* 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);
|
||||
data->err = bt_gatt_check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
|
||||
if (data->err) {
|
||||
if (data->rsp->len) {
|
||||
data->err = 0x00;
|
||||
|
@ -945,7 +898,7 @@ static u8_t read_cb(const struct bt_gatt_attr *attr, void *user_data)
|
|||
data->err = 0x00;
|
||||
|
||||
/* Check attribute permissions */
|
||||
data->err = check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
|
||||
data->err = bt_gatt_check_perm(conn, attr, BT_GATT_PERM_READ_MASK);
|
||||
if (data->err) {
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -1259,7 +1212,8 @@ static u8_t write_cb(const struct bt_gatt_attr *attr, void *user_data)
|
|||
BT_DBG("handle 0x%04x offset %u", attr->handle, data->offset);
|
||||
|
||||
/* Check attribute permissions */
|
||||
data->err = check_perm(data->conn, attr, BT_GATT_PERM_WRITE_MASK);
|
||||
data->err = bt_gatt_check_perm(data->conn, attr,
|
||||
BT_GATT_PERM_WRITE_MASK);
|
||||
if (data->err) {
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -1365,7 +1319,8 @@ static u8_t prep_write_cb(const struct bt_gatt_attr *attr, void *user_data)
|
|||
BT_DBG("handle 0x%04x offset %u", attr->handle, data->offset);
|
||||
|
||||
/* Check attribute permissions */
|
||||
data->err = check_perm(data->conn, attr, BT_GATT_PERM_WRITE_MASK);
|
||||
data->err = bt_gatt_check_perm(data->conn, attr,
|
||||
BT_GATT_PERM_WRITE_MASK);
|
||||
if (data->err) {
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
|
|
@ -1085,6 +1085,16 @@ int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_security_t bt_conn_get_security(struct bt_conn *conn)
|
||||
{
|
||||
return conn->sec_level;
|
||||
}
|
||||
#else
|
||||
bt_security_t bt_conn_get_security(struct bt_conn *conn)
|
||||
{
|
||||
return BT_SECURITY_L1;
|
||||
}
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
||||
void bt_conn_cb_register(struct bt_conn_cb *cb)
|
||||
|
|
|
@ -1695,6 +1695,43 @@ u16_t bt_gatt_get_mtu(struct bt_conn *conn)
|
|||
return bt_att_get_mtu(conn);
|
||||
}
|
||||
|
||||
u8_t bt_gatt_check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
u8_t mask)
|
||||
{
|
||||
if ((mask & BT_GATT_PERM_READ) &&
|
||||
(!(attr->perm & BT_GATT_PERM_READ_MASK) || !attr->read)) {
|
||||
return BT_ATT_ERR_READ_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
if ((mask & BT_GATT_PERM_WRITE) &&
|
||||
(!(attr->perm & BT_GATT_PERM_WRITE_MASK) || !attr->write)) {
|
||||
return BT_ATT_ERR_WRITE_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
mask &= attr->perm;
|
||||
if (mask & BT_GATT_PERM_AUTHEN_MASK) {
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
if (conn->sec_level < BT_SECURITY_L3) {
|
||||
return BT_ATT_ERR_AUTHENTICATION;
|
||||
}
|
||||
#else
|
||||
return BT_ATT_ERR_AUTHENTICATION;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
}
|
||||
|
||||
if ((mask & BT_GATT_PERM_ENCRYPT_MASK)) {
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
if (!conn->encrypt) {
|
||||
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
|
||||
}
|
||||
#else
|
||||
return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_GATT_DYNAMIC_DB)
|
||||
static void sc_restore(struct bt_gatt_ccc_cfg *cfg)
|
||||
{
|
||||
|
@ -1725,6 +1762,7 @@ static u8_t update_ccc(const struct bt_gatt_attr *attr, void *user_data)
|
|||
struct bt_conn *conn = data->conn;
|
||||
struct _bt_gatt_ccc *ccc;
|
||||
size_t i;
|
||||
u8_t err;
|
||||
|
||||
/* Check attribute user_data must be of type struct _bt_gatt_ccc */
|
||||
if (attr->write != bt_gatt_attr_write_ccc) {
|
||||
|
@ -1739,25 +1777,31 @@ static u8_t update_ccc(const struct bt_gatt_attr *attr, void *user_data)
|
|||
continue;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
/* Check if attribute requires encryption/authentication */
|
||||
if (attr->perm &
|
||||
(BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_WRITE_AUTHEN)) {
|
||||
bt_security_t sec = BT_SECURITY_L2;
|
||||
err = bt_gatt_check_perm(conn, attr, BT_GATT_PERM_WRITE_MASK);
|
||||
if (err) {
|
||||
bt_security_t sec;
|
||||
|
||||
if (attr->perm & BT_GATT_PERM_WRITE_AUTHEN) {
|
||||
if (err == BT_ATT_ERR_WRITE_NOT_PERMITTED) {
|
||||
BT_WARN("CCC %p not writable", attr);
|
||||
continue;
|
||||
}
|
||||
|
||||
sec = BT_SECURITY_L2;
|
||||
|
||||
if (err == BT_ATT_ERR_AUTHENTICATION) {
|
||||
sec = BT_SECURITY_L3;
|
||||
}
|
||||
|
||||
/* Check if current security is enough */
|
||||
if (conn->sec_level < sec) {
|
||||
if (IS_ENABLED(CONFIG_BT_SMP) &&
|
||||
bt_conn_get_security(conn) < sec) {
|
||||
if (data->sec < sec) {
|
||||
data->sec = sec;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ccc->cfg[i].value) {
|
||||
gatt_ccc_changed(attr, ccc);
|
||||
|
@ -3264,7 +3308,6 @@ void bt_gatt_connected(struct bt_conn *conn)
|
|||
|
||||
bt_gatt_foreach_attr(0x0001, 0xffff, update_ccc, &data);
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part C page 2192:
|
||||
*
|
||||
* 10.3.1.1 Handling of GATT indications and notifications
|
||||
|
@ -3281,10 +3324,10 @@ void bt_gatt_connected(struct bt_conn *conn)
|
|||
* does not have an LTK indicating that the client has lost the bond,
|
||||
* enabling encryption will fail.
|
||||
*/
|
||||
if (conn->sec_level < data.sec) {
|
||||
if (IS_ENABLED(CONFIG_BT_SMP) &&
|
||||
bt_conn_get_security(conn) < data.sec) {
|
||||
bt_conn_set_security(conn, data.sec);
|
||||
}
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
||||
#if defined(CONFIG_BT_GATT_CLIENT)
|
||||
add_subscriptions(conn);
|
||||
|
|
|
@ -11,6 +11,17 @@
|
|||
#define BT_GATT_CENTRAL_ADDR_RES_NOT_SUPP 0
|
||||
#define BT_GATT_CENTRAL_ADDR_RES_SUPP 1
|
||||
|
||||
#define BT_GATT_PERM_READ_MASK (BT_GATT_PERM_READ | \
|
||||
BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_READ_AUTHEN)
|
||||
#define BT_GATT_PERM_WRITE_MASK (BT_GATT_PERM_WRITE | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
#define BT_GATT_PERM_ENCRYPT_MASK (BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT)
|
||||
#define BT_GATT_PERM_AUTHEN_MASK (BT_GATT_PERM_READ_AUTHEN | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
|
||||
void bt_gatt_init(void);
|
||||
void bt_gatt_connected(struct bt_conn *conn);
|
||||
void bt_gatt_encrypt_change(struct bt_conn *conn);
|
||||
|
@ -31,3 +42,9 @@ static inline void bt_gatt_notification(struct bt_conn *conn, u16_t handle,
|
|||
{
|
||||
}
|
||||
#endif /* CONFIG_BT_GATT_CLIENT */
|
||||
|
||||
struct bt_gatt_attr;
|
||||
|
||||
/* Check attribute permission */
|
||||
u8_t bt_gatt_check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
u8_t mask);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue