diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index d9c7fb8521..f2e2cc18b6 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -427,6 +427,13 @@ if BLE_MESH will store the solicitation src and solicitation sequence number of the received Solicitation PDU message. + config BLE_MESH_PROXY_CLI_SRV_COEXIST + bool "Support Proxy Client and Proxy Server coexistence" + depends on BLE_MESH_EXPERIMENTAL + default n + help + Enable this option to support the coexistence of proxy client and proxy server. + config BLE_MESH_GATT_PROXY_CLIENT bool "BLE Mesh GATT Proxy Client" select BLE_MESH_PROXY @@ -1659,5 +1666,6 @@ if BLE_MESH Experimental features list: - CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG - CONFIG_BLE_MESH_USE_BLE_50 + - CONFIG_BLE_MESH_PROXY_CLI_SRV_COEXIST endif # BLE_MESH diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index d72b83b263..1efb987bb6 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1164,6 +1164,19 @@ static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) /* When connection is created, advertising will be stopped automatically. */ bt_mesh_atomic_test_and_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); #endif + +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + /* Check if this connection is created by Proxy client */ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (!memcmp(bt_mesh_gattc_info[i].addr.val, p_data->conn.remote_bda, BLE_MESH_ADDR_LEN)) { + BT_WARN("Already create connection with %s by proxy client", + bt_hex(p_data->conn.remote_bda, BLE_MESH_ADDR_LEN)); + return; + } + } +#endif if (bt_mesh_gatts_conn_cb != NULL && bt_mesh_gatts_conn_cb->connected != NULL) { uint8_t index = BLE_MESH_GATT_GET_CONN_ID(p_data->conn.conn_id); if (index < BLE_MESH_MAX_CONN) { diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h index 4f28c0d684..cbc59ce513 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -21,13 +21,61 @@ extern "C" { #endif /* BLE Mesh Max Connection Count */ +/** + * The maximum number of connection count is limited by + * the resources allocated by both the host and the controller + * components, so the actual number of available connections + * is the minimum of the resources from both. + * + * On the C3/S3 platform, the controller uses the macro `CONFIG_BT_CTRL_BLE_MAX_ACT`, + * but adv and scan also occupy this resource, so the actual number of available + * connections is (CONFIG_BT_CTRL_BLE_MAX_ACT - adv instance count - scan). + * However, the macro allocation on the host is entirely for connections, + * so on the C3/S3 platform, the maximum number of connectable devices should + * be determined by the configuration at the host minus the number of + * advertising instances and scan from the controller's configuration. +*/ #ifdef CONFIG_BT_BLUEDROID_ENABLED +#if CONFIG_IDF_TARGET_ESP32 +#define BLE_MESH_MAX_CONN 1 +#elif (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3) +/* @todo: must ensure CONFIG_BT_CTRL_BLE_MAX_ACT is greater than 2 */ +#if CONFIG_BT_ACL_CONNECTIONS > (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) +/* decrease the adv,scan */ +#define BLE_MESH_MAX_CONN (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) +#else #define BLE_MESH_MAX_CONN CONFIG_BT_ACL_CONNECTIONS +#endif /* CONFIG_BT_ACL_CONNECTIONS > (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) */ +#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 +#if CONFIG_BT_ACL_CONNECTIONS > CONFIG_BT_LE_MAX_CONNECTIONS +#define BLE_MESH_MAX_CONN CONFIG_BT_LE_MAX_CONNECTIONS +#else +#define BLE_MESH_MAX_CONN CONFIG_BT_ACL_CONNECTIONS +#endif /* CONFIG_BT_ACL_CONNECTIONS > CONFIG_BT_LE_MAX_CONNECTIONS */ +#else +/* default setting */ +#define BLE_MESH_MAX_CONN 1 #endif +#endif /* CONFIG_BT_BLUEDROID_ENABLED */ #ifdef CONFIG_BT_NIMBLE_ENABLED +#if CONFIG_IDF_TARGET_ESP32 +#define BLE_MESH_MAX_CONN 1 +#elif (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3) +/* @todo: must ensure CONFIG_BT_CTRL_BLE_MAX_ACT is greater than 2 */ +#if CONFIG_BT_NIMBLE_MAX_CONNECTIONS > (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) +/* decrease the adv,scan */ +#define BLE_MESH_MAX_CONN (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) +#else #define BLE_MESH_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS +#endif /* CONFIG_BT_NIMBLE_MAX_CONNECTIONS > (CONFIG_BT_CTRL_BLE_MAX_ACT - 2) */ +#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 +#define BLE_MESH_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS +#else +/* default setting */ +#define BLE_MESH_MAX_CONN 1 #endif +#endif /* CONFIG_BT_NIMBLE_ENABLED */ #define BLE_MESH_GAP_ADV_MAX_LEN 31 diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 43f0af2487..d28a99c25f 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -837,6 +837,9 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, uint16_t dst = 0U; int err = 0; + /* The variable is not used when proxy server or proxy client is disabled. */ + ARG_UNUSED(dst); + BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key, buf->len); @@ -914,18 +917,22 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, return err; } - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - bt_mesh_proxy_server_relay(&buf->b, dst) && - BLE_MESH_ADDR_IS_UNICAST(dst)) { + /** + * TODO: Find a way to determine how the message was sent previously + * during a retransmission, to avoid ineffective advertising. + */ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + if (bt_mesh_proxy_server_relay(&buf->b, dst) && + BLE_MESH_ADDR_IS_UNICAST(dst) && + bt_mesh_proxy_server_find_client_by_addr(dst)) { send_cb_finalize(cb, cb_data); return 0; } +#endif - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) && - bt_mesh_proxy_client_relay(&buf->b, dst)) { - send_cb_finalize(cb, cb_data); - return 0; - } +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + bt_mesh_proxy_client_relay(&buf->b, dst); +#endif bt_mesh_adv_send(buf, BLE_MESH_ADV(buf)->xmit, cb, cb_data); return 0; @@ -1052,6 +1059,7 @@ static void bt_mesh_net_adv_xmit_update(struct bt_mesh_net_tx *tx) int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { + const struct bt_mesh_send_cb *send_cb = cb; uint8_t bearer = BLE_MESH_ALL_BEARERS; int err = 0; @@ -1116,40 +1124,48 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, * shall drop all messages secured using the friendship security * credentials." */ - - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - (bearer & BLE_MESH_GATT_BEARER) && - (tx->ctx->send_ttl != 1U || - bt_mesh_tag_relay(tx->ctx->send_tag)) && +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + if ((bearer & BLE_MESH_GATT_BEARER) && + (tx->ctx->send_ttl != 1U || bt_mesh_tag_relay(tx->ctx->send_tag)) && tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_server_relay(&buf->b, tx->ctx->addr) && BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - /** - * When a message is sent to a proxy client, the message - * can be sent via GATT only, eliminating the need for - * an ADV bearer. + /* When the destination address is identified as a proxy client + * address, the message will be sent only to the proxy client. + * This action will enhance the efficiency of the proxy server + * in sending data packets. + * + * It should be noted that this approach does not significantly + * reduce the number of advertising packets in the air, as other + * proxy clients may receive the message and resend it through + * a advertising method. */ if (bt_mesh_proxy_server_find_client_by_addr(tx->ctx->addr)) { - bearer &= ~BLE_MESH_ADV_BEARER; - } + send_cb_finalize(send_cb, cb_data); + send_cb = NULL; - /* Notify completion if this only went - * through the Mesh Proxy. - */ - if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { - send_cb_finalize(cb, cb_data); - - err = 0; goto done; } + /* Finalize transmission if this only went through GATT bearer */ + if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { + send_cb_finalize(send_cb, cb_data); + send_cb = NULL; + +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + /* This message will not be transmitted by proxy client */ + if (!bt_mesh_proxy_client_get_conn_count()) { + goto done; + } +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + } } } +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) && - (bearer & BLE_MESH_GATT_BEARER) && - (tx->ctx->send_ttl != 1U || - bt_mesh_tag_relay(tx->ctx->send_tag)) && +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + if ((bearer & BLE_MESH_GATT_BEARER) && + (tx->ctx->send_ttl != 1U || bt_mesh_tag_relay(tx->ctx->send_tag)) && tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_client_relay(&buf->b, tx->ctx->addr)) { /* If Proxy Client succeeds to send messages with GATT bearer, @@ -1157,45 +1173,43 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, * connection has been created with Proxy Client, here we will * use advertising bearer for the messages. */ - send_cb_finalize(cb, cb_data); + if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { + send_cb_finalize(send_cb, cb_data); + send_cb = NULL; - err = 0; - goto done; + goto done; + } } } +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ /* Deliver to local network interface if necessary */ if (((IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) || (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en())) && (bt_mesh_fixed_group_match(tx->ctx->addr) || bt_mesh_elem_find(tx->ctx->addr))) { - /** - * If the target address isn't a unicast address, then the callback function - * will be called by `adv task` in place of here, to avoid the callback function - * being called twice. + /* If the target address isn't a unicast address, then the callback + * function will be called by mesh adv task instead of called here + * to avoid the callback function being called twice. * See BLEMESH24-76 for more details. */ if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - if (cb && cb->start) { - cb->start(0, 0, cb_data); + if (send_cb && send_cb->start) { + send_cb->start(0, 0, cb_data); } net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); - if (cb && cb->end) { - cb->end(0, cb_data); + if (send_cb && send_cb->end) { + send_cb->end(0, cb_data); } bt_mesh_net_local(); - err = 0; - goto done; - } else { - net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); - bt_mesh_net_local(); } - err = 0; + net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + bt_mesh_net_local(); } if ((bearer & BLE_MESH_ADV_BEARER) && @@ -1217,7 +1231,6 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, BLE_MESH_TRANSMIT_COUNT(tx->xmit), BLE_MESH_TRANSMIT_INT(tx->xmit)); bt_mesh_adv_send(buf, tx->xmit, cb, cb_data); - err = 0; goto done; } @@ -1737,8 +1750,8 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, * shall drop all messages secured using the friendship security * credentials. */ - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - (bearer & BLE_MESH_GATT_BEARER) && +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + if ((bearer & BLE_MESH_GATT_BEARER) && ((bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED && cred != BLE_MESH_FRIENDSHIP_CRED) || #if CONFIG_BLE_MESH_PRB_SRV @@ -1748,11 +1761,14 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED)) { if (bt_mesh_proxy_server_relay(&buf->b, rx->ctx.recv_dst) && BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { + + if (((bearer & (~BLE_MESH_GATT_BEARER)) == 0) || + bt_mesh_proxy_server_find_client_by_addr(rx->ctx.recv_dst)) { goto done; } } } +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ if (((bearer & BLE_MESH_ADV_BEARER) && relay_to_adv(rx->net_if)) || netkey_changed || diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index 2dd9777001..a0651444a5 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -410,7 +410,13 @@ static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, } for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { - if (bt_mesh_gattc_info[i].service_uuid == (uint16_t)BLE_UUID16(uuid)->value) { + /** + * In scenarios with multiple connections, to prevent + * subsequent connections from affecting the first one, + * a check for the connection handle is needed here. + */ + if (bt_mesh_gattc_info[i].conn.handle == conn_handle && + bt_mesh_gattc_info[i].service_uuid == (uint16_t)BLE_UUID16(uuid)->value) { bt_mesh_gattc_info[i].start_handle = service->start_handle; bt_mesh_gattc_info[i].end_handle = service->end_handle; break; @@ -834,6 +840,20 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) /* When connection is created, advertising will be stopped automatically. */ bt_mesh_atomic_test_and_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING); #endif + +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + /* Check if this connection is created by Proxy client */ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { + if (!memcmp(bt_mesh_gattc_info[i].addr.val, desc.peer_id_addr.val, BLE_MESH_ADDR_LEN)) { + BT_WARN("Already create connection with %s by proxy client", + bt_hex(desc.peer_id_addr.val, BLE_MESH_ADDR_LEN)); + return 0; + } + } +#endif + if (bt_mesh_gatts_conn_cb != NULL && bt_mesh_gatts_conn_cb->connected != NULL) { int index = 0; #if CONFIG_BLE_MESH_USE_BLE_50 diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index 8053ac8201..de9ddf50a9 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -1471,6 +1471,9 @@ int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason) if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { prov_link.pb_remote_cbd = true; prov_link.pb_remote_reset = true; + /* @todo: the close reason is disconnect reason, not the + * link close reason, should change it to link close reason? + */ prov_link.pb_remote_close(&prov_link, reason); } #endif diff --git a/components/bt/esp_ble_mesh/core/proxy_client.c b/components/bt/esp_ble_mesh/core/proxy_client.c index 9e9a7354a2..127baa97b4 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.c +++ b/components/bt/esp_ble_mesh/core/proxy_client.c @@ -820,6 +820,23 @@ int bt_mesh_proxy_client_disconnect(uint8_t conn_handle) return 0; } +uint16_t bt_mesh_proxy_client_get_conn_count(void) +{ + uint16_t count = 0; + + for (size_t i = 0; i < ARRAY_SIZE(servers); i++) { + struct bt_mesh_proxy_server *server = &servers[i]; + + if (!server->conn || server->conn_type != CLI_PROXY) { + continue; + } + + count++; + } + + return count; +} + bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst) { bool send = false; diff --git a/components/bt/esp_ble_mesh/core/proxy_client.h b/components/bt/esp_ble_mesh/core/proxy_client.h index ef8db32f6d..6bc0732d3f 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.h +++ b/components/bt/esp_ble_mesh/core/proxy_client.h @@ -104,6 +104,8 @@ int bt_mesh_proxy_client_disconnect(uint8_t conn_handle); bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub, bool private); +uint16_t bt_mesh_proxy_client_get_conn_count(void); + bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst); int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index 65b5dcba63..077050b1e4 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -29,7 +29,7 @@ #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER -#if !CONFIG_BLE_MESH_BQB_TEST +#if !CONFIG_BLE_MESH_BQB_TEST && !CONFIG_BLE_MESH_PROXY_CLI_SRV_COEXIST && !CONFIG_BLE_MESH_RPR_SRV /* Not support enabling Proxy Client and Proxy Server simultaneously */ _Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)), "Not support Proxy Server and Proxy Client simultaneously");