diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 763f5079012..cbbe95c3859 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -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) { diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index fe140597fe1..88cabf86d81 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -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; } diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 4c409010555..5b83a91da65 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -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) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 73d21626503..bad0071acd8 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -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); diff --git a/subsys/bluetooth/host/gatt_internal.h b/subsys/bluetooth/host/gatt_internal.h index 95c544a76e2..ffc54d6af0f 100644 --- a/subsys/bluetooth/host/gatt_internal.h +++ b/subsys/bluetooth/host/gatt_internal.h @@ -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);