diff --git a/doc/reference/bluetooth/connection_mgmt.rst b/doc/reference/bluetooth/connection_mgmt.rst index d4576176357..f0f8b54e518 100644 --- a/doc/reference/bluetooth/connection_mgmt.rst +++ b/doc/reference/bluetooth/connection_mgmt.rst @@ -17,11 +17,11 @@ to a connection. An application may track connections by registering a :c:struct:`bt_conn_cb` struct using the :c:func:`bt_conn_cb_register` -API. This struct lets the application define callbacks for connection & -disconnection events, as well as other events related to a connection -such as a change in the security level or the connection parameters. -When acting as a central the application will also get hold of the -connection object through the return value of the +or c:func:`BT_CONN_CB_DEFINE()` APIs. This struct lets the application +define callbacks for connection & disconnection events, as well as other +events related to a connection such as a change in the security level or +the connection parameters. When acting as a central the application will +also get hold of the connection object through the return value of the :c:func:`bt_conn_create_le` API. API Reference diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 056f0906195..300e3d704f9 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -932,6 +932,17 @@ struct bt_conn_cb { */ void bt_conn_cb_register(struct bt_conn_cb *cb); +/** @def BT_CONN_CB_DEFINE + * + * @brief Register a callback structure for connection events. + * + * @param _name Name of callback structure. + */ +#define BT_CONN_CB_DEFINE(_name) \ + static const Z_STRUCT_SECTION_ITERABLE(bt_conn_cb, \ + _CONCAT(bt_conn_cb, \ + _name)) + /** @brief Enable/disable bonding. * * Set/clear the Bonding flag in the Authentication Requirements of diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index 453655c349a..7557a79e7bc 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -115,6 +115,10 @@ Z_ITERABLE_SECTION_ROM(bt_l2cap_br_fixed_chan, 4) #endif +#if defined(CONFIG_BT_CONN) + Z_ITERABLE_SECTION_ROM(bt_conn_cb, 4) +#endif + Z_ITERABLE_SECTION_ROM(bt_gatt_service_static, 4) #if defined(CONFIG_BT_MESH) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index d1bc636e83e..b82a7c46848 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1196,6 +1196,12 @@ static void notify_connected(struct bt_conn *conn) } } + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->connected) { + cb->connected(conn, conn->err); + } + } + if (!conn->err) { bt_gatt_connected(conn); } @@ -1210,6 +1216,12 @@ static void notify_disconnected(struct bt_conn *conn) cb->disconnected(conn, conn->err); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->disconnected) { + cb->disconnected(conn, conn->err); + } + } } #if defined(CONFIG_BT_REMOTE_INFO) @@ -1230,6 +1242,12 @@ void notify_remote_info(struct bt_conn *conn) cb->remote_info_available(conn, &remote_info); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->remote_info_available) { + cb->remote_info_available(conn, &remote_info); + } + } } #endif /* defined(CONFIG_BT_REMOTE_INFO) */ @@ -1255,6 +1273,14 @@ void notify_le_param_updated(struct bt_conn *conn) conn->le.timeout); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->le_param_updated) { + cb->le_param_updated(conn, conn->le.interval, + conn->le.latency, + conn->le.timeout); + } + } } #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE) @@ -1267,6 +1293,12 @@ void notify_le_data_len_updated(struct bt_conn *conn) cb->le_data_len_updated(conn, &conn->le.data_len); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->le_data_len_updated) { + cb->le_data_len_updated(conn, &conn->le.data_len); + } + } } #endif @@ -1280,6 +1312,12 @@ void notify_le_phy_updated(struct bt_conn *conn) cb->le_phy_updated(conn, &conn->le.phy); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->le_phy_updated) { + cb->le_phy_updated(conn, &conn->le.phy); + } + } } #endif @@ -1308,6 +1346,23 @@ bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) } } + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (!cb->le_param_req) { + continue; + } + + if (!cb->le_param_req(conn, param)) { + return false; + } + + /* The callback may modify the parameters so we need to + * double-check that it returned valid parameters. + */ + if (!bt_le_conn_params_valid(param)) { + return false; + } + } + /* Default to accepting if there's no app callback */ return true; } @@ -1734,6 +1789,12 @@ void bt_conn_identity_resolved(struct bt_conn *conn) cb->identity_resolved(conn, rpa, &conn->le.dst); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->identity_resolved) { + cb->identity_resolved(conn, rpa, &conn->le.dst); + } + } } int bt_conn_le_start_encryption(struct bt_conn *conn, uint8_t rand[8], @@ -1833,6 +1894,13 @@ void bt_conn_security_changed(struct bt_conn *conn, uint8_t hci_err, cb->security_changed(conn, conn->sec_level, err); } } + + Z_STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->security_changed) { + cb->security_changed(conn, conn->sec_level, err); + } + } + #if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) if (!err && conn->sec_level >= BT_SECURITY_L2) { if (conn->type == BT_CONN_TYPE_LE) {