From bd45dc0ea0aaa27bc974c15cb9a34c0e578cd839 Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Mon, 3 Jul 2023 13:45:30 +0200 Subject: [PATCH] bluetooth: host: smp: Add bondable flag overlay per connection The current API for changing the bondable mode uses the global flag. With Zephyr support for multiple Bluetooth identities, the API for changing the bondable mode should be more fine-grained. The bondable requirements of one identity should not have an impact on another identity which can have a different set of requirements. This change introduces function to overlay bondable flag per connection. Signed-off-by: Mateusz Kapala --- include/zephyr/bluetooth/conn.h | 19 +++++++++++++++++ subsys/bluetooth/host/smp.c | 36 +++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index a6c6d3b0366c094..20fbede2f9b71df 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1081,6 +1081,25 @@ void bt_conn_cb_register(struct bt_conn_cb *cb); */ void bt_set_bondable(bool enable); +/** @brief Overlay the bonding flag for a given connection. + * + * Set/clear the Bonding flag in the Authentication Requirements of + * SMP Pairing Request/Response data for a given connection. + * + * The bonding flag for a given connection cannot be overlaid if + * security procedures in the SMP module have already started. This function + * can be called only once per connection. + * + * If the bonding flag is not overlaid, the value will depend on global + * configuration which is set using bt_set_bondable. + * The default value of the global configuration is defined using + * CONFIG_BT_BONDABLE Kconfig option. + * + * @param conn Connection object. + * @param enable Value allowing/disallowing to be bondable. + */ +int bt_bondable_overlay(struct bt_conn *conn, bool enable); + /** @brief Allow/disallow remote LE SC OOB data to be used for pairing. * * Set/clear the OOB data flag for LE SC SMP Pairing Request/Response data. diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 9b40910cb304d3f..3b149aea7e7ba8b 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -209,6 +209,9 @@ struct bt_smp { /* Used Bluetooth authentication callbacks. */ atomic_ptr_t auth_cb; + + /* Bondable flag */ + atomic_t bondable; }; static unsigned int fixed_passkey = BT_PASSKEY_INVALID; @@ -288,6 +291,11 @@ static K_SEM_DEFINE(sc_local_pkey_ready, 0, 1); */ #define BT_SMP_AUTH_CB_UNINITIALIZED ((atomic_ptr_val_t)bt_smp_pool) +/* Value used to mark that per-connection bondable flag is not initialized. + * Value false/true represent if flag is cleared or set and cannot be used for that purpose. + */ +#define BT_SMP_BONDABLE_UNINITIALIZED ((atomic_val_t)-1) + static bool le_sc_supported(void) { /* @@ -310,6 +318,13 @@ static const struct bt_conn_auth_cb *latch_auth_cb(struct bt_smp *smp) return atomic_ptr_get(&smp->auth_cb); } +static bool latch_bondable(struct bt_smp *smp) +{ + atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)bondable); + + return atomic_get(&smp->bondable); +} + static uint8_t get_io_capa(struct bt_smp *smp) { const struct bt_conn_auth_cb *smp_auth_cb = latch_auth_cb(smp); @@ -2592,7 +2607,7 @@ static uint8_t get_auth(struct bt_smp *smp, uint8_t auth) auth |= BT_SMP_AUTH_MITM; } - if (bondable) { + if (latch_bondable(smp)) { auth |= BT_SMP_AUTH_BONDING; } else { auth &= ~BT_SMP_AUTH_BONDING; @@ -3977,7 +3992,7 @@ static uint8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf) } if (IS_ENABLED(CONFIG_BT_BONDING_REQUIRED) && - !(bondable && (auth & BT_SMP_AUTH_BONDING))) { + !(latch_bondable(smp) && (auth & BT_SMP_AUTH_BONDING))) { /* Reject security req if not both intend to bond */ LOG_DBG("Bonding required"); return BT_SMP_ERR_UNSPECIFIED; @@ -4541,6 +4556,7 @@ static void bt_smp_connected(struct bt_l2cap_chan *chan) smp_reset(smp); atomic_ptr_set(&smp->auth_cb, BT_SMP_AUTH_CB_UNINITIALIZED); + atomic_set(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED); } static void bt_smp_disconnected(struct bt_l2cap_chan *chan) @@ -5291,6 +5307,22 @@ static inline int smp_self_test(void) } #endif +int bt_bondable_overlay(struct bt_conn *conn, bool enable) +{ + struct bt_smp *smp; + + smp = smp_chan_get(conn); + if (!smp) { + return -EINVAL; + } + + if (atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)enable)) { + return 0; + } else { + return -EALREADY; + } +} + int bt_smp_auth_cb_overlay(struct bt_conn *conn, const struct bt_conn_auth_cb *cb) { struct bt_smp *smp;