diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 736709fc54..f76f689612 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -515,7 +515,6 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/core/rpl.c" "esp_ble_mesh/core/scan.c" "esp_ble_mesh/core/test.c" - "esp_ble_mesh/core/transport.c" "esp_ble_mesh/models/common/device_property.c" "esp_ble_mesh/models/common/model_common.c" "esp_ble_mesh/models/client/client_common.c" @@ -552,6 +551,12 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c" "esp_ble_mesh/v1.1/ext.c") + + if(CONFIG_BLE_MESH_SAR_ENHANCEMENT) + list(APPEND srcs "esp_ble_mesh/core/transport.enh.c") + else() + list(APPEND srcs "esp_ble_mesh/core/transport.c") + endif() endif() diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index ac5548d140..af76b2240d 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -678,6 +678,13 @@ if BLE_MESH When the above situation is encountered, this option can be used to decide whether to perform the IV index recovery procedure. + config BLE_MESH_SAR_ENHANCEMENT + bool "Segmentation and reassembly enhancement" + default n + help + Enable this option to use the enhanced segmentation and reassembly + mechanism introduced in Bluetooth Mesh Protocol 1.1. + config BLE_MESH_TX_SEG_MSG_COUNT int "Maximum number of simultaneous outgoing segmented messages" default 1 @@ -1091,6 +1098,16 @@ if BLE_MESH help Maximum number of Bridging Table entries that the Bridge Configuration Server can support. + config BLE_MESH_BRIDGE_CRPL + int "Maximum capacity of bridge replay protection list" + default 5 + range 1 255 + help + This option specifies the maximum capacity of the bridge replay + protection list. The bridge replay protection list is used to + prevent a bridged subnet from replay attack, which will store the + source address and sequence number of the received bridge messages. + endif #BLE_MESH_BRC_SRV config BLE_MESH_PRB_CLI @@ -1474,6 +1491,7 @@ if BLE_MESH config BLE_MESH_BQB_TEST bool "Enable BLE Mesh specific internal test" + select BLE_MESH_IV_UPDATE_TEST default n help This option is used to enable some internal functions for auto-pts test. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c index 582ea77557..0365711d86 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c @@ -53,6 +53,34 @@ esp_err_t esp_ble_mesh_proxy_gatt_disable(void) return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +#if CONFIG_BLE_MESH_PRB_SRV +esp_err_t esp_ble_mesh_private_proxy_identity_enable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_ENABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_private_proxy_identity_disable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_DISABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + esp_err_t esp_ble_mesh_proxy_client_connect(esp_ble_mesh_bd_addr_t addr, esp_ble_mesh_addr_type_t addr_type, uint16_t net_idx) diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h index b0f9c82104..66b1e1d4be 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h @@ -48,6 +48,30 @@ esp_err_t esp_ble_mesh_proxy_gatt_enable(void); */ esp_err_t esp_ble_mesh_proxy_gatt_disable(void); +/** + * @brief Enable advertising with Private Node Identity. + * + * @note This API requires that GATT Proxy support be enabled. Once called, + * each subnet starts advertising using Private Node Identity for the + * next 60 seconds, and after 60s Private Network ID will be advertised. + * Under normal conditions, the BLE Mesh Proxy Node Identity, Network + * ID advertising, Proxy Private Node Identity and Private Network + * ID advertising will be enabled automatically by BLE Mesh stack + * after the device is provisioned. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_private_proxy_identity_enable(void); + +/** + * @brief Disable advertising with Private Node Identity. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_private_proxy_identity_disable(void); + /** * @brief Proxy Client creates a connection with the Proxy Server. * diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 37f4bf05dc..744b85c844 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -916,6 +916,8 @@ typedef enum { ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT, /*!< Node input number completion event */ ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT, /*!< Node input string completion event */ ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT, /*!< Enable BLE Mesh Proxy Identity advertising completion event */ + ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_ENABLE_COMP_EVT, /*!< Enable BLE Mesh Private Proxy Identity advertising completion event */ + ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_DISABLE_COMP_EVT, /*!< Disable BLE Mesh Private Proxy Identity advertising completion event */ ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT, /*!< Enable BLE Mesh GATT Proxy Service completion event */ ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT, /*!< Disable BLE Mesh GATT Proxy Service completion event */ ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT, /*!< Node add NetKey locally completion event */ @@ -1109,6 +1111,18 @@ typedef union { struct ble_mesh_proxy_gatt_disable_comp_param { int err_code; /*!< Indicate the result of disabling Mesh Proxy Service */ } node_proxy_gatt_disable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_ENABLE_COMP_EVT + */ + struct ble_mesh_proxy_private_identity_enable_comp_param { + int err_code; /*!< Indicate the result of enabling Mesh Proxy private advertising */ + } node_private_proxy_identity_enable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_ENABLE_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_DISABLE_COMP_EVT + */ + struct ble_mesh_proxy_private_identity_disable_comp_param { + int err_code; /*!< Indicate the result of disabling Mesh Proxy private advertising */ + } node_private_proxy_identity_disable_comp; /*!< Event parameter of ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_DISABLE_COMP_EVT */ /** * @brief ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 826fbf02c1..cbbee08cd4 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -2368,6 +2368,16 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) act = ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT; param.node_proxy_gatt_disable_comp.err_code = bt_mesh_proxy_server_gatt_disable(); break; +#if CONFIG_BLE_MESH_PRB_SRV + case BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_ENABLE: + act = ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_ENABLE_COMP_EVT; + param.node_private_proxy_identity_enable_comp.err_code = bt_mesh_proxy_private_identity_enable(); + break; + case BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_DISABLE: + act = ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_DISABLE_COMP_EVT; + param.node_private_proxy_identity_disable_comp.err_code = bt_mesh_proxy_private_identity_disable(); + break; +#endif /* CONFIG_BLE_MESH_PRB_SRV */ #endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PROVISIONER diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h index efdae7f337..e303f43ab7 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -28,6 +28,8 @@ typedef enum { BTC_BLE_MESH_ACT_INPUT_STRING, BTC_BLE_MESH_ACT_SET_DEVICE_NAME, BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE, + BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_ENABLE, + BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_DISABLE, BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE, BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE, BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_NET_KEY, diff --git a/components/bt/esp_ble_mesh/common/timer.c b/components/bt/esp_ble_mesh/common/timer.c index 74fe3b492e..0d65bd3a10 100644 --- a/components/bt/esp_ble_mesh/common/timer.c +++ b/components/bt/esp_ble_mesh/common/timer.c @@ -207,7 +207,7 @@ int k_delayed_work_free(struct k_delayed_work *work) alarm = hash_map_get(bm_alarm_hash_map, work); if (alarm == NULL) { - BT_WARN("Free, alarm not found"); + BT_DBG("Free, alarm not found"); bt_mesh_alarm_unlock(); return -EINVAL; } diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 531ccd689a..9606581eb8 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -964,6 +964,9 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) ctx.send_ttl = pub->ttl; ctx.send_cred = pub->cred ? BLE_MESH_FRIENDSHIP_CRED : BLE_MESH_FLOODING_CRED; ctx.send_szmic = pub->send_szmic; +#if 0 + ctx.send_tag |= BLE_MESH_TAG_IMMUTABLE_CRED; +#endif if (pub->send_rel) { /* Tag with send-segmented */ ctx.send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index b99d22f2a1..dbbda0ab14 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -32,8 +32,11 @@ /* Pre-5.0 controllers enforce a minimum interval of 100ms * whereas 5.0+ controllers can go down to 20ms. */ -#define ADV_INT_DEFAULT_MS 100 -#define ADV_INT_FAST_MS 20 +#if CONFIG_BLE_MESH_HCI_5_0 +#define ADV_ITVL_MIN 20 +#else +#define ADV_ITVL_MIN 100 +#endif static const uint8_t adv_type[] = { [BLE_MESH_ADV_PROV] = BLE_MESH_DATA_MESH_PROV, @@ -141,10 +144,19 @@ static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, } } +uint16_t bt_mesh_pdu_duration(uint8_t xmit) +{ + uint16_t duration = 0U; + uint16_t adv_int = 0U; + + adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_TRANSMIT_INT(xmit)); + duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + + return duration; +} + static inline int adv_send(struct net_buf *buf) { - const int32_t adv_int_min = ((bt_mesh_dev.hci_version >= BLE_MESH_HCI_VERSION_5_0) ? - ADV_INT_FAST_MS : ADV_INT_DEFAULT_MS); const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; void *cb_data = BLE_MESH_ADV(buf)->cb_data; struct bt_mesh_adv_param param = {0}; @@ -158,7 +170,7 @@ static inline int adv_send(struct net_buf *buf) #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV if (BLE_MESH_ADV(buf)->type != BLE_MESH_ADV_BLE) { #endif - adv_int = MAX(adv_int_min, + adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * (adv_int + 10); @@ -180,7 +192,7 @@ static inline int adv_send(struct net_buf *buf) bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); struct bt_mesh_adv_data solic_ad[3] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), - BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x29, 0x18), + BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x59, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), }; err = bt_le_adv_start(¶m, solic_ad, 3, NULL, 0); diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index 9367f962fd..ab37ec3cda 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -25,6 +25,8 @@ extern "C" { #define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +uint16_t bt_mesh_pdu_duration(uint8_t xmit); + typedef struct bt_mesh_msg { bool relay; /* Flag indicates if the packet is a relayed one */ void *arg; /* Pointer to the struct net_buf */ 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 a9908b7250..68a768c794 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -30,6 +30,7 @@ #include "mesh/common.h" #include "prov_pvnr.h" #include "net.h" +#include "beacon.h" #include "mesh_v1.1/utils.h" @@ -369,7 +370,15 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, } #if CONFIG_BLE_MESH_PRB_SRV - addr_type_own = bt_mesh_private_beacon_update_addr_type(ad); + /* NOTE: When a Mesh Private beacon is advertised, the Mesh Private beacon shall + * use a resolvable private address or a non-resolvable private address in the + * AdvA field of the advertising PDU. + */ + if (ad->type == BLE_MESH_DATA_MESH_BEACON && ad->data[0] == BEACON_TYPE_PRIVATE) { + addr_type_own = BLE_MESH_ADDR_RANDOM; + } else { + addr_type_own = BLE_MESH_ADDR_PUBLIC; + } #else addr_type_own = BLE_MESH_ADDR_PUBLIC; #endif @@ -1978,7 +1987,7 @@ int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) if ((sub_code > BLE_MESH_EXCEP_LIST_SUB_CODE_CLEAN) || (sub_code < BLE_MESH_EXCEP_LIST_SUB_CODE_CLEAN && - type > BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV) || + type >= BLE_MESH_EXCEP_LIST_TYPE_MAX) || (sub_code == BLE_MESH_EXCEP_LIST_SUB_CODE_CLEAN && !(type & BLE_MESH_EXCEP_LIST_CLEAN_ALL_LIST))) { BT_ERR("%s, Invalid parameter", __func__); @@ -1990,6 +1999,16 @@ int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) BT_ERR("Invalid Provisioning Link ID"); return -EINVAL; } + + /* When removing an unused link (i.e., Link ID is 0), and since + * Controller has never added this Link ID, it will cause error + * log been wrongly reported. + * Therefore, add this check here to avoid such occurrences. + */ + if (*(uint32_t *)info == 0) { + return 0; + } + sys_memcpy_swap(value, info, sizeof(uint32_t)); } diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index 614387405c..9d91cb217b 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -2514,7 +2514,7 @@ static void node_identity_set(struct bt_mesh_model *model, * any subnet is 0x01, then the value of the Private Node * Identity state shall be Disable (0x00). */ - disable_all_private_node_identity(); + bt_mesh_proxy_private_identity_disable(); #endif bt_mesh_proxy_server_identity_start(sub); } else { @@ -3575,6 +3575,17 @@ uint8_t bt_mesh_net_transmit_get(void) return 0; } +void bt_mesh_relay_local_set(bool enable) +{ + if (conf && conf->relay != BLE_MESH_RELAY_NOT_SUPPORTED) { + if (enable) { + conf->relay = BLE_MESH_RELAY_ENABLED; + } else { + conf->relay = BLE_MESH_RELAY_DISABLED; + } + } +} + uint8_t bt_mesh_relay_get(void) { if (conf) { diff --git a/components/bt/esp_ble_mesh/core/foundation.h b/components/bt/esp_ble_mesh/core/foundation.h index 0a07e70b02..4f3aa79ad1 100644 --- a/components/bt/esp_ble_mesh/core/foundation.h +++ b/components/bt/esp_ble_mesh/core/foundation.h @@ -246,10 +246,10 @@ extern "C" { /* Defines the status codes for Opcodes Aggregator messages. */ #define AGG_STATUS_SUCCESS 0x00 #define AGG_STATUS_INVALID_ADDRESS 0x01 -#define AGG_STATUS_INVALID_MODEL 0x02 -#define AGG_STATUS_WRONG_ACCESS_KEY 0x03 -#define AGG_STATUS_WRONG_OPCODE 0x04 -#define AGG_STATUS_MSG_NOT_UNDERSTOOD 0x05 +#define AGG_STATUS_WRONG_ACCESS_KEY 0x02 +#define AGG_STATUS_WRONG_OPCODE 0x03 +#define AGG_STATUS_MSG_NOT_UNDERSTOOD 0x04 +#define AGG_STATUS_RESPONSE_OVERFLOW 0x05 enum { BLE_MESH_VA_CHANGED, /* Label information changed */ diff --git a/components/bt/esp_ble_mesh/core/include/mesh/access.h b/components/bt/esp_ble_mesh/core/include/mesh/access.h index 1b78cbd416..ed42ed75f7 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/access.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/access.h @@ -4,7 +4,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ 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 431fc72cfe..e1b8af79bf 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -810,6 +810,9 @@ enum { BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV, + BLE_MESH_EXCEP_LIST_TYPE_MESH_SOLIC_PDU, + BLE_MESH_EXCEP_LIST_TYPE_MESH_URI, + BLE_MESH_EXCEP_LIST_TYPE_MAX, }; #define BLE_MESH_EXCEP_LIST_CLEAN_ADDR_LIST BIT(0) @@ -817,8 +820,10 @@ enum { #define BLE_MESH_EXCEP_LIST_CLEAN_MESH_BEACON_LIST BIT(2) #define BLE_MESH_EXCEP_LIST_CLEAN_MESH_PROV_ADV_LIST BIT(3) #define BLE_MESH_EXCEP_LIST_CLEAN_MESH_PROXY_ADV_LIST BIT(4) -#define BLE_MESH_EXCEP_LIST_CLEAN_ALL_LIST (BIT(0) | BIT(1) | \ - BIT(2) | BIT(3) | BIT(4)) +#define BLE_MESH_EXCEP_LIST_CLEAN_MESH_SOLIC_PDU_LIST BIT(5) +#define BLE_MESH_EXCEP_LIST_CLEAN_MESH_URI_LIST BIT(6) +#define BLE_MESH_EXCEP_LIST_CLEAN_ALL_LIST (BIT(0) | BIT(1) | BIT(2) | BIT(3) | \ + BIT(4) | BIT(5) | BIT(6)) int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info); diff --git a/components/bt/esp_ble_mesh/core/include/mesh/cfg_srv.h b/components/bt/esp_ble_mesh/core/include/mesh/cfg_srv.h index 99c67eab49..dc46c19041 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/cfg_srv.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/cfg_srv.h @@ -212,6 +212,8 @@ typedef union { } cfg_net_transmit_set; } bt_mesh_cfg_server_state_change_t; +void bt_mesh_relay_local_set(bool enable); + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/core/include/mesh/uuid.h b/components/bt/esp_ble_mesh/core/include/mesh/uuid.h index bd63b84d86..bea37c6ef4 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/uuid.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/uuid.h @@ -141,6 +141,11 @@ struct bt_mesh_uuid_128 { */ #define BLE_MESH_UUID_MESH_PROXY BLE_MESH_UUID_DECLARE_16(0x1828) #define BLE_MESH_UUID_MESH_PROXY_VAL 0x1828 +/** @def BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL + * @brief Mesh Proxy Solicitation UUID + */ +#define BLE_MESH_UUID_MESH_PROXY_SOLIC BLE_MESH_UUID_DECLARE_16(0x1859) +#define BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL 0x1859 /** @def BLE_MESH_UUID_GATT_PRIMARY * @brief GATT Primary Service */ @@ -466,10 +471,6 @@ struct bt_mesh_uuid_128 { */ #define BLE_MESH_UUID_MESH_PROXY_DATA_OUT BLE_MESH_UUID_DECLARE_16(0x2ade) #define BLE_MESH_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade -/** @def BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL - * @brief Mesh Proxy Solicitation UUID - */ -#define BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL 0x7fcb /* * Protocol UUIDs diff --git a/components/bt/esp_ble_mesh/core/local.c b/components/bt/esp_ble_mesh/core/local.c index b8bcfffa55..4451e0d7b2 100644 --- a/components/bt/esp_ble_mesh/core/local.c +++ b/components/bt/esp_ble_mesh/core/local.c @@ -148,10 +148,9 @@ int bt_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwardin return 0; } +#endif /* CONFIG_BLE_MESH_DF_SRV */ -#endif #if CONFIG_BLE_MESH_NODE - const uint8_t *bt_mesh_node_get_local_net_key(uint16_t net_idx) { struct bt_mesh_subnet *sub = NULL; @@ -369,5 +368,4 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, BT_ERR("Model bound is full!"); return -ENOMEM; } - #endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/esp_ble_mesh/core/lpn.c b/components/bt/esp_ble_mesh/core/lpn.c index 98c24a323b..f445be5632 100644 --- a/components/bt/esp_ble_mesh/core/lpn.c +++ b/components/bt/esp_ble_mesh/core/lpn.c @@ -238,6 +238,20 @@ static void clear_friendship(bool force, bool disable) lpn_cb(lpn->frnd, false); } + /* If the Low Power node supports directed forwarding functionality when + * the friendship is established in a subnet, the Low Power node shall + * store the current value of the Directed Forwarding state and shall set + * the state to 0x00 for that subnet. When that friendship is terminated, + * the Low Power node shall set the Directed Forwarding state to the stored + * value. + */ +#if CONFIG_BLE_MESH_DF_SRV + if (lpn->established) { + bt_mesh_restore_directed_forwarding_state(bt_mesh.sub[0].net_idx, + lpn->old_directed_forwarding); + } +#endif + lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; lpn->fsn = 0U; lpn->req_attempts = 0U; @@ -1027,9 +1041,9 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, * the Low Power node shall set the Directed Forwarding state to the stored * value. */ - /* TODO: - * Store - clear - restore directed forwarding state value of the subnet. - */ +#if CONFIG_BLE_MESH_DF_SRV + lpn->old_directed_forwarding = bt_mesh_get_and_disable_directed_forwarding_state(sub); +#endif } friend_response_received(lpn); diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 072768fca5..340cf7d7ac 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -606,6 +606,13 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) case BLE_MESH_KR_PHASE_2: BT_INFO("KR Phase 0x%02x -> Normal", sub->kr_phase); +#if CONFIG_BLE_MESH_PRB_SRV + /* In this case, consider that kr_flag has changed, so + * need to modify the content of the random field. + */ + bt_mesh_private_beacon_update_random(sub); +#endif + sub->kr_phase = BLE_MESH_KR_NORMAL; bt_mesh_net_revoke_keys(sub); @@ -669,13 +676,26 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) { int i; + /* If a node in Normal Operation receives a Secure Network beacon or + * a Mesh Private beacon with an IV index less than the last known + * IV Index or greater than the last known IV Index + 42, the Secure + * Network beacon or the Mesh Private beacon shall be ignored. + */ + if (iv_index < bt_mesh.iv_index || + iv_index > bt_mesh.iv_index + 42) { + BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", + iv_index, bt_mesh.iv_index); + return false; + } + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { /* We're currently in IV Update mode */ - - if (iv_index != bt_mesh.iv_index) { - BT_WARN("IV Index mismatch: 0x%08x != 0x%08x", - iv_index, bt_mesh.iv_index); - return false; + if (iv_index >= bt_mesh.iv_index + 1) { + BT_WARN("Performing IV Index Recovery"); + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); + bt_mesh.iv_index = iv_index; + bt_mesh.seq = 0U; + goto do_update; } if (iv_update) { @@ -691,18 +711,6 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } - /* If a node in Normal Operation receives a Secure Network beacon or - * a Mesh Private beacon with an IV index less than the last known - * IV Index or greater than the last known IV Index + 42, the Secure - * Network beacon or the Mesh Private beacon shall be ignored. - */ - if (iv_index < bt_mesh.iv_index || - iv_index > bt_mesh.iv_index + 42) { - BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", - iv_index, bt_mesh.iv_index); - return false; - } - /* If a node in Normal Operation receives a Secure Network beacon * or a Mesh Private beacon with an IV index greater than the * last known IV Index + 1, it may initiate an IV Index Recovery @@ -1027,6 +1035,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, tx->ctx->send_ttl = bt_mesh_default_ttl_get(); } +#if 0 /* The output filter of the interface connected to advertising * or GATT bearers shall drop all messages with the TTL value * set to 1 unless they contain a network PDU that is tagged @@ -1038,6 +1047,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, err = -EIO; goto done; } +#endif /* Spec: * If the message security material is not set by the network @@ -1246,7 +1256,7 @@ int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, rx->ctx.addr = BLE_MESH_NET_HDR_SRC(buf->data); if (!BLE_MESH_ADDR_IS_UNICAST(rx->ctx.addr)) { - BT_INFO("Ignoring non-unicast src addr 0x%04x", rx->ctx.addr); + BT_DBG("Ignoring non-unicast src addr 0x%04x", rx->ctx.addr); return -EINVAL; } @@ -1397,7 +1407,8 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) case BLE_MESH_NET_IF_ADV: return (bt_mesh_relay_get() == BLE_MESH_RELAY_ENABLED); case BLE_MESH_NET_IF_PROXY: - return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED); + return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED || + bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED); default: return false; } @@ -1465,6 +1476,13 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, return; } +#if CONFIG_BLE_MESH_BRC_SRV + if (rx->sbr_rpl) { + BT_ERR("Bridge RPL attack"); + goto done; + } +#endif + if (cred != BLE_MESH_FLOODING_CRED #if CONFIG_BLE_MESH_DF_SRV && cred != BLE_MESH_DIRECTED_CRED @@ -1474,8 +1492,13 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, return; } - if (rx->ctx.recv_ttl == 0x01 && bt_mesh_tag_relay(tag) == false) { - BT_DBG("Ignore PDU with TTL=1 but not tagged as relay"); + if (rx->ctx.recv_ttl == 0x01) { + BT_DBG("Ignore PDU with TTL = 1"); + return; + } + + if (rx->ctx.recv_ttl == 0x02 && bt_mesh_tag_relay(tag) == false) { + BT_DBG("Ignore PDU with TTL = 2 but not tagged as relay"); return; } @@ -1553,10 +1576,11 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, BT_DBG("Relaying packet. TTL is now %u", BLE_MESH_NET_HDR_TTL(buf->data)); - /* 1. Update NID if RX or RX was with friend credentials. + /* 1. Update NID if RX or RX was with friend credentials(included by case 3). * 2. Update NID if the net_key has changed. + * 3. Update NID if credential has changed. */ - if (rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED || netkey_changed) { + if (netkey_changed || cred != rx->ctx.recv_cred) { buf->data[0] &= 0x80; /* Clear everything except IVI */ buf->data[0] |= nid; } @@ -1600,19 +1624,6 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (((bearer & BLE_MESH_ADV_BEARER) && relay_to_adv(rx->net_if)) || netkey_changed || rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED) { - /* NOTE: temporary add for case MESH/NODE/SBR/NET/BV-01-C */ -#if CONFIG_BLE_MESH_BRC_SRV - if (bt_mesh_bridge_rpl_check(rx, NULL) && netkey_changed) { - BT_ERR("It is RPL attack, not bridge"); - /** - * @todo:/NODE/DF/INIT/BV-TBD-C, - * The message from LT2 was double-checked, - * so the message was mistaken for an RPL attack. - */ - goto done; - } -#endif - #if !CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_adv_send(buf, xmit, NULL, NULL); #else diff --git a/components/bt/esp_ble_mesh/core/net.h b/components/bt/esp_ble_mesh/core/net.h index b9dfb42dda..60ca5dc6ab 100644 --- a/components/bt/esp_ble_mesh/core/net.h +++ b/components/bt/esp_ble_mesh/core/net.h @@ -58,7 +58,6 @@ struct bt_mesh_subnet { uint8_t mpb_flags_last; /* Flags of last sent private beacon */ uint8_t mpb_ivi_last: 1; /* IV Index of last sent private beacon */ uint8_t mpb_random[13]; /* Random of current private beacon */ - uint8_t mpb_random_last[13]; /* Random of last sent private beacon */ uint8_t private_node_id; /* Private Node Identity State */ #endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ @@ -274,6 +273,10 @@ struct bt_mesh_lpn { /* Previous Friend of this LPN */ uint16_t old_friend; +#if CONFIG_BLE_MESH_DF_SRV + uint8_t old_directed_forwarding; +#endif + /* Duration reported for last advertising packet */ uint16_t adv_duration; @@ -381,13 +384,14 @@ struct bt_mesh_net_rx { struct bt_mesh_subnet *sub; struct bt_mesh_msg_ctx ctx; uint32_t seq; /* Sequence Number */ - uint8_t old_iv:1, /* iv_index - 1 was used */ + uint16_t old_iv:1, /* iv_index - 1 was used */ new_key:1, /* Data was encrypted with updated key */ friend_cred:1 __attribute__((deprecated)), /* Data was encrypted with friend cred */ ctl:1, /* Network Control */ net_if:2, /* Network interface */ local_match:1, /* Matched a local element */ - friend_match:1; /* Matched an LPN we're friends for */ + friend_match:1, /* Matched an LPN we're friends for */ + sbr_rpl:1; /* Bridge RPL attacker */ uint16_t msg_cache_idx; /* Index of entry in message cache */ }; @@ -406,7 +410,7 @@ extern struct bt_mesh_net bt_mesh; #define BLE_MESH_NET_IVI_TX (bt_mesh.iv_index - \ bt_mesh_atomic_test_bit(bt_mesh.flags, \ - BLE_MESH_IVU_IN_PROGRESS)) + BLE_MESH_IVU_IN_PROGRESS)) #define BLE_MESH_NET_IVI_RX(rx) (bt_mesh.iv_index - (rx)->old_iv) #define BLE_MESH_NET_HDR_LEN 9 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 eec69f1080..806f4e0eb5 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -1958,6 +1958,16 @@ int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) BT_ERR("Invalid Provisioning Link ID"); return -EINVAL; } + + /* When removing an unused link (i.e., Link ID is 0), and since + * Controller has never added this Link ID, it will cause error + * log been wrongly reported. + * Therefore, add this check here to avoid such occurrences. + */ + if (*(uint32_t *)info == 0) { + return 0; + } + sys_memcpy_swap(value, info, sizeof(uint32_t)); } diff --git a/components/bt/esp_ble_mesh/core/prov_common.h b/components/bt/esp_ble_mesh/core/prov_common.h index 4671b07f21..561712ef14 100644 --- a/components/bt/esp_ble_mesh/core/prov_common.h +++ b/components/bt/esp_ble_mesh/core/prov_common.h @@ -62,8 +62,8 @@ extern "C" { #define REC_RSP_REC_NOT_PRESENT 0x01 #define REC_RSP_OFFSET_OUT_OF_BOUND 0x02 -#define CERT_BASED_PROV_SUPPORT(oob) ((oob) & BIT_MASK(7)) -#define PROV_REC_SUPPORT(oob) ((oob) & BIT_MASK(8)) +#define CERT_BASED_PROV_SUPPORT(oob) ((oob) & BIT(7)) +#define PROV_REC_SUPPORT(oob) ((oob) & BIT(8)) #if CONFIG_BLE_MESH_PROV_EPA #define PROV_ENC_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index c6902333ed..50811a3082 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -371,8 +371,7 @@ static int provisioner_start_prov_pb_adv(const uint8_t uuid[16], const bt_mesh_a for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { if (!bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && - !bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_CLOSING) - ) { + !bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_CLOSING)) { memcpy(prov_links[i].uuid, uuid, 16); prov_links[i].oob_info = oob_info; if (addr) { @@ -1070,14 +1069,24 @@ static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) static void send_link_open(struct bt_mesh_prov_link *link) { + uint8_t count; int i; - /* Generate link ID, and may need to check if this id is - * currently being used, which may will not happen ever. - */ - bt_mesh_rand(&link->link_id, sizeof(link->link_id)); + link->link_id = 0; while (1) { + count = 0; + + /* Make sure the generated Link ID is not 0 */ + while(link->link_id == 0) { + bt_mesh_rand(&link->link_id, sizeof(link->link_id)); + if (count++ > 10) { + BT_ERR("Link ID error: all zero"); + return; + } + } + + /* Check if the generated Link ID is the same with other links */ for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && prov_links[i].link_id == link->link_id) { @@ -1085,6 +1094,7 @@ static void send_link_open(struct bt_mesh_prov_link *link) break; } } + if (i == CONFIG_BLE_MESH_PBA_SAME_TIME) { break; } @@ -3037,8 +3047,8 @@ void bt_mesh_provisioner_prov_adv_recv(struct net_buf_simple *buf, uuid = buf->data; net_buf_simple_pull(buf, 16); - /* Mesh beacon uses big-endian to send beacon data */ - oob_info = net_buf_simple_pull_be16(buf); + /* According CSS, all the field within adv data shall be little-endian */ + oob_info = net_buf_simple_pull_le16(buf); if (provisioner_check_unprov_dev_info(uuid, BLE_MESH_PROV_GATT)) { return; diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index aa360b85f8..020793dc6e 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -35,7 +35,8 @@ _Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CON #define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) -#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && \ + (CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) #define RAND_UPDATE_INTERVAL K_MINUTES(10) /* The Random field of Private Network Identity @@ -438,12 +439,12 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne #if CONFIG_BLE_MESH_PROXY_PRIVACY if (client->proxy_privacy == BLE_MESH_PROXY_PRIVACY_ENABLED) { - bt_mesh_private_beacon_create(sub, &buf); - /* NOTE: Each time a Mesh Private beacon for a subnet is sent to a Proxy Client, * the Random field in the Mesh Private beacon shall be regenerated. */ bt_mesh_private_beacon_update_random(sub); + + bt_mesh_private_beacon_create(sub, &buf); } else #endif { @@ -476,22 +477,9 @@ static void proxy_send_beacons(struct k_work *work) for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; -#if 0 - if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED || - sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { - sub->proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED; - } else if (true) { -#if CONFIG_BLE_MESH_PRB_SRV - /* TODO: Check if Private GATT Proxy or Private Node Identity is enabled */ -#endif - sub->proxy_privacy = BLE_MESH_PROXY_PRIVACY_ENABLED; - } else { - sub->proxy_privacy = BLE_MESH_PROXY_PRIVACY_NOT_SUPPORTED; - } -#endif - if (sub->net_idx != BLE_MESH_KEY_UNUSED) { beacon_send(client, sub); + #if CONFIG_BLE_MESH_DF_SRV if (sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { bt_mesh_directed_proxy_server_directed_proxy_caps_status_send(client->conn, sub); @@ -630,16 +618,58 @@ static bool is_exist_private_node_id_enable(void) return false; } -void disable_all_private_node_identity(void) +int bt_mesh_proxy_private_identity_disable(void) { + if (!bt_mesh_is_provisioned()) { + return -EAGAIN; + } + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { /* NOTE: Set private node identity state of all valid subnets disabled */ struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - if (sub->net_idx != BLE_MESH_KEY_UNUSED) { - bt_mesh_proxy_server_private_identity_stop(sub); + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; } + + if (sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED) { + continue; + } + + bt_mesh_proxy_server_private_identity_stop(sub); } + + return 0; +} + +int bt_mesh_proxy_private_identity_enable(void) +{ + int count = 0; + + if (!bt_mesh_is_provisioned()) { + return -EAGAIN; + } + + for (size_t i = 0U; i < ARRAY_SIZE(bt_mesh.sub); i++) { + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { + continue; + } + + if (sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED) { + continue; + } + + bt_mesh_proxy_server_private_identity_start(sub); + count++; + } + + if (count) { + bt_mesh_adv_update(); + } + + return 0; } #endif /* CONFIG_BLE_MESH_PRB_SRV */ #endif /* GATT_PROXY */ @@ -1373,7 +1403,7 @@ static const struct bt_mesh_adv_data net_id_ad[] = { BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), }; -#if CONFIG_BLE_MESH_PRB_SRV +#if CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX static const struct bt_mesh_adv_data private_node_id_ad[] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x28, 0x18), @@ -1533,23 +1563,6 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) return 0; } - -void bt_mesh_prb_pnid_adv_local_set(bool start) -{ - for (size_t i = 0U; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BLE_MESH_KEY_UNUSED) { - continue; - } - - if (start) { - bt_mesh_proxy_server_private_identity_start(sub); - } else { - bt_mesh_proxy_server_private_identity_stop(sub); - } - } -} #endif /* CONFIG_BLE_MESH_PRB_SRV */ #if (CONFIG_BLE_MESH_PRB_SRV || \ @@ -1751,7 +1764,8 @@ static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) } memcpy(prov_svc_data + 2, bt_mesh_prov_get()->uuid, 16); - sys_put_be16(bt_mesh_prov_get()->oob_info, prov_svc_data + 18); + /* According CSS, all the field within adv data shall be little-endian */ + sys_put_le16(bt_mesh_prov_get()->oob_info, prov_svc_data + 18); if (bt_mesh_prov_get()->uri) { size_t uri_len = strlen(bt_mesh_prov_get()->uri); diff --git a/components/bt/esp_ble_mesh/core/proxy_server.h b/components/bt/esp_ble_mesh/core/proxy_server.h index 5ae0a08126..b98728910d 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.h +++ b/components/bt/esp_ble_mesh/core/proxy_server.h @@ -107,9 +107,9 @@ void bt_mesh_disable_private_gatt_proxy(void); bool bt_mesh_proxy_server_is_node_id_enable(void); -void disable_all_private_node_identity(void); +int bt_mesh_proxy_private_identity_disable(void); -void bt_mesh_prb_pnid_adv_local_set(bool start); +int bt_mesh_proxy_private_identity_enable(void); #endif /* CONFIG_BLE_MESH_PRB_SRV */ void bt_mesh_proxy_server_identity_start(struct bt_mesh_subnet *sub); diff --git a/components/bt/esp_ble_mesh/core/rpl.c b/components/bt/esp_ble_mesh/core/rpl.c index cbf763bd01..2b44350805 100644 --- a/components/bt/esp_ble_mesh/core/rpl.c +++ b/components/bt/esp_ble_mesh/core/rpl.c @@ -87,11 +87,6 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) return rpl_check_and_store(rx, match); } -bool bt_mesh_bridge_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) -{ - return rpl_check_and_store(rx, match); -} - void bt_mesh_rpl_update(void) { /* Discard "old old" IV Index entries from RPL and flag diff --git a/components/bt/esp_ble_mesh/core/rpl.h b/components/bt/esp_ble_mesh/core/rpl.h index ae4e49f734..cb6fef5e82 100644 --- a/components/bt/esp_ble_mesh/core/rpl.h +++ b/components/bt/esp_ble_mesh/core/rpl.h @@ -20,8 +20,6 @@ void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx); bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); -bool bt_mesh_bridge_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); - void bt_mesh_rpl_update(void); void bt_mesh_rpl_reset_single(uint16_t src, bool erase); diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 785dc1c543..64ac566ace 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -90,7 +90,7 @@ static struct seg_tx { uint8_t tag; /* Additional metadata */ const struct bt_mesh_send_cb *cb; void *cb_data; - struct k_delayed_work retransmit; /* Retransmit timer */ + struct k_delayed_work rtx_timer; /* Segment Retransmission timer */ } seg_tx[CONFIG_BLE_MESH_TX_SEG_MSG_COUNT]; static struct seg_rx { @@ -106,7 +106,7 @@ static struct seg_rx { uint16_t dst; uint32_t block; uint32_t last; - struct k_delayed_work ack; + struct k_delayed_work ack_timer; struct net_buf_simple buf; } seg_rx[CONFIG_BLE_MESH_RX_SEG_MSG_COUNT] = { [0 ... (CONFIG_BLE_MESH_RX_SEG_MSG_COUNT - 1)] = { @@ -145,7 +145,7 @@ uint8_t bt_mesh_get_seg_rtx_num(void) return SEG_RETRANSMIT_ATTEMPTS; } -int32_t bt_mesh_get_seg_rtx_timeout(uint8_t ttl) +int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) { /* This function will be used when a client model sending an * acknowledged message. And if the dst of a message is not @@ -322,7 +322,7 @@ static void seg_tx_reset(struct seg_tx *tx) bt_mesh_seg_tx_lock(); - k_delayed_work_cancel(&tx->retransmit); + k_delayed_work_cancel(&tx->rtx_timer); tx->cb = NULL; tx->cb_data = NULL; @@ -360,6 +360,8 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) seg_tx_reset(tx); + /* TODO: notify the completion of sending segmented message */ + if (cb && cb->end) { cb->end(err, cb_data); } @@ -377,7 +379,7 @@ static void schedule_retransmit(struct seg_tx *tx) return; } - k_delayed_work_submit(&tx->retransmit, SEG_RETRANSMIT_TIMEOUT(tx)); + k_delayed_work_submit(&tx->rtx_timer, SEG_RETRANSMIT_TIMEOUT(tx)); } static void seg_first_send_start(uint16_t duration, int err, void *user_data) @@ -471,7 +473,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) static void seg_retransmit(struct k_work *work) { - struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, retransmit); + struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, rtx_timer); seg_tx_send_unacked(tx); } @@ -511,10 +513,6 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, } tx->dst = net_tx->ctx->addr; - /* TODO: - * When SAR Transmitter is introduced, the xmit may be - * updated with "bt_mesh_get_sar_seg_transmit()". - */ if (sdu->len) { tx->seg_n = (sdu->len - 1) / seg_len(!!ctl_op); } else { @@ -784,6 +782,12 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, rx->ctl, rx->ctx.recv_ttl, rx->ctx.addr, rx->ctx.recv_dst, bt_hex(sdu->data, sdu->len)); + /* When the Device Key Candidate is available, and an access message + * is decrypted using the Device Key Candidate that was delivered to + * the access layer, then the node shall revoke the device key, the + * Device Key Candidate shall become the device key, and the Device + * Key Candidate shall become unavailable. + */ revoke_dev_key(dev_key); rx->ctx.app_idx = BLE_MESH_KEY_DEV; @@ -942,7 +946,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return -EINVAL; } - k_delayed_work_cancel(&tx->retransmit); + k_delayed_work_cancel(&tx->rtx_timer); while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { @@ -1216,11 +1220,9 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { - BT_DBG("rx %p", rx); - bt_mesh_seg_rx_lock(); - k_delayed_work_cancel(&rx->ack); + k_delayed_work_cancel(&rx->ack_timer); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->obo && rx->block != BLOCK_COMPLETE(rx->seg_n)) { @@ -1267,9 +1269,7 @@ static uint32_t incomplete_timeout(struct seg_rx *rx) static void seg_ack(struct k_work *work) { - struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack); - - BT_DBG("rx %p", rx); + struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); bt_mesh_seg_rx_lock(); @@ -1291,14 +1291,14 @@ static void seg_ack(struct k_work *work) send_ack(rx->sub, rx->dst, rx->src, rx->ttl, &rx->seq_auth, rx->block, rx->obo); - k_delayed_work_submit(&rx->ack, ack_timeout(rx)); + k_delayed_work_submit(&rx->ack_timer, ack_timeout(rx)); bt_mesh_seg_rx_unlock(); } static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) { - return ((seg_n * seg_len(ctl) + 1) <= CONFIG_BLE_MESH_RX_SDU_MAX); + return ((seg_n + 1) * seg_len(ctl) <= CONFIG_BLE_MESH_RX_SDU_MAX); } static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, @@ -1568,9 +1568,9 @@ found_rx: /* Reset the Incomplete Timer */ rx->last = k_uptime_get_32(); - if (!k_delayed_work_remaining_get(&rx->ack) && + if (!k_delayed_work_remaining_get(&rx->ack_timer) && !bt_mesh_lpn_established()) { - k_delayed_work_submit(&rx->ack, ack_timeout(rx)); + k_delayed_work_submit(&rx->ack_timer, ack_timeout(rx)); } /* Location in buffer can be calculated based on seg_o & rx->ctl */ @@ -1594,7 +1594,7 @@ found_rx: *pdu_type = BLE_MESH_FRIEND_PDU_COMPLETE; - k_delayed_work_cancel(&rx->ack); + k_delayed_work_cancel(&rx->ack_timer); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1754,11 +1754,11 @@ void bt_mesh_trans_init(void) bt_mesh_sar_init(); for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); + k_delayed_work_init(&seg_tx[i].rtx_timer, seg_retransmit); } for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_delayed_work_init(&seg_rx[i].ack, seg_ack); + k_delayed_work_init(&seg_rx[i].ack_timer, seg_ack); seg_rx[i].buf.__buf = (seg_rx_buf_data + (i * CONFIG_BLE_MESH_RX_SDU_MAX)); seg_rx[i].buf.data = seg_rx[i].buf.__buf; @@ -1778,11 +1778,11 @@ void bt_mesh_trans_deinit(bool erase) bt_mesh_rpl_reset(erase); for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_delayed_work_free(&seg_tx[i].retransmit); + k_delayed_work_free(&seg_tx[i].rtx_timer); } for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_delayed_work_free(&seg_rx[i].ack); + k_delayed_work_free(&seg_rx[i].ack_timer); } bt_mesh_mutex_free(&seg_tx_lock); diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c new file mode 100644 index 0000000000..4951c58290 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -0,0 +1,2344 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "lpn.h" +#include "rpl.h" +#include "friend.h" +#include "access.h" +#include "foundation.h" +#include "settings.h" +#include "transport.h" +#include "mesh/main.h" +#include "fast_prov.h" +#include "mesh/common.h" +#include "mesh/cfg_srv.h" +#include "heartbeat.h" + +#include "mesh_v1.1/utils.h" + +/* The transport layer needs at least three buffers for itself to avoid + * deadlocks. Ensure that there are a sufficient number of advertising + * buffers available compared to the maximum supported outgoing segment + * count. + */ +_Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3), + "Too small BLE Mesh adv buffer count"); + +#define AID_MASK ((uint8_t)(BIT_MASK(6))) + +#define SEG(data) ((data)[0] >> 7) +#define AKF(data) (((data)[0] >> 6) & 0x01) +#define AID(data) ((data)[0] & AID_MASK) +#define ASZMIC(data) (((data)[1] >> 7) & 1) + +#define APP_MIC_LEN(aszmic) ((aszmic) ? BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT) + +#define UNSEG_HDR(akf, aid) ((akf << 6) | (aid & AID_MASK)) +#define SEG_HDR(akf, aid) (UNSEG_HDR(akf, aid) | 0x80) + +#define BLOCK_COMPLETE(seg_n) (uint32_t)(((uint64_t)1 << (seg_n + 1)) - 1) + +#define SEQ_AUTH(iv_index, seq) (((uint64_t)iv_index) << 24 | (uint64_t)seq) + +/* How long to wait for available buffers before giving up */ +#define BUF_TIMEOUT K_NO_WAIT + +static struct seg_tx { + struct bt_mesh_subnet *sub; + struct net_buf *seg[CONFIG_BLE_MESH_TX_SEG_MAX]; + uint64_t seq_auth; + uint8_t hdr; + uint16_t src; + uint16_t dst; + uint16_t app_idx; + uint8_t xmit; /* Segment transmit */ + uint8_t aszmic:1; /* MIC size */ + uint8_t ttl; /* TTL */ + uint8_t cred; /* Security credentials */ + uint8_t tag; /* Additional metadata */ + uint16_t len; + uint8_t nack_count; /* Number of unacked segs */ + uint32_t seg_n:5, /* Last segment index */ + last_seg_n:5, /* Last transmitted segment index */ + lsn_updated:1, /* Last transmitted segment index updated */ + surc:4, /* SAR Unicast Retransmission Count */ + surwpc:4, /* SAR Unicast Retransmission Without Progress Count + * (i.e., without newly marking any segment as acknowledged) + */ + smrc:4, /* SAR Multicast Retransmission Count */ + new_key:1, /* New/Old Key */ + ctl:1, /* Control packet */ + resend:1; /* Segments are been retransmitted */ + const struct bt_mesh_send_cb *cb; + void *cb_data; + struct k_delayed_work seg_timer; /* Segment Interval timer */ + struct k_delayed_work rtx_timer; /* Segment Retransmission timer */ +} seg_tx[CONFIG_BLE_MESH_TX_SEG_MSG_COUNT]; + +static struct seg_rx { + struct bt_mesh_subnet *sub; + uint64_t seq_auth; + uint16_t seg_n:5, + ctl:1, + in_use:1, + obo:1, + new_seg:1, /* Indicate if a new segment is just received */ + sarc:2; /* SAR ACK Retransmissions Count */ + uint8_t hdr; + uint8_t ttl; + uint16_t src; + uint16_t dst; + uint32_t block; + uint32_t last_ack; + struct k_delayed_work ack_timer; + struct k_delayed_work dis_timer; + struct net_buf_simple buf; +} seg_rx[CONFIG_BLE_MESH_RX_SEG_MSG_COUNT] = { + [0 ... (CONFIG_BLE_MESH_RX_SEG_MSG_COUNT - 1)] = { + .buf.size = CONFIG_BLE_MESH_RX_SDU_MAX, + }, +}; + +static uint8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT * + CONFIG_BLE_MESH_RX_SDU_MAX)]; + +static const struct bt_mesh_send_cb seg_sent_cb; + +static bt_mesh_mutex_t seg_tx_lock; +static bt_mesh_mutex_t seg_rx_lock; + +static inline void bt_mesh_seg_tx_lock(void) +{ + bt_mesh_mutex_lock(&seg_tx_lock); +} + +static inline void bt_mesh_seg_tx_unlock(void) +{ + bt_mesh_mutex_unlock(&seg_tx_lock); +} + +static inline void bt_mesh_seg_rx_lock(void) +{ + bt_mesh_mutex_lock(&seg_rx_lock); +} + +static inline void bt_mesh_seg_rx_unlock(void) +{ + bt_mesh_mutex_unlock(&seg_rx_lock); +} + +uint8_t bt_mesh_seg_send_interval(void) +{ + return (bt_mesh_get_sar_sis() + 1) * 10; +} + +uint8_t bt_mesh_get_seg_rtx_num(void) +{ + return bt_mesh_get_sar_urc(); +} + +int32_t bt_mesh_seg_rtx_interval(uint16_t dst, uint8_t ttl) +{ + if (BLE_MESH_ADDR_IS_UNICAST(dst)) { + if (ttl == 0) { + return (bt_mesh_get_sar_uris() + 1) * 25; + } + + return ((bt_mesh_get_sar_uris() + 1) * 25 + + (bt_mesh_get_sar_urii() + 1) * 25 * (ttl - 1)); + } + + return (bt_mesh_get_sar_mris() + 1) * 25; +} + +int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) +{ + return bt_mesh_seg_rtx_interval(dst, ttl); +} + +uint32_t bt_mesh_seg_discard_timeout(void) +{ + return K_SECONDS((bt_mesh_get_sar_dt() + 1) * 5); +} + +uint32_t bt_mesh_seg_rx_interval(void) +{ + return (bt_mesh_get_sar_rsis() + 1) * 10; +} + +uint32_t bt_mesh_seg_ack_timeout(uint8_t seg_n) +{ + float min = MIN((float)seg_n + 0.5, (float)bt_mesh_get_sar_adi() + 1.5); + return (uint32_t)(min * bt_mesh_seg_rx_interval()); +} + +uint32_t bt_mesh_seg_ack_period(void) +{ + float val = (float)bt_mesh_get_sar_adi() + 1.5; + return (uint32_t)(val * bt_mesh_seg_rx_interval()); +} + +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) +{ + if (bt_mesh_is_provisioned()) { +#if CONFIG_BLE_MESH_NODE + if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { + for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.app_keys[i].app_idx == app_idx) { + return &bt_mesh.app_keys[i]; + } + } + } else { + return bt_mesh_fast_prov_app_key_find(app_idx); + } +#endif + } else if (bt_mesh_is_provisioner_en()) { +#if CONFIG_BLE_MESH_PROVISIONER + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + if (bt_mesh.p_app_keys[i] && + bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.p_app_keys[i]->app_idx == app_idx) { + return bt_mesh.p_app_keys[i]; + } + } +#endif + } + + return NULL; +} + +int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, + const uint8_t **key, uint8_t *aid, uint16_t dst) +{ + struct bt_mesh_app_key *app_key = NULL; + + if (app_idx == BLE_MESH_KEY_DEV) { + *key = bt_mesh_dev_key_get(dst); + if (!*key) { + BT_ERR("DevKey of 0x%04x not found", dst); + return -EINVAL; + } + + *aid = 0U; + return 0; + } + + if (!subnet) { + BT_ERR("Invalid subnet"); + return -EINVAL; + } + + app_key = bt_mesh_app_key_get(app_idx); + if (!app_key) { + BT_ERR("AppKey 0x%04x not found", app_idx); + return -ENOENT; + } + + if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { + *key = app_key->keys[1].val; + *aid = app_key->keys[1].id; + } else { + *key = app_key->keys[0].val; + *aid = app_key->keys[0].id; + } + + return 0; +} + +static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, + const struct bt_mesh_send_cb *cb, void *cb_data, + const uint8_t *ctl_op) +{ + struct net_buf *buf = NULL; + + BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); + if (!buf) { + BT_ERR("Out of network buffers"); + return -ENOBUFS; + } + + net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); + + if (ctl_op) { + net_buf_add_u8(buf, TRANS_CTL_HDR(*ctl_op, 0)); + } else if (tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + net_buf_add_u8(buf, UNSEG_HDR(0, 0)); + } else { + net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); + } + + net_buf_add_mem(buf, sdu->data, sdu->len); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, + tx->src, tx->ctx->addr, + NULL, 1)) { + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + BT_ERR("Not enough space in Friend Queue"); + net_buf_unref(buf); + return -ENOBUFS; + } + + BT_WARN("No space in Friend Queue"); + goto send; + } + + if (bt_mesh_friend_enqueue_tx(tx, BLE_MESH_FRIEND_PDU_SINGLE, + NULL, 1, &buf->b) && + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + /* PDUs for a specific Friend should only go + * out through the Friend Queue. + */ + net_buf_unref(buf); + send_cb_finalize(cb, cb_data); + return 0; + } + } + +send: + return bt_mesh_net_send(tx, buf, cb, cb_data); +} + +static inline uint8_t seg_len(bool ctl) +{ + if (ctl) { + return BLE_MESH_CTL_SEG_SDU_MAX; + } + + return BLE_MESH_APP_SEG_SDU_MAX; +} + +bool bt_mesh_tx_in_progress(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + if (seg_tx[i].nack_count) { + return true; + } + } + + return false; +} + +static bool seg_tx_blocks(struct seg_tx *tx, uint16_t src, uint16_t dst) +{ + return (tx->src == src) && (tx->dst == dst); +} + +static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) +{ + /* If the segments are sent from local network interface, buf->ref + * should be smaller than 4. + * For other network interfaces, buf->ref should be smaller than 3. + */ + bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 4U, BLE_MESH_BUF_REF_SMALL); + + BLE_MESH_ADV(tx->seg[seg_idx])->busy = 0U; + net_buf_unref(tx->seg[seg_idx]); + + tx->seg[seg_idx] = NULL; + tx->nack_count--; +} + +static void seg_tx_reset(struct seg_tx *tx) +{ + bt_mesh_seg_tx_lock(); + + k_delayed_work_free(&tx->seg_timer); + k_delayed_work_free(&tx->rtx_timer); + + tx->cb = NULL; + tx->cb_data = NULL; + tx->seq_auth = 0U; + tx->sub = NULL; + tx->seg_n = 0; + tx->last_seg_n = 0; + tx->lsn_updated = 0; + tx->dst = BLE_MESH_ADDR_UNASSIGNED; + tx->surc = 0; + tx->surwpc = 0; + tx->smrc = 0; + + for (size_t i = 0; i <= tx->seg_n && tx->nack_count; i++) { + if (tx->seg[i] == NULL) { + continue; + } + + seg_tx_done(tx, i); + } + + tx->nack_count = 0U; + + bt_mesh_seg_tx_unlock(); + + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { + BT_DBG("Proceeding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this + * wasn't the only transfer. + */ + if (bt_mesh_net_iv_update(bt_mesh.iv_index, false)) { + bt_mesh_net_sec_update(NULL); + } + } +} + +static void seg_tx_complete(struct seg_tx *tx, int err) +{ + const struct bt_mesh_send_cb *cb = tx->cb; + void *cb_data = tx->cb_data; + + seg_tx_reset(tx); + + /* TODO: notify the completion of sending segmented message */ + + if (cb && cb->end) { + cb->end(err, cb_data); + } +} + +static bool all_seg_acked(struct seg_tx *tx, uint8_t *seg_n) +{ + for (size_t i = 0; i <= tx->seg_n; i++) { + if (tx->seg[i]) { + if (seg_n) { + *seg_n = i; + } + return false; + } + } + + return true; +} + +static bool send_next_segment(struct seg_tx *tx, int *result) +{ + struct bt_mesh_msg_ctx ctx = { + .app_idx = tx->app_idx, + .addr = tx->dst, + .send_ttl = tx->ttl, + .send_cred = tx->cred, + .send_tag = tx->tag, + }; + struct bt_mesh_net_tx net_tx = { + .sub = tx->sub, + .ctx = &ctx, + .src = tx->src, + .xmit = tx->xmit, + .aszmic = tx->aszmic, + .aid = AID(&tx->hdr), + }; + struct net_buf *seg = NULL; + int err = 0; + + /* Check if all the segments are acknowledged. This could happen + * when the complete Segment ACK (i.e. with all ack bits set) is + * received before sending the next segment, which will cause the + * corresponding "struct seg_tx" been reset. + */ + if (all_seg_acked(tx, NULL)) { + assert(tx->nack_count == 0 && "NACK count is not 0"); + return false; + } + + assert(tx->sub && "NULL seg_tx sub"); + + /* While the Segment Interval timer is active, the last_seg_n may + * be updated(i.e. a Segment ACK is received), and it could just + * be equal to seg_n, so we need to check that if tx->last_seg_n + * is "<=" tx->seg_n here(i.e. not "<"). + */ + assert(tx->last_seg_n <= tx->seg_n && "Too large last_seg_n"); + + /* After the Segment Interval timer expired, try to send the next + * unacknowledged segment. + * Note: + * If the lsn_updated flag is 1, which means the last_seg_n is just + * updated, we should sent the segment indicated by the last_seg_n. + */ + for (size_t i = tx->last_seg_n + (tx->lsn_updated ? 0 : 1); + i <= tx->seg_n; i++) { + /* If tx->seg[i] not equals to NULL, which means the segment has + * not been acknowledged. + */ + if (tx->seg[i]) { + tx->last_seg_n = i; + seg = tx->seg[i]; + break; + } + } + + /* All the segments could be marked as acknowledged at this moment. + * For example before the seg_timer expires(i.e. this function is + * invoked), some segment ack is received from the BTU task, which + * marks all the remaining segments as acknowledged. + */ + if (seg == NULL) { + BT_INFO("All segments acked, not send next segment"); + /* "seg_tx_complete" shall not be invoked here */ + return false; + } + + /* The segment may have already been transmitted, for example, the + * Segment Retransmission timer is expired earlier. + */ + if (BLE_MESH_ADV(seg)->busy) { + return false; + } + + BT_INFO("Send next seg %u, cred %u", tx->last_seg_n, tx->cred); + + if (tx->resend) { + err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, &tx->cred, + tx->tag, &seg_sent_cb, tx); + if (err) { + BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + *result = -EIO; + return true; + } + return false; + } + + net_tx.ctx->net_idx = tx->sub->net_idx; + + err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); + if (err) { + BT_ERR("Send seg %u failed (err %d)", tx->last_seg_n, err); + *result = -EIO; + return true; + } + + /* If security credentials is updated in the network layer, + * need to store the security credentials for the segments, + * which will be used for retransmission later. + */ + if (tx->cred != net_tx.ctx->send_cred) { + BT_ERR("Mismatch seg cred %u/%u", tx->cred, net_tx.ctx->send_cred); + *result = -EIO; + return true; + } + + return false; +} + +static void send_next_seg(struct k_work *work) +{ + struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, seg_timer); + bool tx_complete = false; + int result = 0; + + bt_mesh_seg_tx_lock(); + tx_complete = send_next_segment(tx, &result); + bt_mesh_seg_tx_unlock(); + + if (tx_complete) { + seg_tx_complete(tx, result); + } +} + +static void prepare_next_seg(struct seg_tx *tx) +{ + int32_t interval = 0; + uint8_t seg_n = 0; + uint8_t xmit = 0; + + /* Check if all the segments are acknowledged. This could happen + * when the complete Segment ACK (i.e. with all ack bits set) is + * received before the completion of sending last segment, which + * will cause the corresponding "struct seg_tx" been reset. + */ + if (all_seg_acked(tx, &seg_n)) { + assert(tx->nack_count == 0 && "NACK count is not 0"); + return; + } + + /* The last_seg_n must not be larger than the seg_n */ + assert(tx->last_seg_n <= tx->seg_n && "Too large last_seg_n"); + + if (tx->last_seg_n < tx->seg_n) { + /* Once an unacknowledged segment is transmitted, need to check + * if it is the last segment marked as unacknowledged. If yes, + * start the segments retransmission timer; otherwise start the + * segment interval timer. + */ + for (size_t i = tx->last_seg_n + 1; i <= tx->seg_n; i++) { + /* Check if the segment is already been acknowledged */ + if (tx->seg[i] == NULL) { + continue; + } + + /* The duration of transmitting a segment will be decided by + * the Network Transmit state. And if the segment interval + * is smaller than the duration, which will cause the next + * segment been posted to queue before the previous segment + * is transmitted successfully, which is meaningless. + * In case of this, just give a debug log here. By default, + * we transmit a PDU for about 90ms, and the segment interval + * is 60ms. + */ + xmit = bt_mesh_net_transmit_get(); + + if (bt_mesh_pdu_duration(xmit) > bt_mesh_seg_send_interval()) { + BT_INFO("Segment interval should be at least %u (cur %u)", + bt_mesh_pdu_duration(xmit), bt_mesh_seg_send_interval()); + } + + interval = bt_mesh_seg_send_interval(); + + BT_INFO("Send next segment %u after %dms", i, interval); + + k_delayed_work_submit(&tx->seg_timer, interval); + return; + } + } + + /* If the first round of sending segments is finished, update the + * resend flag to 1 here, because when a segment is retransmitted, + * we need to decrypt it firstly. + */ + if (tx->resend == 0) { + tx->resend = 1; + } + + /* Update the last_seg_n to the first unacknowledged SegN */ + tx->last_seg_n = seg_n; + tx->lsn_updated = 1; + + /* Start the SAR retransmission timer */ + interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); + + BT_INFO("All segments sent, resend after %dms", interval); + + k_delayed_work_submit(&tx->rtx_timer, interval); +} + +static void seg_send_start(uint16_t duration, int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + /* If there's an error in transmitting the 'sent' callback will never + * be called. Make sure that we kick the retransmit timer also in this + * case since otherwise we risk the transmission of becoming stale. + */ + if (err) { + seg_tx_complete(tx, -EIO); + return; + } + + if (tx->resend == 0 && tx->last_seg_n == 0) { + /* Start sending the multi-segment message */ + if (tx->cb && tx->cb->start) { + tx->cb->start(duration, err, tx->cb_data); + } + } + + bt_mesh_seg_tx_lock(); + prepare_next_seg(tx); + bt_mesh_seg_tx_unlock(); +} + +static void seg_send_end(int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + if (err) { + seg_tx_complete(tx, -EIO); + } +} + +static const struct bt_mesh_send_cb seg_sent_cb = { + .start = seg_send_start, + .end = seg_send_end, +}; + +static bool resend_unacked_seg(struct seg_tx *tx, int *result) +{ + struct net_buf *seg = NULL; + int err = 0; + + /* Check if all the segments are acknowledged. This could happen + * when the complete Segment ACK(i.e. with all ack bits set) is + * received before the completion of sending last segment, which + * will cause the corresponding "struct seg_tx" been reset. + */ + if (all_seg_acked(tx, NULL)) { + assert(tx->nack_count == 0 && "NACK count is not 0"); + return false; + } + + /* Unacknowledged segments will be retransmitted when: + * - Segment retransmission timer is expired; + * - A Segment ACK is received, and "tx->nack_count" indicates + * that some segments of the message(to unicast address) are + * missing by the peer device. + */ + + if (BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { + /* When the SAR Unicast Retransmissions Timer expires and either + * the remaining number of retransmissions or the remaining number + * of retransmissions without progress is 0, the lower transport + * layer shall cancel the transmission of the Upper Transport PDU, + * and shall notify the upper transport layer that the transmission + * of the Upper Transport PDU has timed out. + */ + if (tx->surc == 0 || tx->surwpc == 0) { + BT_WARN("Ran out of retransmission to 0x%04x (%u/%u)", + tx->dst, tx->surc, tx->surwpc); + *result = -ETIMEDOUT; + return true; + } + + tx->surc -= 1; + tx->surwpc -= 1; + + BT_INFO("Unicast Retransmission Count left: %u/%u", tx->surc, tx->surwpc); + } else { + if (tx->smrc == 0) { + BT_INFO("Complete tx sdu to multicast 0x%04x", tx->dst); + *result = 0; + return true; + } + + tx->smrc -= 1; + + BT_INFO("Multicast Retransmission Count left: %u", tx->smrc); + } + + /* If the Segment Retransmission timer is expired before all the segments + * are transmitted in the first round, we shall not resend the segments, + * since during retransmission, we will decode and encode a segment, and + * a segment will only be encoded after the first round. + */ + if (tx->resend == 0) { + BT_WARN("Segments in the first round not all sent"); + return false; + } + + /* Get the first unacknowledged segment and retransmit it. + * Note: + * Try to find the first unacknowledged segment from "last_seg_n" + * since it marks the first unacknowledged segment previously. + * But before the rtx_timer expires(i.e. this function is invoked), + * some segment ack could be received from the BTU task, which + * marks some of the remaining segments as acknowledged. In this + * case, we need to find the next unacknowledged segment. + */ + for (size_t i = tx->last_seg_n; i <= tx->seg_n; i++) { + if (tx->seg[i]) { + tx->last_seg_n = i; + seg = tx->seg[i]; + break; + } + } + + if (seg == NULL) { + BT_INFO("All segments acked, not retransmit"); + /* "seg_tx_complete" shall not be invoked here */ + return false; + } + + /* The "busy" flag of a segment could be 1 here for example: + * Segment A is being transmitted because the Segment Interval timer + * just expired. While during the previous segments transmission(i.e., + * segments before Segment A), a Segment ACK is received. + * After handling the Segment ACK, the Segment Retransmission timer + * is started. In the Segment Retransmission timeout handler, Segment + * A is still going to be retransmitted, but at this moment we could + * find that the "busy" flag of Segment A is 1. + */ + if (BLE_MESH_ADV(seg)->busy) { + return false; + } + + BT_INFO("Resend seg %u, cred %u", tx->last_seg_n, tx->cred); + + /* TODO: + * The "tx->new_key" should be replaced with sub->kr_flag, + * since there is a chance that the key is refreshed during + * the retransmission of segments. + */ + err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, + &tx->cred, tx->tag, + &seg_sent_cb, tx); + if (err) { + BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + *result = -EIO; + return true; + } + + tx->lsn_updated = 0; + + return false; +} + +static void seg_retransmit(struct k_work *work) +{ + struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, rtx_timer); + bool tx_complete = false; + int err = 0; + + bt_mesh_seg_tx_lock(); + tx_complete = resend_unacked_seg(tx, &err); + bt_mesh_seg_tx_unlock(); + + if (tx_complete) { + seg_tx_complete(tx, err); + } +} + +static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, + const struct bt_mesh_send_cb *cb, void *cb_data, + const uint8_t *ctl_op) +{ + struct seg_tx *tx = NULL; + uint16_t seq_zero = 0U; + uint8_t seg_o = 0U; + int err = 0; + size_t i; + + BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, + net_tx->aszmic, sdu->len); + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + if (seg_tx[i].nack_count) { + /* The lower transport layer shall not transmit segmented messages + * for more than one Upper Transport PDU to the same destination + * at the same time. + */ + if (seg_tx_blocks(&seg_tx[i], net_tx->src, net_tx->ctx->addr)) { + BT_ERR("Multi-segment message to dst 0x%04x blocked", net_tx->ctx->addr); + return -EBUSY; + } + } + } + + for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { + if (!seg_tx[i].nack_count) { + tx = &seg_tx[i]; + break; + } + } + + if (!tx) { + BT_ERR("No multi-segment message contexts available"); + return -EBUSY; + } + + err = k_delayed_work_init(&tx->seg_timer, send_next_seg); + if (err) { + BT_ERR("No free seg_timer for sending multi-segment message"); + return -ENODEV; + } + + err = k_delayed_work_init(&tx->rtx_timer, seg_retransmit); + if (err) { + BT_ERR("No free rtx_timer for sending multi-segment message"); + k_delayed_work_free(&tx->seg_timer); /* Must do */ + return -ENODEV; + } + + tx->sub = net_tx->sub; + tx->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq); + if (ctl_op) { + tx->hdr = TRANS_CTL_HDR(*ctl_op, 1); + } else if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + tx->hdr = SEG_HDR(0, 0); + } else { + tx->hdr = SEG_HDR(1, net_tx->aid); + } + tx->src = net_tx->src; + tx->dst = net_tx->ctx->addr; + tx->app_idx = net_tx->ctx->app_idx; + tx->xmit = net_tx->xmit; + tx->aszmic = net_tx->aszmic; + if (net_tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { + tx->ttl = bt_mesh_default_ttl_get(); + } else { + tx->ttl = net_tx->ctx->send_ttl; + } + tx->cred = net_tx->ctx->send_cred; + tx->tag = net_tx->ctx->send_tag; + tx->len = sdu->len; + if (sdu->len) { + tx->seg_n = (sdu->len - 1) / seg_len(!!ctl_op); + } else { + tx->seg_n = 0; + } + tx->last_seg_n = 0; + tx->lsn_updated = 0; + tx->nack_count = tx->seg_n + 1; + if (BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { + /* When the lower transport layer starts a new transfer of an + * Upper Transport PDU that is destined to a unicast address, + * the lower transport layer shall set the remaining number + * of retransmissions to the initial value and shall set the + * remaining number of retransmissions without progress to the + * initial value. + */ + tx->surc = bt_mesh_get_sar_urc(); + tx->surwpc = bt_mesh_get_sar_urwpc(); + } else { + /* When the lower transport layer starts a new transfer of an + * Upper Transport PDU that is destined to a group address or + * a virtual address, he lower transport layer shall set the + * remaining number of retransmissions to the initial value. + */ + tx->smrc = bt_mesh_get_sar_mrc(); + } + tx->new_key = net_tx->sub->kr_flag; + tx->ctl = !!ctl_op; + tx->resend = 0; + tx->cb = cb; + tx->cb_data = cb_data; + + seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; + + BT_DBG("SeqZero 0x%04x (segs: %u)", seq_zero, tx->nack_count); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && + !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, + tx->dst, &tx->seq_auth, + tx->seg_n + 1) && + BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { + BT_ERR("Not enough space in Friend Queue for %u segments", + tx->seg_n + 1); + seg_tx_reset(tx); + return -ENOBUFS; + } + + for (seg_o = 0U; sdu->len; seg_o++) { + struct net_buf *seg = NULL; + uint16_t len = 0U; + + seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); + if (!seg) { + BT_ERR("Out of segment buffers"); + seg_tx_reset(tx); + return -ENOBUFS; + } + + net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN); + + net_buf_add_u8(seg, tx->hdr); + net_buf_add_u8(seg, (net_tx->aszmic << 7) | seq_zero >> 6); + net_buf_add_u8(seg, (((seq_zero & 0x3f) << 2) | (seg_o >> 3))); + net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx->seg_n); + + len = MIN(sdu->len, seg_len(!!ctl_op)); + net_buf_add_mem(seg, net_buf_simple_pull_mem(sdu, len), len); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + enum bt_mesh_friend_pdu_type type = BLE_MESH_FRIEND_PDU_PARTIAL; + + if (seg_o == tx->seg_n) { + type = BLE_MESH_FRIEND_PDU_COMPLETE; + } else { + type = BLE_MESH_FRIEND_PDU_PARTIAL; + } + + if (bt_mesh_friend_enqueue_tx(net_tx, type, + &tx->seq_auth, + tx->seg_n + 1, + &seg->b) && + BLE_MESH_ADDR_IS_UNICAST(net_tx->ctx->addr)) { + /* PDUs for a specific Friend should only go + * out through the Friend Queue. + */ + net_buf_unref(seg); + continue; + } + } + + tx->seg[seg_o] = net_buf_ref(seg); + + BT_DBG("Seg %u/%u prepared", seg_o, tx->seg_n); + } + + /* If all the segments are enqueued in the friend queue, then the + * tx->seg[0] will be NULL here. + */ + if (tx->seg[0]) { + err = bt_mesh_net_send(net_tx, tx->seg[0], &seg_sent_cb, tx); + if (err) { + BT_ERR("Send 1st seg failed (err %d)", err); + seg_tx_reset(tx); + return err; + } + + /* If security credentials is updated in the network layer, + * need to store the security credentials for the segments, + * which will be used for retransmission later. + */ + if (tx->cred != net_tx->ctx->send_cred) { + tx->cred = net_tx->ctx->send_cred; + } + } + + /* This can happen if segments only went into the Friend Queue */ + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) { + seg_tx_reset(tx); + /* If there was a callback notify sending immediately since + * there's no other way to track this (at least currently) + * with the Friend Queue. + */ + send_cb_finalize(cb, cb_data); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + bt_mesh_lpn_established()) { + bt_mesh_lpn_poll(); + } + + return 0; +} + +int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + const uint8_t *key = NULL; + uint8_t *ad = NULL; + uint8_t aid = 0U; + int err = 0; + + if (msg->len < 1) { + BT_ERR("Zero-length SDU not allowed"); + return -EINVAL; + } + + if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } + + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, + tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + + err = bt_mesh_upper_key_get(tx->sub, tx->ctx->app_idx, &key, + &aid, tx->ctx->addr); + if (err) { + return err; + } + + tx->aid = aid; + + if (!bt_mesh_tag_send_segmented(tx->ctx->send_tag) || + tx->ctx->send_szmic == BLE_MESH_SEG_SZMIC_SHORT || + net_buf_simple_tailroom(msg) < BLE_MESH_MIC_LONG) { + tx->aszmic = 0U; + } else { + tx->aszmic = 1U; + } + + BT_INFO("%s, send_tag 0x%02x, send_szmic %d, aszmic %d", + bt_mesh_tag_send_segmented(tx->ctx->send_tag) ? "Seg" : "Unseg", + tx->ctx->send_tag, tx->ctx->send_szmic, tx->aszmic); + + if (BLE_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { + ad = bt_mesh_label_uuid_get(tx->ctx->addr); + } else { + ad = NULL; + } + + err = bt_mesh_app_encrypt(key, tx->ctx->app_idx == BLE_MESH_KEY_DEV, + tx->aszmic, msg, ad, tx->src, + tx->ctx->addr, bt_mesh.seq, + BLE_MESH_NET_IVI_TX); + if (err) { + BT_ERR("Encrypt failed (err %d)", err); + return err; + } + + if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { + return send_seg(tx, msg, cb, cb_data, NULL); + } + + return send_unseg(tx, msg, cb, cb_data, NULL); +} + +static void revoke_dev_key(const uint8_t *dev_key) +{ + if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { + BT_INFO("Revoke Device Key"); + + memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); + memset(bt_mesh.dev_key_ca, 0, 16); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_net(); + bt_mesh_clear_dkca(); + } + } +} + +static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, + uint8_t aszmic, struct net_buf_simple *buf) +{ + struct net_buf_simple *sdu = NULL; + size_t array_size = 0U; + uint8_t *ad = NULL; + size_t i = 0U; + int err = 0; + + BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (buf->len < 1 + APP_MIC_LEN(aszmic)) { + BT_ERR("Too short SDU + MIC (len %u)", buf->len); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !rx->local_match) { + BT_DBG("Ignoring PDU for LPN 0x%04x of this Friend", + rx->ctx.recv_dst); + return 0; + } + + if (BLE_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + ad = bt_mesh_label_uuid_get(rx->ctx.recv_dst); + } else { + ad = NULL; + } + + /* Adjust the length to not contain the MIC at the end */ + buf->len -= APP_MIC_LEN(aszmic); + + /* Use bt_mesh_alloc_buf() instead of NET_BUF_SIMPLE_DEFINE to avoid + * causing btu task stack overflow. + */ + sdu = bt_mesh_alloc_buf(CONFIG_BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT); + if (!sdu) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + if (!AKF(&hdr)) { + array_size = bt_mesh_rx_devkey_size(); + + for (i = 0U; i < array_size; i++) { + const uint8_t *dev_key = NULL; + + dev_key = bt_mesh_rx_devkey_get(i, rx->ctx.addr); + if (!dev_key) { + BT_DBG("DevKey not found"); + continue; + } + + net_buf_simple_reset(sdu); + + err = bt_mesh_app_decrypt(dev_key, true, aszmic, buf, + sdu, ad, rx->ctx.addr, + rx->ctx.recv_dst, seq, + BLE_MESH_NET_IVI_RX(rx)); + if (err) { + continue; + } + + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + "\nTNPTRecv: ctl: 0x%04x, ttl: 0x%04x, src: 0x%04x, dst: 0x%04x, payload: 0x%s", + rx->ctl, rx->ctx.recv_ttl, rx->ctx.addr, rx->ctx.recv_dst, + bt_hex(sdu->data, sdu->len)); + + /* When the Device Key Candidate is available, and an access message + * is decrypted using the Device Key Candidate that was delivered to + * the access layer, then the node shall revoke the device key, the + * Device Key Candidate shall become the device key, and the Device + * Key Candidate shall become unavailable. + */ + revoke_dev_key(dev_key); + + rx->ctx.app_idx = BLE_MESH_KEY_DEV; + bt_mesh_model_recv(rx, sdu); + + bt_mesh_free_buf(sdu); + return 0; + } + + BT_WARN("Unable to decrypt with DevKey"); + bt_mesh_free_buf(sdu); + return -ENODEV; + } + + array_size = bt_mesh_rx_appkey_size(); + + for (i = 0U; i < array_size; i++) { + struct bt_mesh_app_keys *keys = NULL; + struct bt_mesh_app_key *key = NULL; + + key = bt_mesh_rx_appkey_get(i); + if (!key) { + BT_DBG("AppKey not found"); + continue; + } + + /* Make sure that this AppKey matches received net_idx */ + if (key->net_idx != rx->sub->net_idx) { + continue; + } + + if (rx->new_key && key->updated) { + keys = &key->keys[1]; + } else { + keys = &key->keys[0]; + } + + /* Check that the AppKey ID matches */ + if (AID(&hdr) != keys->id) { + continue; + } + + net_buf_simple_reset(sdu); + + err = bt_mesh_app_decrypt(keys->val, false, aszmic, buf, + sdu, ad, rx->ctx.addr, + rx->ctx.recv_dst, seq, + BLE_MESH_NET_IVI_RX(rx)); + + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + "\nTNPTRecv: ctl: 0x%04x, ttl: 0x%04x, src: 0x%04x, dst: 0x%04x, payload: 0x%s", + rx->ctl, rx->ctx.recv_ttl, rx->ctx.addr, rx->ctx.recv_dst, + bt_hex(sdu->data, sdu->len)); + + if (err) { + BT_DBG("Unable to decrypt with AppKey 0x%03x", + key->app_idx); + continue; + } + + rx->ctx.app_idx = key->app_idx; + bt_mesh_model_recv(rx, sdu); + + bt_mesh_free_buf(sdu); + return 0; + } + + if (rx->local_match) { + BT_WARN("No matching AppKey"); + } + bt_mesh_free_buf(sdu); + + return 0; +} + +static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, + uint16_t addr, uint16_t net_idx) +{ + struct seg_tx *tx = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + tx = &seg_tx[i]; + + if ((tx->seq_auth & TRANS_SEQ_ZERO_MASK) != seq_zero) { + continue; + } + + /* The message was secured using the same NetKey that was + * used to secure the segmented message. + */ + if (tx->sub == NULL || tx->sub->net_idx != net_idx) { + continue; + } + + if (tx->dst == addr) { + return tx; + } + + /* If the expected remote address doesn't match, + * but the OBO flag is set and this is the first + * acknowledgement, assume it's a Friend that's + * responding and therefore accept the message. + */ + if (obo && tx->nack_count == tx->seg_n + 1) { + tx->dst = addr; + return tx; + } + } + + return NULL; +} + +static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, + struct net_buf_simple *buf, uint64_t *seq_auth, + struct seg_tx **seg_tx, bool *tx_complete, + int *result) +{ + struct seg_tx *tx = NULL; + bool newly_mark = false; + unsigned int bit = 0; + uint32_t ack = 0U; + uint16_t seq_zero = 0U; + int32_t interval = 0; + uint8_t obo = 0U; + uint8_t seg_n = 0; + + *seg_tx = NULL; + *tx_complete = false; + *result = 0; + + if (buf->len != 6) { + BT_ERR("Malformed Segment Ack (len %u)", buf->len); + return -EINVAL; + } + + seq_zero = net_buf_simple_pull_be16(buf); + obo = seq_zero >> 15; + seq_zero = (seq_zero >> 2) & TRANS_SEQ_ZERO_MASK; + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->friend_match) { + BT_DBG("Ack for LPN 0x%04x of this Friend", rx->ctx.recv_dst); + /* Best effort - we don't have enough info for true SeqAuth */ + *seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_RX(rx), seq_zero); + return 0; + } + + ack = net_buf_simple_pull_be32(buf); + + BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + + tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr, rx->ctx.net_idx); + if (!tx) { + BT_INFO("No matching TX context for Seg Ack"); + return -EINVAL; + } + + *seg_tx = tx; + + /* When the lower transport layer starts a new transfer of an Upper + * Transport PDU that is destined to a group address or a virtual + * address, the lower transport layer shall set the remaining number + * of retransmissions to the initial value. Segment Acknowledgment + * messages are not sent by the destination. + */ + if (!BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { + BT_WARN("Received ack for segments to group"); + return -EINVAL; + } + + *seq_auth = tx->seq_auth; + + if (ack == 0) { + BT_WARN("SDU canceled"); + *tx_complete = true; + *result = -ECANCELED; + return 0; + } + + if (find_msb_set(ack) - 1 > tx->seg_n) { + BT_ERR("Too large segment number in ack"); + return -EINVAL; + } + + k_delayed_work_cancel(&tx->rtx_timer); + + while ((bit = find_lsb_set(ack))) { + if (tx->seg[bit - 1]) { + BT_INFO("Seg %u/%u acked", bit - 1, tx->seg_n); + + seg_tx_done(tx, bit - 1); + + if (newly_mark == false) { + newly_mark = true; + } + } + + ack &= ~BIT(bit - 1); + } + + if (tx->nack_count == 0) { + BT_INFO("SDU TX complete"); + *tx_complete = true; + *result = 0; + return 0; + } + + /* If at least one segment is newly marked as acknowledged as + * a result of receiving the Segment Acknowledgment message, + * the lower transport layer shall set the remaining number of + * retransmissions without progress to the initial value. + */ + if (newly_mark) { + tx->surwpc = bt_mesh_get_sar_urwpc(); + } + + if (tx->surc == 0 || tx->surwpc == 0) { + BT_WARN("Ran out of retransmission to 0x%04x (%u/%u)", + tx->dst, tx->surc, tx->surwpc); + *tx_complete = true; + *result = -ETIMEDOUT; + return 0; + } + + assert(all_seg_acked(tx, &seg_n) == false && "All segments acked"); + + if (tx->resend == 1) { + /* Only update the last_seg_n to the first unacked SegN while + * the first round transmission is finished, because we need + * the segment in the tx buffer been encrypted. + * If the last_seg_n is updated here, it may cause the segments + * been wrongly transmitted (i.e. not retransmitted) after the + * last segment starts being transmitted. + * + * For example, 3 segments A, B and C exist. + * - Segment A send start(i.e. seg_send_start) + * - Segment A send end(i.e. seg_send_end) + * - Segment B send start(i.e. seg_send_start) + * - Segment B send end(i.e. seg_send_end) + * - Segment ACK received + * - The last_seg_n updated + * - Segment C send start(i.e. seg_send_start) + * - The "resend" flag is 0, start Segment Interval timer + * - Segment Interval timer expired, send next segment + * - Since the "resend" flag is 0, bt_mesh_net_send invoked + * - "Insufficient MIC space for PDU" reported + */ + tx->last_seg_n = seg_n; + tx->lsn_updated = 1; + } + + /* Restart the SAR Unicast Retransmission timer */ + interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); + + BT_INFO("Resend segments after %dms", interval); + + k_delayed_work_submit(&tx->rtx_timer, interval); + + return 0; +} + +static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, + struct net_buf_simple *buf, uint64_t *seq_auth) +{ + struct seg_tx *tx = NULL; + bool tx_complete = false; + int result = 0; + int err = 0; + + bt_mesh_seg_tx_lock(); + err = recv_seg_ack(rx, hdr, buf, seq_auth, &tx, &tx_complete, &result); + bt_mesh_seg_tx_unlock(); + + if (tx_complete) { + seg_tx_complete(tx, result); + } + + return err; +} + +static int trans_heartbeat(struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + uint8_t init_ttl = 0U, hops = 0U; + uint16_t feat = 0U; + + if (buf->len != 3) { + BT_ERR("Malformed heartbeat message (len %u)", buf->len); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && + rx->ctx.recv_dst != bt_mesh_get_hb_sub_dst()) { + BT_WARN("Ignoring heartbeat to non-subscribed destination"); + return 0; + } + + init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f); + feat = net_buf_simple_pull_be16(buf); + + hops = (init_ttl - rx->ctx.recv_ttl + 1); + + BT_INFO("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, + (hops == 1U) ? "" : "s", feat); + + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + bt_mesh_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); + } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER_RECV_HB) && bt_mesh_is_provisioner_en()) { + bt_mesh_pvnr_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, + init_ttl, rx->ctx.recv_ttl, + hops, feat, rx->ctx.recv_rssi); + } + + return 0; +} + +static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, + struct net_buf_simple *buf, uint64_t *seq_auth) +{ + uint8_t ctl_op = TRANS_CTL_OP(&hdr); + + BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + "\nTNPTRecv: ctl: 0x%04x, ttl: 0x%04x, src: 0x%04x, dst: 0x%04x, payload: 0x%s", + rx->ctl, rx->ctx.recv_ttl, rx->ctx.addr, rx->ctx.recv_dst, + bt_hex(buf->data, buf->len)); + + switch (ctl_op) { + case TRANS_CTL_OP_ACK: + return trans_ack(rx, hdr, buf, seq_auth); + case TRANS_CTL_OP_HEARTBEAT: + return trans_heartbeat(rx, buf); + } + + /* Only acks and heartbeats may need processing without local_match */ + if (!rx->local_match) { + return 0; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_DF_SRV)) { + switch (ctl_op) { + case TRANS_CTL_OP_PATH_REQ: + case TRANS_CTL_OP_PATH_REPLY: + case TRANS_CTL_OP_PATH_CFM: + case TRANS_CTL_OP_PATH_ECHO_REQ: + case TRANS_CTL_OP_PATH_ECHO_REPLY: + case TRANS_CTL_OP_DEP_NODE_UPDATE: + case TRANS_CTL_OP_PATH_REQ_SOLIC: + return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); + } + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { + switch (ctl_op) { + case TRANS_CTL_OP_FRIEND_POLL: + return bt_mesh_friend_poll(rx, buf); + case TRANS_CTL_OP_FRIEND_REQ: + return bt_mesh_friend_req(rx, buf); + case TRANS_CTL_OP_FRIEND_CLEAR: + return bt_mesh_friend_clear(rx, buf); + case TRANS_CTL_OP_FRIEND_CLEAR_CFM: + return bt_mesh_friend_clear_cfm(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_ADD: + return bt_mesh_friend_sub_add(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_REM: + return bt_mesh_friend_sub_rem(rx, buf); + } + } + +#if CONFIG_BLE_MESH_LOW_POWER + if (ctl_op == TRANS_CTL_OP_FRIEND_OFFER) { + return bt_mesh_lpn_friend_offer(rx, buf); + } + + if (rx->ctx.addr == bt_mesh.lpn.frnd) { + if (ctl_op == TRANS_CTL_OP_FRIEND_CLEAR_CFM) { + return bt_mesh_lpn_friend_clear_cfm(rx, buf); + } + + if (rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED) { + BT_WARN("Message from friend with wrong credentials"); + return -EINVAL; + } + + switch (ctl_op) { + case TRANS_CTL_OP_FRIEND_UPDATE: + return bt_mesh_lpn_friend_update(rx, buf); + case TRANS_CTL_OP_FRIEND_SUB_CFM: + return bt_mesh_lpn_friend_sub_cfm(rx, buf); + } + } +#endif /* CONFIG_BLE_MESH_LOW_POWER */ + + BT_WARN("Unhandled TransOpCode 0x%02x", ctl_op); + + return -ENOENT; +} + +static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, + uint64_t *seq_auth) +{ + uint8_t hdr = 0U; + + BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + + if (buf->len < 1) { + BT_ERR("Too small unsegmented PDU"); + return -EINVAL; + } + + if (bt_mesh_rpl_check(rx, NULL)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + rx->ctx.addr, rx->ctx.recv_dst, rx->seq); + return -EINVAL; + } + + hdr = net_buf_simple_pull_u8(buf); + + if (rx->ctl) { + return ctl_recv(rx, hdr, buf, seq_auth); + } + + /* SDUs must match a local element or an LPN of this Friend. */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + + return sdu_recv(rx, rx->seq, hdr, 0, buf); +} + +int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, + size_t data_len, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + struct net_buf_simple buf = {0}; + + net_buf_simple_init_with_data(&buf, data, data_len); + + if (data_len > BLE_MESH_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } + + /* Set app_idx to unused here since CTL is only encrypted with NetKey */ + tx->ctx->app_idx = BLE_MESH_KEY_UNUSED; + + BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, + tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); + + if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { + return send_seg(tx, &buf, cb, cb_data, &ctl_op); + } + + return send_unseg(tx, &buf, cb, cb_data, &ctl_op); +} + +static void seg_ack_send_start(uint16_t duration, int err, void *user_data) +{ + struct seg_rx *rx = user_data; + + BT_INFO("Send segment ack start (err %d)", err); + + if (err) { + rx->last_ack = k_uptime_get_32(); + } +} + +static void seg_ack_send_end(int err, void *user_data) +{ + struct seg_rx *rx = user_data; + + BT_INFO("Send segment ack end"); + + /* This could happen when during the Segment ACK transaction, + * the seg_rx is been reset. + */ + if (rx->in_use == 0) { + return; + } + + rx->last_ack = k_uptime_get_32(); + + /* If the seg_rx is in use, we will restart the SAR ACK timer if + * the SegN is greater than the SAR Segments Threshold. + * Note: + * Check the "in_use" flag here in case the seg_rx has been reset, + * in this case, the SAR ACK timer will not be restarted. + * + * Check the "new_seg" flag here in case a seg is received during + * the Segment ACK transaction, which will cause the SAR ACK timer + * been started with the initial value. In this case, we shall not + * restart the Segment ACK timer here. + */ + if (rx->seg_n > bt_mesh_get_sar_st() && + rx->sarc && + rx->new_seg == 0) { + /* Decrement the SAR ACK Retransmissions Count */ + rx->sarc -= 1; + + BT_INFO("Resend segment ack after %dms", bt_mesh_seg_rx_interval()); + + /* Introduce a delay for the Segment ACK retransmission */ + k_delayed_work_submit(&rx->ack_timer, bt_mesh_seg_rx_interval()); + } +} + +static const struct bt_mesh_send_cb seg_ack_sent_cb = { + .start = seg_ack_send_start, + .end = seg_ack_send_end, +}; + +/* The Segment Acknowledgment message shall use the same NetKey as + * the first received segment of a multi-segment message, and the + * DST field shall have the same value as the SRC field of the first + * received segment of a multi-segment message. + */ +static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, + uint8_t ttl, uint64_t *seq_auth, uint32_t block, uint8_t obo, + struct seg_rx *rx) +{ + struct bt_mesh_msg_ctx ctx = { + .net_idx = sub->net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = dst, + .send_ttl = ttl, + /* TODO: + * Could be Managed flooding/Friendship/Directed security credentials. + * The "recv_cred" could be used to initialize "send_cred". + */ + .send_cred = BLE_MESH_FLOODING_CRED, + }; + struct bt_mesh_net_tx tx = { + .sub = sub, + .ctx = &ctx, + .src = obo ? bt_mesh_primary_addr() : src, + .xmit = bt_mesh_net_transmit_get(), + }; + uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; + uint8_t buf[6] = {0}; + + BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + + if (bt_mesh_lpn_established()) { + BT_WARN("Not sending ack when LPN is enabled"); + return 0; + } + + /* This can happen if the segmented message was destined for a group + * or virtual address. + */ + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { + BT_INFO("Not sending ack for non-unicast address"); + return 0; + } + + sys_put_be16(((seq_zero << 2) & 0x7ffc) | (obo << 15), buf); + sys_put_be32(block, &buf[2]); + + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_ACK, buf, sizeof(buf), + rx ? &seg_ack_sent_cb : NULL, rx); +} + +static void seg_rx_reset(struct seg_rx *rx, bool full_reset) +{ + bt_mesh_seg_rx_lock(); + + k_delayed_work_free(&rx->dis_timer); + if (BLE_MESH_ADDR_IS_UNICAST(rx->dst)) { + k_delayed_work_free(&rx->ack_timer); + } + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->obo && + rx->block != BLOCK_COMPLETE(rx->seg_n)) { + BT_WARN("Clearing incomplete buffers from Friend queue"); + bt_mesh_friend_clear_incomplete(rx->sub, rx->src, rx->dst, + &rx->seq_auth); + } + + rx->in_use = 0U; + + /* We don't always reset these values since we need to be able to + * send an ack if we receive a segment after we've already received + * the full SDU. + */ + if (full_reset) { + rx->seq_auth = 0U; + rx->seg_n = 0; + rx->ctl = 0; + rx->obo = 0; + rx->sub = NULL; + rx->ttl = 0; + rx->src = BLE_MESH_ADDR_UNASSIGNED; + rx->dst = BLE_MESH_ADDR_UNASSIGNED; + rx->block = 0; + rx->last_ack = 0; + } + + bt_mesh_seg_rx_unlock(); +} + +static void send_seg_ack(struct k_work *work) +{ + struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); + + bt_mesh_seg_rx_lock(); + + /* This could happen when the SAR ACK timer expired, and a BTC + * event is posted to the BTC queue. + * But before the BTC event been handled, the seg_rx is fully + * reset, we must return here, since the rx->sub will be NULL. + */ + if (rx->sub == NULL) { + goto end; + } + + /* Even if the seg_rx is reset(but not fully), we will continue + * sending the Segment ACK. + */ + send_ack(rx->sub, rx->dst, rx->src, rx->ttl, &rx->seq_auth, + rx->block, rx->obo, rx); + + rx->new_seg = 0; + +end: + bt_mesh_seg_rx_unlock(); +} + +static void discard_msg(struct k_work *work) +{ + struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, dis_timer); + + /* This could happen when the SAR Discard timer expired, and a + * BTC event is posted to the BTC queue. + * But before the BTC event been handled, the last segment is + * received from the BTU task(higher priority than the BTC task). + * In this case, the segmented message will be marked as fully + * received, and we ignore the discard timeout here. + */ + if (rx->in_use == 0) { + return; + } + + /* Stop SAR ACK timer when SAR Discard timer expires */ + if (BLE_MESH_ADDR_IS_UNICAST(rx->dst)) { + k_delayed_work_cancel(&rx->ack_timer); + } + + BT_WARN("Discard timer expired (%dms)", bt_mesh_seg_discard_timeout()); + + /* Not fully reset the seg_rx, in case any segment of this + * message is received later. + */ + seg_rx_reset(rx, false); +} + +static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) +{ + return ((seg_n + 1) * seg_len(ctl) <= CONFIG_BLE_MESH_RX_SDU_MAX); +} + +static void seg_rx_reset_pending(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth) +{ + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + + if (rx->src == net_rx->ctx.addr && + rx->dst == net_rx->ctx.recv_dst && + rx->seq_auth < *seq_auth && + rx->in_use) { + BT_WARN("Discard pending reassembly, src 0x%04x dst 0x%04x", + net_rx->ctx.addr, net_rx->ctx.recv_dst); + + /* In this case, fully reset the seg_rx */ + seg_rx_reset(rx, true); + } + } +} + +static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth) +{ + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + + if (rx->src == net_rx->ctx.addr && + rx->dst == net_rx->ctx.recv_dst && + rx->seq_auth >= *seq_auth) { + return rx; + } + } + + return NULL; +} + +static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, + const uint8_t *hdr, uint8_t seg_n) +{ + if (rx->hdr != *hdr || rx->seg_n != seg_n) { + BT_ERR("Invalid segment for ongoing session"); + return false; + } + + if (rx->ctl != net_rx->ctl) { + BT_ERR("Inconsistent CTL in segment"); + return false; + } + + return true; +} + +static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, + const uint8_t *hdr, const uint64_t *seq_auth, + uint8_t seg_n) +{ + int err = 0; + + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + + if (rx->in_use) { + continue; + } + + err = k_delayed_work_init(&rx->dis_timer, discard_msg); + if (err) { + BT_ERR("No free dis_timer for new incoming segmented message"); + return NULL; + } + + if (BLE_MESH_ADDR_IS_UNICAST(net_rx->ctx.recv_dst)) { + err = k_delayed_work_init(&rx->ack_timer, send_seg_ack); + if (err) { + BT_ERR("No free ack_timer for new incoming segmented message"); + k_delayed_work_free(&rx->dis_timer); /* Must do */ + return NULL; + } + } + + rx->in_use = 1U; + net_buf_simple_reset(&rx->buf); + rx->sub = net_rx->sub; + rx->ctl = net_rx->ctl; + rx->seq_auth = *seq_auth; + rx->seg_n = seg_n; + rx->hdr = *hdr; + rx->ttl = net_rx->ctx.send_ttl; + rx->src = net_rx->ctx.addr; + rx->dst = net_rx->ctx.recv_dst; + rx->block = 0U; + rx->last_ack = 0; + + BT_DBG("New RX context. Block Complete 0x%08x", + BLOCK_COMPLETE(seg_n)); + + return rx; + } + + BT_WARN("No free slots for new incoming segmented messages"); + return NULL; +} + +static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, + enum bt_mesh_friend_pdu_type *pdu_type, uint64_t *seq_auth, + uint8_t *seg_count) +{ + struct bt_mesh_rpl *rpl = NULL; + struct seg_rx *rx = NULL; + uint8_t *hdr = buf->data; + uint16_t seq_zero = 0U; + uint8_t seg_n = 0U; + uint8_t seg_o = 0U; + int err = 0; + + if (buf->len < 5) { + BT_ERR("Too short segmented message (len %u)", buf->len); + return -EINVAL; + } + + if (bt_mesh_rpl_check(net_rx, &rpl)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); + return -EINVAL; + } + + BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + + net_buf_simple_pull(buf, 1); + + seq_zero = net_buf_simple_pull_be16(buf); + seg_o = (seq_zero & 0x03) << 3; + seq_zero = (seq_zero >> 2) & TRANS_SEQ_ZERO_MASK; + seg_n = net_buf_simple_pull_u8(buf); + seg_o |= seg_n >> 5; + seg_n &= 0x1f; + + BT_DBG("SeqZero 0x%04x SegO %u SegN %u", seq_zero, seg_o, seg_n); + + if (seg_o > seg_n) { + BT_ERR("SegO greater than SegN (%u > %u)", seg_o, seg_n); + return -EINVAL; + } + + /* SEQ(0) = SEQ(n) - (delta between seqZero and SEQ(n) by looking + * into 14 least significant bits of SEQ(n)) + */ + *seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_RX(net_rx), + (net_rx->seq - + (((net_rx->seq & BIT_MASK(14)) - seq_zero) & BIT_MASK(13)))); + + *seg_count = seg_n + 1; + + /* If this is the first segment, check if any pending reassembly + * exists. If yes, we need to discard the pending reassembly. + * Note: + * The first segment may not have SeqO with 0 here, because the + * segment with SegO = 0 may be missed and SegO = 1 is received. + */ + seg_rx_reset_pending(net_rx, seq_auth); + + /* Look for old RX sessions */ + rx = seg_rx_find(net_rx, seq_auth); + if (rx) { + /* Processing result is SeqAuth Error, ignore the segment */ + if (rx->seq_auth > *seq_auth) { + BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", + rx->src, rx->dst); + return -EINVAL; + } + + if (!seg_rx_is_valid(rx, net_rx, hdr, seg_n)) { + return -EINVAL; + } + + if (rx->in_use) { + BT_DBG("Existing RX context. Block 0x%08x", rx->block); + goto found_rx; + } + + /* If a segmented message is received successfully, the "in_use" + * flag will be set to 0, but the other information, e.g. src, + * dst, seq_auth will not be reset. These information could be + * used to check if any segment of an already received message + * is received again. In this case, the processing result will + * be Most Recent SeqAuth, and a Segment ACK will be sent. + */ + if (rx->block == BLOCK_COMPLETE(rx->seg_n)) { + BT_INFO("Got segment for already complete SDU"); + + /* Make sure not sending more than one Segment ACK for the + * same SeqAuth in a period of: + * [ack_delay_increment * seg_reception_interval] ms + */ + if (k_uptime_get_32() - rx->last_ack >= bt_mesh_seg_ack_period()) { + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, rx->block, rx->obo, rx); + } + + if (rpl) { + bt_mesh_update_rpl(rpl, net_rx); + } + + return -EALREADY; + } + + /* The "in_use" flag is 0, which means the seg_rx has been reset, + * but not all the segments are received. Ignore this segment. + */ + BT_WARN("Got segment for canceled SDU"); + return -EINVAL; + } + + /* Bail out early if we're not ready to receive such a large SDU */ + if (!sdu_len_is_ok(net_rx->ctl, seg_n)) { + BT_ERR("Too big incoming SDU length"); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, + net_rx->ctx.send_ttl, seq_auth, 0, + net_rx->friend_match, NULL); + return -EMSGSIZE; + } + + /* Verify early that there will be space in the Friend Queue(s) in + * case this message is destined to an LPN of ours. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && + net_rx->friend_match && !net_rx->local_match && + !bt_mesh_friend_queue_has_space(net_rx->sub->net_idx, + net_rx->ctx.addr, + net_rx->ctx.recv_dst, seq_auth, + *seg_count)) { + BT_ERR("No space in Friend Queue for %u segments", *seg_count); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, + net_rx->ctx.send_ttl, seq_auth, 0, + net_rx->friend_match, NULL); + return -ENOBUFS; + } + + /* Look for free slot for a new RX session */ + rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); + if (!rx) { + /* Processing result is Message Rejected, respond with a Segment + * ACK with the AckedSegments field set to 0x00000000. + */ + if (BLE_MESH_ADDR_IS_UNICAST(net_rx->ctx.recv_dst)) { + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, + net_rx->ctx.send_ttl, seq_auth, 0, + net_rx->friend_match, NULL); + } + return -ENOMEM; + } + + rx->obo = net_rx->friend_match; + +found_rx: + /* Processing result is Repeated Segment, ignore the segment */ + if (BIT(seg_o) & rx->block) { + BT_INFO("Received already received fragment"); + return -EALREADY; + } + + /* All segments, except the last one, must either have 8 bytes of + * payload (for 64bit Net MIC) or 12 bytes of payload (for 32bit + * Net MIC). + * Processing result is Last Segment. + */ + if (seg_o == seg_n) { + /* Set the expected final buffer length */ + rx->buf.len = seg_n * seg_len(rx->ctl) + buf->len; + + BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(rx->ctl), + buf->len, rx->buf.len); + + /* This should not happen, since we have made sure the whole + * SDU could be received while handling the first segment. + * But if the peer device sends the segments of a segmented + * message with different CTL, then the following could happen. + */ + if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { + BT_ERR("Too large SDU len %u/%u", rx->buf.len, + CONFIG_BLE_MESH_RX_SDU_MAX); + + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, 0, rx->obo, NULL); + seg_rx_reset(rx, true); + + return -EMSGSIZE; + } + } else { + if (buf->len != seg_len(rx->ctl)) { + BT_ERR("Incorrect segment size for message type"); + return -EINVAL; + } + } + + /* Location in buffer can be calculated based on seg_o & rx->ctl */ + memcpy(rx->buf.data + (seg_o * seg_len(rx->ctl)), buf->data, buf->len); + + BT_INFO("Seg %u/%u received", seg_o, seg_n); + + /* Restart the timer with no need to check if its remaining time is 0 */ + if (!bt_mesh_lpn_established()) { + /* Start SAR Discard timer when processing result is First Segment + * or Next Segment. + */ + k_delayed_work_submit(&rx->dis_timer, bt_mesh_seg_discard_timeout()); + + /* Start SAR ACK timer when processing result is First Segment + * or Next Segment. + */ + if (BLE_MESH_ADDR_IS_UNICAST(rx->dst)) { + /* Update the SAR ACK Retransmissions Count in case the SegN + * is greater than the SAR Segments Threshold. + */ + rx->sarc = (seg_n > bt_mesh_get_sar_st() ? bt_mesh_get_sar_arc() : 0); + rx->new_seg = 1; + + BT_INFO("Send segment ack after %dms", bt_mesh_seg_ack_timeout(seg_n)); + + k_delayed_work_submit(&rx->ack_timer, bt_mesh_seg_ack_timeout(seg_n)); + } + } + + if (rpl) { + bt_mesh_update_rpl(rpl, net_rx); + } + + /* Mark segment as received */ + rx->block |= BIT(seg_o); + + if (rx->block != BLOCK_COMPLETE(seg_n)) { + *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; + return 0; + } + + BT_DBG("Complete SDU"); + + *pdu_type = BLE_MESH_FRIEND_PDU_COMPLETE; + + /* Stop SAR Discard timer when processing result is Last Segment */ + k_delayed_work_cancel(&rx->dis_timer); + + /* Stop SAR ACK timer when processing result is Last Segment */ + if (BLE_MESH_ADDR_IS_UNICAST(rx->dst)) { + k_delayed_work_cancel(&rx->ack_timer); + } + + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, rx->block, rx->obo, rx); + + if (net_rx->ctl) { + err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); + } else { + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, + ASZMIC(hdr), &rx->buf); + } + + seg_rx_reset(rx, false); + + return err; +} + +int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) +{ + uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; + enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; + struct net_buf_simple_state state = {0}; + uint8_t seg_count = 0U; + int err = 0; + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, + rx->ctx.recv_dst); + } else { + rx->friend_match = false; + } + + BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); + + /* Remove network headers */ + net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); + + BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + + /* If LPN mode is enabled messages are only accepted when we've + * requested the Friend to send them. The messages must also + * be encrypted using the Friend Credentials. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + (!bt_mesh_lpn_waiting_update() || + rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { + BT_WARN("Ignoring unexpected message in Low Power mode"); + return -EAGAIN; + } + + /* Save the app-level state so the buffer can later be placed in + * the Friend Queue. + */ + net_buf_simple_save(buf, &state); + + if (SEG(buf->data)) { + /* Segmented messages must match a local element or an + * LPN of this Friend. + */ + if (!rx->local_match && !rx->friend_match) { + return 0; + } + + err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); + } else { + seg_count = 1U; + err = trans_unseg(buf, rx, &seq_auth); + } + + /* Notify LPN state machine so a Friend Poll will be sent. If the + * message was a Friend Update it's possible that a Poll was already + * queued for sending, however that's fine since then the + * bt_mesh_lpn_waiting_update() function will return false: + * we still need to go through the actual sending to the bearer and + * wait for ReceiveDelay before transitioning to WAIT_UPDATE state. + * Another situation where we want to notify the LPN state machine + * is if it's configured to use an automatic Friendship establishment + * timer, in which case we want to reset the timer at this point. + * + */ + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + (bt_mesh_lpn_timer() || + (bt_mesh_lpn_established() && bt_mesh_lpn_waiting_update()))) { + bt_mesh_lpn_msg_received(rx); + } + + net_buf_simple_restore(buf, &state); + + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->friend_match && !err) { + if (seq_auth == TRANS_SEQ_AUTH_NVAL) { + bt_mesh_friend_enqueue_rx(rx, pdu_type, NULL, + seg_count, buf); + } else { + bt_mesh_friend_enqueue_rx(rx, pdu_type, &seq_auth, + seg_count, buf); + } + } + + return err; +} + +void bt_mesh_rx_reset(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + seg_rx_reset(&seg_rx[i], true); + } +} + +void bt_mesh_tx_reset(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(seg_tx); i++) { + seg_tx_reset(&seg_tx[i]); + } +} + +void bt_mesh_rx_reset_single(uint16_t src) +{ + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; + if (src == rx->src) { + seg_rx_reset(rx, true); + } + } +} + +void bt_mesh_tx_reset_single(uint16_t dst) +{ + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(seg_tx); i++) { + struct seg_tx *tx = &seg_tx[i]; + if (dst == tx->dst) { + seg_tx_reset(tx); + } + } +} + +void bt_mesh_trans_init(void) +{ + bt_mesh_sar_init(); + + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + seg_rx[i].buf.__buf = (seg_rx_buf_data + (i * CONFIG_BLE_MESH_RX_SDU_MAX)); + seg_rx[i].buf.data = seg_rx[i].buf.__buf; + } + + bt_mesh_mutex_create(&seg_tx_lock); + bt_mesh_mutex_create(&seg_rx_lock); +} + +#if CONFIG_BLE_MESH_DEINIT +void bt_mesh_trans_deinit(bool erase) +{ + bt_mesh_rx_reset(); + bt_mesh_tx_reset(); + bt_mesh_rpl_reset(erase); + + bt_mesh_mutex_free(&seg_tx_lock); + bt_mesh_mutex_free(&seg_rx_lock); +} +#endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/core/transport.h b/components/bt/esp_ble_mesh/core/transport.h index 056ccc5b87..9c75ea77e9 100644 --- a/components/bt/esp_ble_mesh/core/transport.h +++ b/components/bt/esp_ble_mesh/core/transport.h @@ -96,7 +96,7 @@ struct bt_mesh_ctl_friend_sub_confirm { uint8_t bt_mesh_get_seg_rtx_num(void); -int32_t bt_mesh_get_seg_rtx_timeout(uint8_t ttl); +int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl); struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); diff --git a/components/bt/esp_ble_mesh/models/client/client_common.c b/components/bt/esp_ble_mesh/models/client/client_common.c index 9abce3d884..db87851613 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -198,7 +198,7 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, * All the messages sent from here are access messages. */ seg_rtx_num = bt_mesh_get_seg_rtx_num(); - seg_rtx_to = bt_mesh_get_seg_rtx_timeout(ctx->send_ttl); + seg_rtx_to = bt_mesh_get_seg_rtx_timeout(ctx->addr, ctx->send_ttl); seg_count = (msg->len + mic_size - 1) / 12U + 1U; duration = bt_mesh_get_adv_duration(ctx); diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h index 74a4b59374..da4fe8a0a6 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h @@ -63,15 +63,16 @@ typedef struct { sar_unicast_retrans_interval_step:4; /*!< SAR Unicast Retransmissions Interval Step state */ uint8_t sar_unicast_retrans_interval_increment:4, /*!< SAR Unicast Retransmissions Interval Increment state */ sar_multicast_retrans_count:4; /*!< SAR Multicast Retransmissions Count state */ - uint8_t sar_multicast_retrans_interval:4; /*!< SAR Multicast Retransmissions Interval state */ + uint8_t sar_multicast_retrans_interval_step:4; /*!< SAR Multicast Retransmissions Interval state */ } esp_ble_mesh_sar_transmitter_set_t; /** Parameters of SAR Receiver Set */ typedef struct { uint8_t sar_segments_threshold:5, /*!< SAR Segments Threshold state */ sar_ack_delay_increment:3; /*!< SAR Acknowledgment Delay Increment state */ - uint8_t sar_ack_retrans_count:2, /*!< SAR Acknowledgment Retransmissions Count state */ - sar_discard_timeout:4; /*!< SAR Discard Timeout state */ + uint8_t sar_discard_timeout:4, /*!< SAR Discard Timeout state */ + sar_receiver_segment_interval_step:4; /*!< SAR Receiver Segment Interval Step state */ + uint8_t sar_ack_retrans_count:4; /*!< SAR Acknowledgment Retransmissions Count state */ } esp_ble_mesh_sar_receiver_set_t; /** @@ -90,15 +91,16 @@ typedef struct { sar_unicast_retrans_interval_step:4; /*!< SAR Unicast Retransmissions Interval Step state */ uint8_t sar_unicast_retrans_interval_increment:4, /*!< SAR Unicast Retransmissions Interval Increment state */ sar_multicast_retrans_count:4; /*!< SAR Multicast Retransmissions Count state */ - uint8_t sar_multicast_retrans_interval:4; /*!< SAR Multicast Retransmissions Interval state */ + uint8_t sar_multicast_retrans_interval_step:4; /*!< SAR Multicast Retransmissions Interval state */ } esp_ble_mesh_sar_transmitter_status_t; /** Parameters of SAR Receiver Status */ typedef struct { uint8_t sar_segments_threshold:5, /*!< SAR Segments Threshold state */ sar_ack_delay_increment:3; /*!< SAR Acknowledgment Delay Increment state */ - uint8_t sar_ack_retrans_count:2, /*!< SAR Acknowledgment Retransmissions Count state */ - sar_discard_timeout:4; /*!< SAR Discard Timeout state */ + uint8_t sar_discard_timeout:4, /*!< SAR Discard Timeout state */ + sar_receiver_segment_interval_step:4; /*!< SAR Receiver Segment Interval Step state */ + uint8_t sar_ack_retrans_count:4; /*!< SAR Acknowledgment Retransmissions Count state */ } esp_ble_mesh_sar_receiver_status_t; /** Result of sending SAR Configuration Client messages */ diff --git a/components/bt/esp_ble_mesh/v1.1/ext.c b/components/bt/esp_ble_mesh/v1.1/ext.c index 048bcc1c59..3208ebb72a 100644 --- a/components/bt/esp_ble_mesh/v1.1/ext.c +++ b/components/bt/esp_ble_mesh/v1.1/ext.c @@ -76,6 +76,7 @@ #define CLI_PARAM(a) ((bt_mesh_client_common_param_t *)(a)) #define CLI_NODE(a) ((bt_mesh_client_node_t *)(a)) #define ADV_DATA(a) ((const struct bt_mesh_adv_data *)(a)) +#define RPL(a) ((struct bt_mesh_rpl *)(a)) #define VOID(a) ((void *)(a)) /* Sys utilities */ @@ -739,6 +740,11 @@ size_t bt_mesh_ext_comp_get_elem_count(const void *comp) return COMP(comp)->elem_count; } +void *bt_mesh_ext_comp_get_elem_s(const void *comp) +{ + return COMP(comp)->elem; +} + void *bt_mesh_ext_comp_get_elem(const void *comp, uint8_t index) { return &COMP(comp)->elem[index]; @@ -2228,6 +2234,56 @@ bool bt_mesh_ext_lpn_match(uint16_t addr) #endif /* CONFIG_BLE_MESH_LOW_POWER */ } +uint16_t bt_mesh_ext_lpn_frnd(void) +{ +#if CONFIG_BLE_MESH_LOW_POWER + return bt_mesh.lpn.frnd; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + +/* RPL */ +uint16_t bt_mesh_ext_rpl_get_src(void *rpl) +{ +#if CONFIG_BLE_MESH_LOW_POWER + return RPL(rpl)->src; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + +bool bt_mesh_ext_rpl_get_old_iv(void *rpl) +{ +#if CONFIG_BLE_MESH_LOW_POWER + return RPL(rpl)->old_iv; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + +uint32_t bt_mesh_ext_rpl_get_seq(void *rpl) +{ +#if CONFIG_BLE_MESH_LOW_POWER + return RPL(rpl)->seq; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + +void bt_mesh_ext_update_rpl(void *rpl, void *rx) +{ +#if CONFIG_BLE_MESH_LOW_POWER + bt_mesh_update_rpl(RPL(rpl), NET_RX(rx)); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + /* Adv */ uint8_t bt_mesh_ext_adv_data_get_type(const void *ad) { @@ -2558,16 +2614,6 @@ uint8_t *bt_mesh_ext_sub_get_mpb_random(void *sub) #endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ } -uint8_t *bt_mesh_ext_sub_get_mpb_random_last(void *sub) -{ -#if CONFIG_BLE_MESH_PRIVATE_BEACON - return SUBNET(sub)->mpb_random_last; -#else - assert(0); - return NULL; -#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ -} - uint8_t bt_mesh_ext_sub_get_private_node_id(void *sub) { #if CONFIG_BLE_MESH_PRIVATE_BEACON @@ -3419,6 +3465,21 @@ void bt_mesh_ext_net_rx_set_net_if(void *rx, uint8_t net_if) NET_RX(rx)->net_if = net_if; } +bool bt_mesh_ext_net_rx_get_old_iv(void *rx) +{ + return NET_RX(rx)->old_iv; +} + +bool bt_mesh_ext_net_rx_get_sbr_rpl(void *rx) +{ + return NET_RX(rx)->sbr_rpl; +} + +void bt_mesh_ext_net_rx_set_sbr_rpl(void *rx, bool sbr_rpl) +{ + NET_RX(rx)->sbr_rpl = sbr_rpl; +} + /* struct bt_mesh_msg_ctx */ uint16_t bt_mesh_ext_msg_ctx_get_net_idx(void *ctx) { @@ -3674,12 +3735,6 @@ int bt_mesh_ext_client_send_msg(void *param, struct net_buf_simple *msg, return bt_mesh_client_send_msg(param, msg, need_ack, VOID(timeout_cb)); } -/* Bridge Configuration */ -bool bt_mesh_ext_bridge_rpl_check(void *rx, void **match) -{ - return bt_mesh_bridge_rpl_check(rx, (struct bt_mesh_rpl **)match); -} - #if CONFIG_BLE_MESH_BRC_SRV struct bt_mesh_subnet_bridge_table { uint8_t bridge_direction; @@ -3695,6 +3750,8 @@ struct bt_mesh_bridge_cfg_srv { uint16_t bridging_table_size; struct bt_mesh_subnet_bridge_table bridge_table[CONFIG_BLE_MESH_MAX_BRIDGING_TABLE_ENTRY_COUNT]; }; + +static struct bt_mesh_rpl bridge_rpl[CONFIG_BLE_MESH_BRIDGE_CRPL]; #endif /* CONFIG_BLE_MESH_BRC_SRV */ void *bt_mesh_ext_brc_srv_get_bridge_table_entry(void *srv, uint8_t index) @@ -3707,6 +3764,16 @@ void *bt_mesh_ext_brc_srv_get_bridge_table_entry(void *srv, uint8_t index) #endif /* CONFIG_BLE_MESH_BRC_SRV */ } +void *bt_mesh_ext_brc_srv_get_bridge_rpl(uint8_t index) +{ +#if CONFIG_BLE_MESH_BRC_SRV + return &bridge_rpl[index]; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +} + /* BTC */ void bt_mesh_ext_agg_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, void *model, void *ctx, @@ -3935,6 +4002,7 @@ typedef struct { uint16_t config_ble_mesh_proxy_solic_rx_crpl; uint16_t config_ble_mesh_proxy_solic_tx_src_count; uint16_t config_ble_mesh_max_bridging_table_entry_count; + uint16_t config_ble_mesh_bridge_crpl; uint16_t config_ble_mesh_max_disc_table_entry_count; uint16_t config_ble_mesh_max_forward_table_entry_count; uint16_t config_ble_mesh_max_deps_nodes_per_path; @@ -4105,6 +4173,7 @@ static const bt_mesh_ext_config_t bt_mesh_ext_cfg = { #endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ #if CONFIG_BLE_MESH_BRC_SRV .config_ble_mesh_max_bridging_table_entry_count = CONFIG_BLE_MESH_MAX_BRIDGING_TABLE_ENTRY_COUNT, + .config_ble_mesh_bridge_crpl = CONFIG_BLE_MESH_BRIDGE_CRPL, #endif /* CONFIG_BLE_MESH_BRC_SRV */ #if CONFIG_BLE_MESH_DF_SRV .config_ble_mesh_max_disc_table_entry_count = CONFIG_BLE_MESH_MAX_DISC_TABLE_ENTRY_COUNT, @@ -4328,6 +4397,7 @@ typedef struct { /* CONFIG_BLE_MESH_LOW_POWER */ bool (*_bt_mesh_ext_lpn_match)(uint16_t addr); + uint16_t (*_bt_mesh_ext_lpn_frnd)(void); /* CONFIG_BLE_MESH_LOW_POWER */ /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ @@ -4448,7 +4518,6 @@ typedef struct { uint8_t (*_bt_mesh_ext_sub_get_mpb_ivi_last)(void *sub); void (*_bt_mesh_ext_sub_set_mpb_ivi_last)(void *sub, uint8_t mpb_ivi_last); uint8_t *(*_bt_mesh_ext_sub_get_mpb_random)(void *sub); - uint8_t *(*_bt_mesh_ext_sub_get_mpb_random_last)(void *sub); uint8_t (*_bt_mesh_ext_sub_get_private_node_id)(void *sub); uint8_t *(*_bt_mesh_ext_sub_get_keys_private_beacon)(void *sub, uint8_t index); /* CONFIG_BLE_MESH_PRIVATE_BEACON */ @@ -4457,6 +4526,7 @@ typedef struct { uint16_t (*_bt_mesh_ext_sub_get_sbr_net_idx)(void *sub); void (*_bt_mesh_ext_sub_set_sbr_net_idx)(void *sub, uint16_t sbr_net_idx); void *(*_bt_mesh_ext_brc_srv_get_bridge_table_entry)(void *srv, uint8_t index); + void *(*_bt_mesh_ext_brc_srv_get_bridge_rpl)(uint8_t index); /* CONFIG_BLE_MESH_BRC_SRV */ /* CONFIG_BLE_MESH_AGG_CLI */ @@ -4649,6 +4719,7 @@ static const bt_mesh_ext_funcs_t bt_mesh_ext_func = { /* CONFIG_BLE_MESH_LOW_POWER */ ._bt_mesh_ext_lpn_match = bt_mesh_ext_lpn_match, + ._bt_mesh_ext_lpn_frnd = bt_mesh_ext_lpn_frnd, /* CONFIG_BLE_MESH_LOW_POWER */ /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ @@ -4770,7 +4841,6 @@ static const bt_mesh_ext_funcs_t bt_mesh_ext_func = { ._bt_mesh_ext_sub_get_mpb_ivi_last = bt_mesh_ext_sub_get_mpb_ivi_last, ._bt_mesh_ext_sub_set_mpb_ivi_last = bt_mesh_ext_sub_set_mpb_ivi_last, ._bt_mesh_ext_sub_get_mpb_random = bt_mesh_ext_sub_get_mpb_random, - ._bt_mesh_ext_sub_get_mpb_random_last = bt_mesh_ext_sub_get_mpb_random_last, ._bt_mesh_ext_sub_get_private_node_id = bt_mesh_ext_sub_get_private_node_id, ._bt_mesh_ext_sub_get_keys_private_beacon = bt_mesh_ext_sub_get_keys_private_beacon, /* CONFIG_BLE_MESH_PRIVATE_BEACON */ @@ -4779,6 +4849,7 @@ static const bt_mesh_ext_funcs_t bt_mesh_ext_func = { ._bt_mesh_ext_sub_get_sbr_net_idx = bt_mesh_ext_sub_get_sbr_net_idx, ._bt_mesh_ext_sub_set_sbr_net_idx = bt_mesh_ext_sub_set_sbr_net_idx, ._bt_mesh_ext_brc_srv_get_bridge_table_entry = bt_mesh_ext_brc_srv_get_bridge_table_entry, + ._bt_mesh_ext_brc_srv_get_bridge_rpl = bt_mesh_ext_brc_srv_get_bridge_rpl, /* CONFIG_BLE_MESH_BRC_SRV */ /* CONFIG_BLE_MESH_AGG_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h index ab87a87e67..71a02314c8 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h @@ -119,6 +119,11 @@ int bt_mesh_directed_update_dependent_node(void *sub, uint8_t type, int bt_mesh_directed_forwarding_ctl_recv(uint8_t ctl_op, void *rx, struct net_buf_simple *buf); +void bt_mesh_restore_directed_forwarding_state(uint16_t net_idx, + uint8_t directed_forwarding); + +uint8_t bt_mesh_get_and_disable_directed_forwarding_state(void *sub); + int bt_mesh_directed_forwarding_sub_init(void *sub); int bt_mesh_recovery_directed_forwarding_table(void *sub); @@ -182,6 +187,8 @@ bool bt_mesh_bridge_change_net_key(void *rx, const uint8_t **enc, const uint8_t **priv, uint8_t *nid, uint8_t cred); +int bt_mesh_print_subnet_bridge_table(void); + void bt_mesh_disable_directed_proxy_state(uint16_t net_idx); void bt_mesh_disable_directed_friend_state(uint16_t net_idx); @@ -241,6 +248,30 @@ uint8_t bt_mesh_net_retrans_match(void *rx, uint8_t *cred, uint8_t *tag); bool bt_mesh_dev_key_ca_valid(void); +uint8_t bt_mesh_get_sar_sis(void); + +uint8_t bt_mesh_get_sar_urc(void); + +uint8_t bt_mesh_get_sar_urwpc(void); + +uint8_t bt_mesh_get_sar_uris(void); + +uint8_t bt_mesh_get_sar_urii(void); + +uint8_t bt_mesh_get_sar_mrc(void); + +uint8_t bt_mesh_get_sar_mris(void); + +uint8_t bt_mesh_get_sar_st(void); + +uint8_t bt_mesh_get_sar_adi(void); + +uint8_t bt_mesh_get_sar_arc(void); + +uint8_t bt_mesh_get_sar_dt(void); + +uint8_t bt_mesh_get_sar_rsis(void); + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a b/components/bt/esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a index 4fad457beb..5cec3f8e90 100644 Binary files a/components/bt/esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a and b/components/bt/esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a differ diff --git a/components/bt/esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a b/components/bt/esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a index 532c00ce4b..0d91c961ad 100644 Binary files a/components/bt/esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a and b/components/bt/esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a differ diff --git a/components/bt/esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a b/components/bt/esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a index 532c00ce4b..0d91c961ad 100644 Binary files a/components/bt/esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a and b/components/bt/esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a differ diff --git a/components/bt/esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a b/components/bt/esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a index 532c00ce4b..0d91c961ad 100644 Binary files a/components/bt/esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a and b/components/bt/esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a differ diff --git a/components/bt/esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a b/components/bt/esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a index 4fad457beb..5cec3f8e90 100644 Binary files a/components/bt/esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a and b/components/bt/esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a differ diff --git a/components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh b/components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh deleted file mode 100755 index 449c883d61..0000000000 --- a/components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh +++ /dev/null @@ -1,39 +0,0 @@ -#! /usr/bin/env bash - -echo "Copy Bluetooth Mesh v1.1 lib:" - -chip=$1 - -if [[ $chip != "esp32" && - $chip != "esp32s3" && - $chip != "esp32c3" && - $chip != "esp32c6" && - $chip != "esp32h2" && - $chip != "all" ]]; then - echo "Invalid Chip Target: $chip" - exit 0 -fi - -if [[ $chip == "esp32" || - $chip == "esp32s3" || - $chip == "esp32c3" || - $chip == "esp32c6" || - $chip == "esp32h2" ]]; then - cp ./build/$chip/libmesh_v1.1.a ./$chip/ - echo "Copy for $chip done!" -elif [[ $chip == "all" ]]; then - cp ./build/esp32/libmesh_v1.1.a ./esp32/ - echo "Copy for esp32 done!" - - cp ./build/esp32s3/libmesh_v1.1.a ./esp32s3/ - echo "Copy for esp32s3 done!" - - cp ./build/esp32c3/libmesh_v1.1.a ./esp32c3/ - echo "Copy for esp32c3 done!" - - cp ./build/esp32c6/libmesh_v1.1.a ./esp32c6/ - echo "Copy for esp32c6 done!" - - cp ./build/esp32h2/libmesh_v1.1.a ./esp32h2/ - echo "Copy for esp32h2 done!" -fi diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 068d03cb42..f0a4a6691d 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -1,5 +1,4 @@ components/app_update/otatool.py -components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh components/efuse/efuse_table_gen.py components/efuse/test_efuse_host/efuse_tests.py components/esp_coex/test_md5/test_md5.sh