From 5bab168b0e0c09cc0778a614314acf2d274a3006 Mon Sep 17 00:00:00 2001 From: Liu Linyan Date: Mon, 28 Aug 2023 16:09:37 +0800 Subject: [PATCH] feat(ble_mesh): Support Bluetooth Mesh Protocol v1.1 (Preview) --- components/bt/CMakeLists.txt | 52 +- components/bt/common/btc/core/btc_task.c | 70 + .../bt/common/btc/include/btc/btc_task.h | 20 + components/bt/esp_ble_mesh/Kconfig.in | 339 ++ .../esp_ble_mesh_local_data_operation_api.c | 14 + .../api/core/esp_ble_mesh_networking_api.c | 109 +- .../api/core/esp_ble_mesh_provisioning_api.c | 31 +- .../api/core/esp_ble_mesh_proxy_api.c | 53 + .../api/core/include/esp_ble_mesh_ble_api.h | 2 +- .../esp_ble_mesh_local_data_operation_api.h | 18 + .../include/esp_ble_mesh_networking_api.h | 53 +- .../api/core/include/esp_ble_mesh_proxy_api.h | 28 + .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 383 +- .../include/esp_ble_mesh_config_model_api.h | 19 +- .../include/esp_ble_mesh_lighting_model_api.h | 4 +- .../include/esp_ble_mesh_sensor_model_api.h | 2 +- .../esp_ble_mesh_time_scene_model_api.h | 4 +- .../btc/btc_ble_mesh_config_model.c | 109 +- .../btc/btc_ble_mesh_generic_model.c | 63 +- .../btc/btc_ble_mesh_health_model.c | 63 +- .../btc/btc_ble_mesh_lighting_model.c | 72 +- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 812 ++- .../btc/btc_ble_mesh_sensor_model.c | 66 +- .../btc/btc_ble_mesh_time_scene_model.c | 71 +- .../btc/include/btc_ble_mesh_config_model.h | 6 +- .../btc/include/btc_ble_mesh_generic_model.h | 6 +- .../btc/include/btc_ble_mesh_health_model.h | 3 +- .../btc/include/btc_ble_mesh_lighting_model.h | 6 +- .../btc/include/btc_ble_mesh_model_common.h | 42 + .../btc/include/btc_ble_mesh_prov.h | 41 +- .../btc/include/btc_ble_mesh_sensor_model.h | 6 +- .../include/btc_ble_mesh_time_scene_model.h | 8 +- components/bt/esp_ble_mesh/common/buf.c | 24 +- components/bt/esp_ble_mesh/common/common.c | 19 - .../bt/esp_ble_mesh/common/include/mesh/buf.h | 14 +- .../common/include/mesh/byteorder.h | 2 +- .../esp_ble_mesh/common/include/mesh/common.h | 14 - .../esp_ble_mesh/common/include/mesh/config.h | 14 + .../esp_ble_mesh/common/include/mesh/mutex.h | 5 + .../esp_ble_mesh/common/include/mesh/timer.h | 16 +- .../esp_ble_mesh/common/include/mesh/trace.h | 4 +- .../esp_ble_mesh/common/include/mesh/utils.h | 12 +- components/bt/esp_ble_mesh/common/mutex.c | 107 +- components/bt/esp_ble_mesh/common/timer.c | 88 +- components/bt/esp_ble_mesh/core/access.c | 437 +- components/bt/esp_ble_mesh/core/access.h | 11 +- components/bt/esp_ble_mesh/core/adv.c | 119 +- components/bt/esp_ble_mesh/core/adv.h | 29 +- components/bt/esp_ble_mesh/core/beacon.c | 322 +- components/bt/esp_ble_mesh/core/beacon.h | 19 +- .../core/bluedroid_host/adapter.c | 102 +- components/bt/esp_ble_mesh/core/cfg_cli.c | 83 +- components/bt/esp_ble_mesh/core/cfg_srv.c | 498 +- components/bt/esp_ble_mesh/core/crypto.c | 49 +- components/bt/esp_ble_mesh/core/crypto.h | 12 +- components/bt/esp_ble_mesh/core/fast_prov.c | 24 +- components/bt/esp_ble_mesh/core/foundation.h | 340 +- components/bt/esp_ble_mesh/core/friend.c | 158 +- components/bt/esp_ble_mesh/core/friend.h | 1 + components/bt/esp_ble_mesh/core/health_cli.c | 73 +- components/bt/esp_ble_mesh/core/health_srv.c | 14 - .../esp_ble_mesh/core/include/mesh/access.h | 100 +- .../esp_ble_mesh/core/include/mesh/adapter.h | 43 +- .../bt/esp_ble_mesh/core/include/mesh/hci.h | 6 +- .../bt/esp_ble_mesh/core/include/mesh/main.h | 146 +- .../bt/esp_ble_mesh/core/include/mesh/uuid.h | 4 + components/bt/esp_ble_mesh/core/local.c | 42 +- components/bt/esp_ble_mesh/core/local.h | 5 + components/bt/esp_ble_mesh/core/lpn.c | 111 +- components/bt/esp_ble_mesh/core/lpn.h | 8 +- components/bt/esp_ble_mesh/core/main.c | 163 +- components/bt/esp_ble_mesh/core/mesh.h | 18 +- components/bt/esp_ble_mesh/core/net.c | 761 ++- components/bt/esp_ble_mesh/core/net.h | 199 +- .../esp_ble_mesh/core/nimble_host/adapter.c | 107 +- components/bt/esp_ble_mesh/core/prov_common.c | 684 +++ components/bt/esp_ble_mesh/core/prov_common.h | 333 ++ components/bt/esp_ble_mesh/core/prov_node.c | 1864 +++---- components/bt/esp_ble_mesh/core/prov_node.h | 14 +- components/bt/esp_ble_mesh/core/prov_pvnr.c | 3019 +++++----- components/bt/esp_ble_mesh/core/prov_pvnr.h | 48 +- .../bt/esp_ble_mesh/core/proxy_client.c | 357 +- .../bt/esp_ble_mesh/core/proxy_client.h | 38 +- .../bt/esp_ble_mesh/core/proxy_common.h | 67 + .../bt/esp_ble_mesh/core/proxy_server.c | 849 ++- .../bt/esp_ble_mesh/core/proxy_server.h | 67 +- components/bt/esp_ble_mesh/core/pvnr_mgmt.c | 184 +- components/bt/esp_ble_mesh/core/pvnr_mgmt.h | 15 +- components/bt/esp_ble_mesh/core/rpl.c | 141 + components/bt/esp_ble_mesh/core/rpl.h | 35 + components/bt/esp_ble_mesh/core/scan.c | 247 +- components/bt/esp_ble_mesh/core/scan.h | 11 + .../bt/esp_ble_mesh/core/storage/settings.c | 252 +- .../bt/esp_ble_mesh/core/storage/settings.h | 5 +- .../esp_ble_mesh/core/storage/settings_nvs.c | 6 +- .../esp_ble_mesh/core/storage/settings_nvs.h | 2 + .../esp_ble_mesh/core/storage/settings_uid.c | 4 +- components/bt/esp_ble_mesh/core/test.c | 28 +- components/bt/esp_ble_mesh/core/test.h | 12 +- components/bt/esp_ble_mesh/core/transport.c | 648 +-- components/bt/esp_ble_mesh/core/transport.h | 73 +- .../models/client/client_common.c | 130 +- .../models/client/generic_client.c | 77 +- .../client/include/mesh/client_common.h | 29 +- .../models/client/lighting_client.c | 77 +- .../models/client/sensor_client.c | 75 +- .../models/client/time_scene_client.c | 75 +- .../common/include/mesh/device_property.h | 46 +- .../models/common/include/mesh/model_common.h | 27 + .../models/common/include/mesh/model_opcode.h | 405 +- .../esp_ble_mesh/models/common/model_common.c | 47 + .../models/server/generic_server.c | 265 +- .../server/include/mesh/sensor_server.h | 2 +- .../server/include/mesh/time_scene_server.h | 2 +- .../models/server/lighting_server.c | 334 +- .../models/server/sensor_server.c | 103 +- .../models/server/server_common.c | 17 +- .../models/server/state_binding.c | 38 +- .../models/server/state_transition.c | 272 +- .../models/server/time_scene_server.c | 128 +- .../api/core/esp_ble_mesh_agg_model_api.c | 56 + .../api/core/esp_ble_mesh_brc_model_api.c | 70 + .../v1.1/api/core/esp_ble_mesh_cm_data_api.c | 38 + .../v1.1/api/core/esp_ble_mesh_df_model_api.c | 102 + .../api/core/esp_ble_mesh_lcd_model_api.c | 56 + .../api/core/esp_ble_mesh_odp_model_api.c | 57 + .../api/core/esp_ble_mesh_prb_model_api.c | 69 + .../api/core/esp_ble_mesh_rpr_model_api.c | 94 + .../api/core/esp_ble_mesh_sar_model_api.c | 58 + .../api/core/esp_ble_mesh_srpl_model_api.c | 56 + .../core/include/esp_ble_mesh_agg_model_api.h | 218 + .../core/include/esp_ble_mesh_brc_model_api.h | 322 ++ .../core/include/esp_ble_mesh_cm_data_api.h | 136 + .../core/include/esp_ble_mesh_df_model_api.h | 746 +++ .../core/include/esp_ble_mesh_lcd_model_api.h | 211 + .../core/include/esp_ble_mesh_odp_model_api.h | 205 + .../core/include/esp_ble_mesh_prb_model_api.h | 258 + .../core/include/esp_ble_mesh_rpr_model_api.h | 479 ++ .../core/include/esp_ble_mesh_sar_model_api.h | 223 + .../include/esp_ble_mesh_srpl_model_api.h | 198 + .../api/models/esp_ble_mesh_mbt_model_api.c | 421 ++ .../include/esp_ble_mesh_mbt_model_api.h | 693 +++ .../v1.1/btc/btc_ble_mesh_agg_model.c | 490 ++ .../v1.1/btc/btc_ble_mesh_brc_model.c | 462 ++ .../v1.1/btc/btc_ble_mesh_df_model.c | 711 +++ .../v1.1/btc/btc_ble_mesh_lcd_model.c | 435 ++ .../v1.1/btc/btc_ble_mesh_mbt_model.c | 600 ++ .../v1.1/btc/btc_ble_mesh_odp_model.c | 380 ++ .../v1.1/btc/btc_ble_mesh_prb_model.c | 404 ++ .../v1.1/btc/btc_ble_mesh_rpr_model.c | 543 ++ .../v1.1/btc/btc_ble_mesh_sar_model.c | 389 ++ .../v1.1/btc/btc_ble_mesh_srpl_model.c | 370 ++ .../v1.1/btc/include/btc_ble_mesh_agg_model.h | 70 + .../v1.1/btc/include/btc_ble_mesh_brc_model.h | 70 + .../v1.1/btc/include/btc_ble_mesh_df_model.h | 77 + .../v1.1/btc/include/btc_ble_mesh_lcd_model.h | 70 + .../v1.1/btc/include/btc_ble_mesh_mbt_model.h | 143 + .../v1.1/btc/include/btc_ble_mesh_odp_model.h | 70 + .../v1.1/btc/include/btc_ble_mesh_prb_model.h | 70 + .../v1.1/btc/include/btc_ble_mesh_rpr_model.h | 86 + .../v1.1/btc/include/btc_ble_mesh_sar_model.h | 70 + .../btc/include/btc_ble_mesh_srpl_model.h | 70 + components/bt/esp_ble_mesh/v1.1/ext.c | 4836 +++++++++++++++++ .../v1.1/include/mesh_v1.1/utils.h | 248 + .../v1.1/lib/esp32/libmesh_v1.1.a | Bin 0 -> 667916 bytes .../v1.1/lib/esp32c3/libmesh_v1.1.a | Bin 0 -> 1459768 bytes .../v1.1/lib/esp32c6/libmesh_v1.1.a | Bin 0 -> 1459768 bytes .../v1.1/lib/esp32h2/libmesh_v1.1.a | Bin 0 -> 1459768 bytes .../v1.1/lib/esp32s3/libmesh_v1.1.a | Bin 0 -> 667916 bytes .../bt/esp_ble_mesh/v1.1/lib/lib_copy.sh | 39 + docs/doxygen/Doxyfile | 11 + .../esp-ble-mesh/ble-mesh-architecture.rst | 2 +- .../api-guides/esp-ble-mesh/ble-mesh-faq.rst | 2 +- .../esp-ble-mesh/ble-mesh-feature-list.rst | 39 +- .../esp-ble-mesh/ble-mesh-index.rst | 8 +- .../esp-ble-mesh/ble-mesh-terminology.rst | 72 +- .../api-reference/bluetooth/esp-ble-mesh.rst | 4 + .../esp-ble-mesh/ble-mesh-architecture.rst | 2 +- .../api-guides/esp-ble-mesh/ble-mesh-faq.rst | 2 +- .../esp-ble-mesh/ble-mesh-index.rst | 8 +- .../esp-ble-mesh/ble-mesh-terminology.rst | 69 +- .../components/vendor_model/genie_model_srv.c | 1 - .../ble_mesh_fast_prov_client_model.c | 7 - .../fast_prov/ble_mesh_fast_prov_operation.c | 11 - .../light_driver/CMakeLists.txt | 6 +- .../light_driver/include/led_strip_encoder.h | 41 + .../common_components/light_driver/iot_led.c | 4 + .../light_driver/led_strip_encoder.c | 178 + .../directed_forwarding/README.md | 56 + .../df_client/CMakeLists.txt | 11 + .../df_client/main/CMakeLists.txt | 7 + .../df_client/main/Kconfig.projbuild | 38 + .../df_client/main/board.c | 88 + .../df_client/main/board.h | 56 + .../directed_forwarding/df_client/main/main.c | 916 ++++ .../df_client/sdkconfig.defaults | 23 + .../df_client/sdkconfig.defaults.esp32c3 | 17 + .../df_client/sdkconfig.defaults.esp32c6 | 19 + .../df_client/sdkconfig.defaults.esp32h2 | 29 + .../df_client/sdkconfig.defaults.esp32s3 | 17 + .../df_server/CMakeLists.txt | 10 + .../df_server/main/CMakeLists.txt | 5 + .../df_server/main/Kconfig.projbuild | 38 + .../df_server/main/board.c | 78 + .../df_server/main/board.h | 47 + .../directed_forwarding/df_server/main/main.c | 501 ++ .../df_server/sdkconfig.defaults | 22 + .../df_server/sdkconfig.defaults.esp32c3 | 16 + .../df_server/sdkconfig.defaults.esp32c6 | 18 + .../df_server/sdkconfig.defaults.esp32h2 | 18 + .../df_server/sdkconfig.defaults.esp32s3 | 16 + ...Directed_Forwarding_Example_Walkthrough.md | 318 ++ .../images/directed_forwarding_sequence.png | Bin 0 -> 74836 bytes .../fast_prov_client/main/main.c | 3 - .../fast_prov_client/sdkconfig.defaults | 2 + ...sh_Fast_Prov_Client_Example_Walkthrough.md | 3 - .../fast_prov_server/main/main.c | 3 - .../fast_prov_server/sdkconfig.defaults | 2 + ...sh_Fast_Prov_Server_Example_Walkthrough.md | 3 - .../onoff_models/onoff_client/main/main.c | 2 - .../onoff_client/sdkconfig.defaults | 2 + ...h_Node_OnOff_Client_Example_Walkthrough.md | 2 - .../onoff_server/sdkconfig.defaults | 2 + .../esp_ble_mesh/provisioner/main/main.c | 3 - .../provisioner/sdkconfig.defaults | 1 + .../remote_provisioning/README.md | 58 + .../rpr_client/CMakeLists.txt | 11 + .../rpr_client/main/CMakeLists.txt | 6 + .../rpr_client/main/Kconfig.projbuild | 38 + .../rpr_client/main/board.c | 73 + .../rpr_client/main/board.h | 51 + .../rpr_client/main/main.c | 1144 ++++ .../rpr_client/sdkconfig.defaults | 21 + .../rpr_client/sdkconfig.defaults.esp32c3 | 17 + .../rpr_client/sdkconfig.defaults.esp32c6 | 19 + .../rpr_client/sdkconfig.defaults.esp32h2 | 19 + .../rpr_client/sdkconfig.defaults.esp32s3 | 17 + .../rpr_server/CMakeLists.txt | 10 + .../rpr_server/main/CMakeLists.txt | 5 + .../rpr_server/main/Kconfig.projbuild | 38 + .../rpr_server/main/board.c | 44 + .../rpr_server/main/board.h | 51 + .../rpr_server/main/main.c | 469 ++ .../rpr_server/sdkconfig.defaults | 20 + .../rpr_server/sdkconfig.defaults.esp32c3 | 16 + .../rpr_server/sdkconfig.defaults.esp32c6 | 18 + .../rpr_server/sdkconfig.defaults.esp32h2 | 18 + .../rpr_server/sdkconfig.defaults.esp32s3 | 16 + ...Remote_Provisioning_Example_Walkthrough.md | 504 ++ .../tutorial/images/message_sequence.png | Bin 0 -> 61049 bytes .../unprov_dev/CMakeLists.txt | 10 + .../unprov_dev/main/CMakeLists.txt | 5 + .../unprov_dev/main/Kconfig.projbuild | 38 + .../unprov_dev/main/board.c | 44 + .../unprov_dev/main/board.h | 51 + .../unprov_dev/main/main.c | 343 ++ .../unprov_dev/sdkconfig.defaults | 19 + .../unprov_dev/sdkconfig.defaults.esp32c3 | 16 + .../unprov_dev/sdkconfig.defaults.esp32c6 | 18 + .../unprov_dev/sdkconfig.defaults.esp32h2 | 18 + .../unprov_dev/sdkconfig.defaults.esp32s3 | 16 + .../sensor_models/sensor_client/main/main.c | 3 - .../sensor_client/sdkconfig.defaults | 1 + .../sensor_server/sdkconfig.defaults | 1 + .../vendor_models/vendor_client/main/main.c | 4 - .../vendor_client/sdkconfig.defaults | 1 + .../vendor_server/sdkconfig.defaults | 1 + .../esp_ble_mesh/wifi_coexist/main/main.c | 3 - tools/ci/executable-list.txt | 1 + .../sdkconfig.ci.noasserts.nimble | 1 - .../sdkconfig.ci.silentasserts.nimble | 1 - 271 files changed, 32403 insertions(+), 7253 deletions(-) create mode 100644 components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h create mode 100644 components/bt/esp_ble_mesh/core/prov_common.c create mode 100644 components/bt/esp_ble_mesh/core/prov_common.h create mode 100644 components/bt/esp_ble_mesh/core/proxy_common.h create mode 100644 components/bt/esp_ble_mesh/core/rpl.c create mode 100644 components/bt/esp_ble_mesh/core/rpl.h create mode 100644 components/bt/esp_ble_mesh/models/common/include/mesh/model_common.h create mode 100644 components/bt/esp_ble_mesh/models/common/model_common.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_agg_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_brc_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_cm_data_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_df_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_lcd_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_odp_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_prb_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_rpr_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_agg_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_brc_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_cm_data_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_df_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_lcd_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_odp_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_prb_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_prb_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_agg_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_brc_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_df_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_lcd_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_odp_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_prb_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_rpr_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_sar_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_srpl_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/ext.c create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h create mode 100644 components/bt/esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a create mode 100644 components/bt/esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a create mode 100644 components/bt/esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a create mode 100644 components/bt/esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a create mode 100644 components/bt/esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a create mode 100755 components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh create mode 100644 examples/bluetooth/esp_ble_mesh/common_components/light_driver/include/led_strip_encoder.h create mode 100644 examples/bluetooth/esp_ble_mesh/common_components/light_driver/led_strip_encoder.c create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/README.md create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/Kconfig.projbuild create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.c create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.h create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/main.c create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c3 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c6 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32h2 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32s3 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/Kconfig.projbuild create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.c create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.h create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/main.c create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c3 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c6 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32h2 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32s3 create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/images/directed_forwarding_sequence.png create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/README.md create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/Kconfig.projbuild create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.h create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c3 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c6 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32h2 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32s3 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/Kconfig.projbuild create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.h create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/main.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c3 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c6 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32h2 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32s3 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/images/message_sequence.png create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/CMakeLists.txt create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/Kconfig.projbuild create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.h create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/main.c create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c3 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c6 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32h2 create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32s3 diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 1ec32112da..9f39dcf57b 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -390,7 +390,11 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/models/server/include" "esp_ble_mesh/api/core/include" "esp_ble_mesh/api/models/include" - "esp_ble_mesh/api") + "esp_ble_mesh/api" + "esp_ble_mesh/v1.1/api/core/include" + "esp_ble_mesh/v1.1/api/models/include" + "esp_ble_mesh/v1.1/btc/include" + "esp_ble_mesh/v1.1/include") list(APPEND srcs "esp_ble_mesh/api/core/esp_ble_mesh_ble_api.c" "esp_ble_mesh/api/core/esp_ble_mesh_common_api.c" @@ -452,15 +456,18 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/core/lpn.c" "esp_ble_mesh/core/main.c" "esp_ble_mesh/core/net.c" + "esp_ble_mesh/core/prov_common.c" "esp_ble_mesh/core/prov_node.c" "esp_ble_mesh/core/prov_pvnr.c" "esp_ble_mesh/core/proxy_client.c" "esp_ble_mesh/core/proxy_server.c" "esp_ble_mesh/core/pvnr_mgmt.c" + "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" "esp_ble_mesh/models/client/generic_client.c" "esp_ble_mesh/models/client/lighting_client.c" @@ -472,7 +479,29 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/models/server/server_common.c" "esp_ble_mesh/models/server/state_binding.c" "esp_ble_mesh/models/server/state_transition.c" - "esp_ble_mesh/models/server/time_scene_server.c") + "esp_ble_mesh/models/server/time_scene_server.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_agg_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_brc_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_cm_data_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_df_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_lcd_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_odp_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_prb_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_rpr_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c" + "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c" + "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_prb_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c" + "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") endif() @@ -741,6 +770,25 @@ if(CONFIG_BT_ENABLED) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") endif() +if(CONFIG_BLE_MESH) + if(CONFIG_IDF_TARGET_ESP32) + add_prebuilt_library(mesh_v11 "esp_ble_mesh/v1.1/lib/esp32/libmesh_v1.1.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE mesh_v11) + elseif(CONFIG_IDF_TARGET_ESP32S3) + add_prebuilt_library(mesh_v11 "esp_ble_mesh/v1.1/lib/esp32s3/libmesh_v1.1.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE mesh_v11) + elseif(CONFIG_IDF_TARGET_ESP32C3) + add_prebuilt_library(mesh_v11 "esp_ble_mesh/v1.1/lib/esp32c3/libmesh_v1.1.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE mesh_v11) + elseif(CONFIG_IDF_TARGET_ESP32C6) + add_prebuilt_library(mesh_v11 "esp_ble_mesh/v1.1/lib/esp32c6/libmesh_v1.1.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE mesh_v11) + elseif(CONFIG_IDF_TARGET_ESP32H2) + add_prebuilt_library(mesh_v11 "esp_ble_mesh/v1.1/lib/esp32h2/libmesh_v1.1.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE mesh_v11) + endif() +endif() + if(CONFIG_BT_NIMBLE_MESH) set_source_files_properties("host/nimble/nimble/nimble/host/mesh/src/net.c" PROPERTIES COMPILE_FLAGS -Wno-type-limits) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 93f36b5e23..179d501e72 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -69,10 +69,20 @@ #include "btc_ble_mesh_prov.h" #include "btc_ble_mesh_health_model.h" #include "btc_ble_mesh_config_model.h" +#include "btc_ble_mesh_agg_model.h" +#include "btc_ble_mesh_brc_model.h" +#include "btc_ble_mesh_df_model.h" +#include "btc_ble_mesh_lcd_model.h" +#include "btc_ble_mesh_odp_model.h" +#include "btc_ble_mesh_prb_model.h" +#include "btc_ble_mesh_rpr_model.h" +#include "btc_ble_mesh_sar_model.h" +#include "btc_ble_mesh_srpl_model.h" #include "btc_ble_mesh_generic_model.h" #include "btc_ble_mesh_lighting_model.h" #include "btc_ble_mesh_sensor_model.h" #include "btc_ble_mesh_time_scene_model.h" +#include "btc_ble_mesh_mbt_model.h" #endif /* #if CONFIG_BLE_MESH */ #define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) @@ -158,6 +168,60 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_CONFIG_CLIENT] = {btc_ble_mesh_config_client_call_handler, btc_ble_mesh_config_client_cb_handler }, #endif /* CONFIG_BLE_MESH_CFG_CLI */ [BTC_PID_CONFIG_SERVER] = {NULL, btc_ble_mesh_config_server_cb_handler }, +#if CONFIG_BLE_MESH_AGG_CLI + [BTC_PID_AGG_CLIENT] = {btc_ble_mesh_agg_client_call_handler, btc_ble_mesh_agg_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_AGG_CLI */ +#if CONFIG_BLE_MESH_AGG_SRV + [BTC_PID_AGG_SERVER] = {NULL, btc_ble_mesh_agg_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_AGG_SRV */ +#if CONFIG_BLE_MESH_BRC_CLI + [BTC_PID_BRC_CLIENT] = {btc_ble_mesh_brc_client_call_handler, btc_ble_mesh_brc_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_BRC_CLI */ +#if CONFIG_BLE_MESH_BRC_SRV + [BTC_PID_BRC_SERVER] = {NULL, btc_ble_mesh_brc_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +#if CONFIG_BLE_MESH_DF_CLI + [BTC_PID_DF_CLIENT] = {btc_ble_mesh_df_client_call_handler, btc_ble_mesh_df_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_DF_CLI */ +#if CONFIG_BLE_MESH_DF_SRV + [BTC_PID_DF_SERVER] = {NULL, btc_ble_mesh_df_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_DF_SRV */ +#if CONFIG_BLE_MESH_LCD_CLI + [BTC_PID_LCD_CLIENT] = {btc_ble_mesh_lcd_client_call_handler, btc_ble_mesh_lcd_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_LCD_CLI */ +#if CONFIG_BLE_MESH_LCD_SRV + [BTC_PID_LCD_SERVER] = {NULL, btc_ble_mesh_lcd_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_LCD_SRV */ +#if CONFIG_BLE_MESH_ODP_CLI + [BTC_PID_ODP_CLIENT] = {btc_ble_mesh_odp_client_call_handler, btc_ble_mesh_odp_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_ODP_CLI */ +#if CONFIG_BLE_MESH_ODP_SRV + [BTC_PID_ODP_SERVER] = {NULL, btc_ble_mesh_odp_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_ODP_SRV */ +#if CONFIG_BLE_MESH_PRB_CLI + [BTC_PID_PRB_CLIENT] = {btc_ble_mesh_prb_client_call_handler, btc_ble_mesh_prb_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_PRB_CLI */ +#if CONFIG_BLE_MESH_PRB_SRV + [BTC_PID_PRB_SERVER] = {NULL, btc_ble_mesh_prb_server_cb_handler }, +#endif /*CONFIG_BLE_MESH_PRB_SRV*/ +#if CONFIG_BLE_MESH_RPR_CLI + [BTC_PID_RPR_CLIENT] = {btc_ble_mesh_rpr_client_call_handler, btc_ble_mesh_rpr_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +#if CONFIG_BLE_MESH_RPR_SRV + [BTC_PID_RPR_SERVER] = {NULL, btc_ble_mesh_rpr_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +#if CONFIG_BLE_MESH_SAR_CLI + [BTC_PID_SAR_CLIENT] = {btc_ble_mesh_sar_client_call_handler, btc_ble_mesh_sar_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_SAR_CLI */ +#if CONFIG_BLE_MESH_SAR_SRV + [BTC_PID_SAR_SERVER] = {NULL, btc_ble_mesh_sar_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_SAR_SRV */ +#if CONFIG_BLE_MESH_SRPL_CLI + [BTC_PID_SRPL_CLIENT] = {btc_ble_mesh_srpl_client_call_handler, btc_ble_mesh_srpl_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ +#if CONFIG_BLE_MESH_SRPL_SRV + [BTC_PID_SRPL_SERVER] = {NULL, btc_ble_mesh_srpl_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_SRPL_SRV */ #if CONFIG_BLE_MESH_GENERIC_CLIENT [BTC_PID_GENERIC_CLIENT] = {btc_ble_mesh_generic_client_call_handler, btc_ble_mesh_generic_client_cb_handler }, #endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */ @@ -182,6 +246,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { #if CONFIG_BLE_MESH_TIME_SCENE_SERVER [BTC_PID_TIME_SCENE_SERVER] = {NULL, btc_ble_mesh_time_scene_server_cb_handler}, #endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */ +#if CONFIG_BLE_MESH_MBT_CLI + [BTC_PID_MBT_CLIENT] = {btc_ble_mesh_mbt_client_call_handler, btc_ble_mesh_mbt_client_cb_handler }, +#endif /* CONFIG_BLE_MESH_MBT_CLI */ +#if CONFIG_BLE_MESH_MBT_SRV + [BTC_PID_MBT_SERVER] = {btc_ble_mesh_mbt_server_call_handler, btc_ble_mesh_mbt_server_cb_handler }, +#endif /* CONFIG_BLE_MESH_MBT_SRV */ #if CONFIG_BLE_MESH_BLE_COEX_SUPPORT [BTC_PID_BLE_MESH_BLE_COEX] = {btc_ble_mesh_ble_call_handler, btc_ble_mesh_ble_cb_handler }, #endif /* CONFIG_BLE_MESH_BLE_COEX_SUPPORT */ diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index ef286c3236..232186b51c 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -75,6 +75,24 @@ typedef enum { BTC_PID_HEALTH_SERVER, BTC_PID_CONFIG_CLIENT, BTC_PID_CONFIG_SERVER, + BTC_PID_AGG_CLIENT, + BTC_PID_AGG_SERVER, + BTC_PID_BRC_CLIENT, + BTC_PID_BRC_SERVER, + BTC_PID_DF_CLIENT, + BTC_PID_DF_SERVER, + BTC_PID_LCD_CLIENT, + BTC_PID_LCD_SERVER, + BTC_PID_ODP_CLIENT, + BTC_PID_ODP_SERVER, + BTC_PID_PRB_CLIENT, + BTC_PID_PRB_SERVER, + BTC_PID_RPR_CLIENT, + BTC_PID_RPR_SERVER, + BTC_PID_SAR_CLIENT, + BTC_PID_SAR_SERVER, + BTC_PID_SRPL_CLIENT, + BTC_PID_SRPL_SERVER, BTC_PID_GENERIC_CLIENT, BTC_PID_LIGHTING_CLIENT, BTC_PID_SENSOR_CLIENT, @@ -83,6 +101,8 @@ typedef enum { BTC_PID_LIGHTING_SERVER, BTC_PID_SENSOR_SERVER, BTC_PID_TIME_SCENE_SERVER, + BTC_PID_MBT_CLIENT, + BTC_PID_MBT_SERVER, BTC_PID_BLE_MESH_BLE_COEX, #endif /* CONFIG_BLE_MESH */ BTC_PID_NUM, diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index 807f1a4fe3..ac5548d140 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -21,6 +21,11 @@ if BLE_MESH option in the Bluetooth Controller section in menuconfig, which is "Scan Duplicate By Device Address and Advertising Data". + config BLE_MESH_ACTIVE_SCAN + bool "Support Active Scan in BLE Mesh" + help + Enable this option to allow using BLE Active Scan for BLE Mesh. + choice BLE_MESH_MEM_ALLOC_MODE prompt "Memory allocation strategy" default BLE_MESH_MEM_ALLOC_MODE_INTERNAL @@ -264,6 +269,31 @@ if BLE_MESH Enable this option to support BLE Mesh Provisioning functionality. For BLE Mesh, this option should be always enabled. + config BLE_MESH_PROV_EPA + bool "BLE Mesh enhanced provisioning authentication" + depends on BLE_MESH_PROV + default y + help + Enable this option to support BLE Mesh enhanced provisioning authentication + functionality. This option can increase the security level of provisioning. + It is recommended to enable this option. + + config BLE_MESH_CERT_BASED_PROV + bool "Support Certificate-based provisioning" + depends on BLE_MESH_PROV + default n + help + Enable this option to support BLE Mesh Certificate-Based Provisioning. + + config BLE_MESH_RECORD_FRAG_MAX_SIZE + int "Maximum size of the provisioning record fragment that Provisioner can receive" + depends on BLE_MESH_CERT_BASED_PROV + default 56 + range 1 57 + help + This option sets the maximum size of the provisioning record fragment that the + Provisioner can receive. The range depends on provisioning bearer. + config BLE_MESH_PB_ADV bool "Provisioning support using the advertising bearer (PB-ADV)" select BLE_MESH_PROV @@ -338,6 +368,34 @@ if BLE_MESH list of addresses which can be used to decide which messages will be forwarded to the Proxy Client by the Proxy Server. + config BLE_MESH_PROXY_PRIVACY + bool "Support Proxy Privacy" + depends on BLE_MESH_PRB_SRV && BLE_MESH_GATT_PROXY_SERVER + default y + help + The Proxy Privacy parameter controls the privacy of the Proxy Server + over the connection. The value of the Proxy Privacy parameter is + controlled by the type of proxy connection, which is dependent on the + bearer used by the proxy connection. + + config BLE_MESH_PROXY_SOLIC_PDU_RX + bool "Support receiving Proxy Solicitation PDU" + depends on BLE_MESH_GATT_PROXY_SERVER + help + Enable this option to support receiving Proxy Solicitation PDU. + + config BLE_MESH_PROXY_SOLIC_RX_CRPL + int "Maximum capacity of solicitation replay protection list" + depends on BLE_MESH_PROXY_SOLIC_PDU_RX + default 2 + range 1 255 + help + This option specifies the maximum capacity of the solicitation replay + protection list. The solicitation replay protection list is used to + reject Solicitation PDUs that were already processed by a node, which + will store the solicitation src and solicitation sequence number of + the received Solicitation PDU message. + config BLE_MESH_GATT_PROXY_CLIENT bool "BLE Mesh GATT Proxy Client" select BLE_MESH_PROXY @@ -347,6 +405,25 @@ if BLE_MESH can use the GATT bearer to send mesh messages to a node that supports the advertising bearer. + config BLE_MESH_PROXY_SOLIC_PDU_TX + bool "Support sending Proxy Solicitation PDU" + depends on BLE_MESH_GATT_PROXY_CLIENT + help + Enable this option to support sending Proxy Solicitation PDU. + + config BLE_MESH_PROXY_SOLIC_TX_SRC_COUNT + int "Maximum number of SSRC that can be used by Proxy Client" + depends on BLE_MESH_PROXY_SOLIC_PDU_TX + default 2 + range 1 16 + help + This option specifies the maximum number of Solicitation Source (SSRC) + that can be used by Proxy Client for sending a Solicitation PDU. + A Proxy Client may use the primary address or any of the secondary + addresses as the SSRC for a Solicitation PDU. + So for a Proxy Client, it's better to choose the value based on its + own element count. + config BLE_MESH_NET_BUF_POOL_USAGE bool default y @@ -994,6 +1071,244 @@ if BLE_MESH help Enable support for Health Server model. + config BLE_MESH_BRC_CLI + bool "Bridge Configuration Client model" + help + Enable support for Bridge Configuration Client model. + + config BLE_MESH_BRC_SRV + bool "Bridge Configuration Server model" + default n + help + Enable support for Bridge Configuration Server model. + + if BLE_MESH_BRC_SRV + + config BLE_MESH_MAX_BRIDGING_TABLE_ENTRY_COUNT + int "Maximum number of Bridging Table entries" + range 16 65535 + default 16 + help + Maximum number of Bridging Table entries that the Bridge Configuration Server can support. + + endif #BLE_MESH_BRC_SRV + + config BLE_MESH_PRB_CLI + bool "Mesh Private Beacon Client model" + help + Enable support for Mesh Private Beacon Client model. + + config BLE_MESH_PRB_SRV + bool "Mesh Private Beacon Server model" + help + Enable support for Mesh Private Beacon Server model. + + config BLE_MESH_ODP_CLI + bool "On-Demand Private Proxy Client model" + help + Enable support for On-Demand Private Proxy Client model. + + config BLE_MESH_ODP_SRV + bool "On-Demand Private Proxy Server model" + depends on BLE_MESH_PROXY_SOLIC_PDU_RX + select BLE_MESH_SRPL_SRV + help + Enable support for On-Demand Private Proxy Server model. + + config BLE_MESH_SRPL_CLI + bool "Solicitation PDU RPL Configuration Client model" + help + Enable support for Solicitation PDU RPL Configuration Client model. + + config BLE_MESH_SRPL_SRV + bool "Solicitation PDU RPL Configuration Server model" + depends on BLE_MESH_PROXY_SOLIC_PDU_RX + help + Enable support for Solicitation PDU RPL Configuration Server model. + Note: + This option depends on the functionality of receiving Solicitation + PDU. If the device doesn't support receiving Solicitation PDU, then + there is no need to enable this server model. + + config BLE_MESH_AGG_CLI + bool "Opcodes Aggregator Client model" + help + Enable support for Opcodes Aggregator Client model. + + config BLE_MESH_AGG_SRV + bool "Opcodes Aggregator Server model" + help + Enable support for Opcodes Aggregator Server model. + + config BLE_MESH_SAR_CLI + bool "SAR Configuration Client model" + help + Enable support for SAR Configuration Client model. + + config BLE_MESH_SAR_SRV + bool "SAR Configuration Server model" + help + Enable support for SAR Configuration Server model. + + config BLE_MESH_COMP_DATA_1 + bool "Support Composition Data Page 1" + help + Composition Data Page 1 contains information about the relationships + among models. + Each model either can be a root model or can extend other models. + + config BLE_MESH_COMP_DATA_128 + bool "Support Composition Data Page 128" + help + Composition Data Page 128 is used to indicate the structure of + elements, features, and models of a node after the successful + execution of the Node Address Refresh procedure or the Node + Composition Refresh procedure, or after the execution of the + Node Removal procedure followed by the provisioning process. + Composition Data Page 128 shall be present if the node supports + the Remote Provisioning Server model; otherwise it is optional. + + config BLE_MESH_MODELS_METADATA_0 + bool "Support Models Metadata Page 0" + help + The Models Metadata state contains metadata of a node’s models. + The Models Metadata state is composed of a number of pages of + information. + Models Metadata Page 0 shall be present if the node supports + the Large Composition Data Server model. + + config BLE_MESH_MODELS_METADATA_128 + bool "Support Models Metadata Page 128" + depends on BLE_MESH_MODELS_METADATA_0 + help + The Models Metadata state contains metadata of a node’s models. + The Models Metadata state is composed of a number of pages of + information. + Models Metadata Page 128 contains metadata for the node’s models + after the successful execution of the Node Address Refresh + procedure or the Node Composition Refresh procedure, or after + the execution of the Node Removal procedure followed by the + provisioning process. + Models Metadata Page 128 shall be present if the node supports + the Remote Provisioning Server model and the node supports the + Large Composition Data Server model. + + config BLE_MESH_LCD_CLI + bool "Large Composition Data Client model" + help + Enable support for Large Composition Data Client model. + + config BLE_MESH_LCD_SRV + bool "Large Composition Data Server model" + select BLE_MESH_MODELS_METADATA_0 + help + Enable support for Large Composition Data Server model. + + config BLE_MESH_RPR_CLI + bool "Remote Provisioning Client model" + depends on BLE_MESH_PROVISIONER + select BLE_MESH_PROV + help + Enable support for Remote Provisioning Client model + + if BLE_MESH_RPR_CLI + + config BLE_MESH_RPR_CLI_PROV_SAME_TIME + int "Maximum number of PB-Remote running at the same time by Provisioner" + range 1 5 + default 2 + help + This option specifies how many devices can be provisioned at the same time + using PB-REMOTE. For example, if the value is 2, it means a Provisioner can + provision two unprovisioned devices with PB-REMOTE at the same time. + + endif # BLE_MESH_RPR_CLI + + config BLE_MESH_RPR_SRV + bool "Remote Provisioning Server model" + depends on BLE_MESH_NODE + select BLE_MESH_PB_ADV + help + Enable support for Remote Provisioning Server model + + if BLE_MESH_RPR_SRV + + config BLE_MESH_RPR_SRV_MAX_SCANNED_ITEMS + int "Maximum number of device information can be scanned" + range 4 255 + default 10 + help + This option specifies how many device information can a Remote + Provisioning Server store each time while scanning. + + config BLE_MESH_RPR_SRV_ACTIVE_SCAN + bool "Support Active Scan for remote provisioning" + select BLE_MESH_ACTIVE_SCAN + help + Enable this option to support Active Scan for remote provisioning. + + config BLE_MESH_RPR_SRV_MAX_EXT_SCAN + int "Maximum number of extended scan procedures" + range 1 10 + default 1 + help + This option specifies how many extended scan procedures can be + started by the Remote Provisioning Server. + + endif # BLE_MESH_RPR_SRV + + config BLE_MESH_DF_CLI + bool "Directed Forwarding Configuration Client model" + help + Enable support for Directed Forwarding Configuration Client model. + + config BLE_MESH_DF_SRV + bool "Directed Forwarding Configuration Server model" + help + Enable support for Directed Forwarding Configuration Server model. + + if BLE_MESH_DF_SRV + + config BLE_MESH_MAX_DISC_TABLE_ENTRY_COUNT + int "Maximum number of discovery table entries in a given subnet" + range 2 255 + default 2 + help + Maximum number of Discovery Table entries supported by the node in a given subnet. + + config BLE_MESH_MAX_FORWARD_TABLE_ENTRY_COUNT + int "Maximum number of forward table entries in a given subnet" + range 2 64 + default 2 + help + Maximum number of Forward Table entries supported by the node in a given subnet. + + config BLE_MESH_MAX_DEPS_NODES_PER_PATH + int "Maximum number of dependent nodes per path" + range 2 64 + default 2 + help + Maximum size of dependent nodes list supported by each forward table entry. + + config BLE_MESH_PATH_MONITOR_TEST + bool "Enable Path Monitoring test mode" + default n + help + The option only removes the Path Use timer; all other behavior of the + device is not changed. + If Path Monitoring test mode is going to be used, this option should + be enabled. + + if BLE_MESH_GATT_PROXY_SERVER + config BLE_MESH_SUPPORT_DIRECTED_PROXY + bool "Enable Directed Proxy functionality" + default y + help + Support Directed Proxy functionality. + endif + + endif # BLE_MESH_DF_SRV + endmenu #Support for BLE Mesh Foundation models menu "Support for BLE Mesh Client/Server models" @@ -1107,6 +1422,30 @@ if BLE_MESH help Enable support for Lighting server models. + config BLE_MESH_MBT_CLI + bool "BLOB Transfer Client model" + default y + help + Enable support for BLOB Transfer Client model. + + if BLE_MESH_MBT_CLI + + config BLE_MESH_MAX_BLOB_RECEIVERS + int "Maximum number of simultaneous blob receivers" + default 2 + range 1 255 + help + Maximum number of BLOB Transfer Server models that can participating + in the BLOB transfer with a BLOB Transfer Client model. + + endif # BLE_MESH_MBT_CLI + + config BLE_MESH_MBT_SRV + bool "BLOB Transfer Server model" + default y + help + Enable support for BLOB Transfer Server model. + endmenu #Support for BLE Mesh Client/Server models config BLE_MESH_IV_UPDATE_TEST diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c index 13ce4f5342..e4f2e67b67 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c @@ -17,6 +17,7 @@ int32_t esp_ble_mesh_get_model_publish_period(esp_ble_mesh_model_t *model) if (model == NULL) { return 0; } + return btc_ble_mesh_model_pub_period_get(model); } @@ -31,6 +32,7 @@ uint16_t *esp_ble_mesh_is_model_subscribed_to_group(esp_ble_mesh_model_t *model, if (model == NULL) { return NULL; } + return btc_ble_mesh_model_find_group(model, group_addr); } @@ -39,6 +41,7 @@ esp_ble_mesh_elem_t *esp_ble_mesh_find_element(uint16_t element_addr) if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr)) { return NULL; } + return btc_ble_mesh_elem_find(element_addr); } @@ -53,6 +56,7 @@ esp_ble_mesh_model_t *esp_ble_mesh_find_vendor_model(const esp_ble_mesh_elem_t * if (element == NULL) { return NULL; } + return btc_ble_mesh_model_find_vnd(element, company_id, model_id); } @@ -62,6 +66,7 @@ esp_ble_mesh_model_t *esp_ble_mesh_find_sig_model(const esp_ble_mesh_elem_t *ele if (element == NULL) { return NULL; } + return btc_ble_mesh_model_find(element, model_id); } @@ -122,6 +127,15 @@ esp_err_t esp_ble_mesh_model_unsubscribe_group_addr(uint16_t element_addr, uint1 == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +#if CONFIG_BLE_MESH_DF_SRV +esp_err_t esp_ble_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay) +{ + return btc_ble_mesh_enable_directed_forwarding(net_idx, directed_forwarding, + directed_forwarding_relay); +} +#endif /* CONFIG_BLE_MESH_DF_SRV */ + #if CONFIG_BLE_MESH_NODE const uint8_t *esp_ble_mesh_node_get_local_net_key(uint16_t net_idx) diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c index 3bc1a60eae..16b0805dea 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -35,11 +35,6 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, return ESP_ERR_INVALID_ARG; } - if (device_role > ROLE_FAST_PROV) { - BT_ERR("Invalid device role 0x%02x", device_role); - return ESP_ERR_INVALID_ARG; - } - /* When data is NULL, it is mandatory to set length to 0 to prevent users from misinterpreting parameters. */ if (data == NULL) { length = 0; @@ -61,9 +56,18 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, } if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { - mic_len = ESP_BLE_MESH_MIC_SHORT; + /* When "send_rel" is true and "send_szmic" is 1, 8-octets TransMIC will + * be used, otherwise 4-octets TransMIC will be used. + */ + mic_len = (model->pub->send_rel && model->pub->send_szmic) ? + ESP_BLE_MESH_MIC_LONG : ESP_BLE_MESH_MIC_SHORT; } else { - mic_len = ctx->send_rel ? ESP_BLE_MESH_MIC_LONG : ESP_BLE_MESH_MIC_SHORT; + /* When the message is tagged with the send-segmented tag and "send_szmic" + * is 1, 8-octets TransMIC will be used, otherwise 4-octets TransMIC will + * be used. + */ + mic_len = ((ctx->send_tag & ESP_BLE_MESH_TAG_SEND_SEGMENTED) && ctx->send_szmic) ? + ESP_BLE_MESH_MIC_LONG : ESP_BLE_MESH_MIC_SHORT; } if (op_len + length + mic_len > MIN(ESP_BLE_MESH_SDU_MAX_LEN, ESP_BLE_MESH_TX_SDU_MAX)) { @@ -89,7 +93,6 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { arg.model_publish.model = model; - arg.model_publish.device_role = device_role; } else { arg.model_send.model = model; arg.model_send.ctx = ctx; @@ -97,7 +100,6 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, arg.model_send.opcode = opcode; arg.model_send.length = op_len + length; arg.model_send.data = msg_data; - arg.model_send.device_role = device_role; arg.model_send.msg_timeout = msg_timeout; } @@ -254,8 +256,7 @@ esp_err_t esp_ble_mesh_node_local_reset(void) return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -#if (CONFIG_BLE_MESH_PROVISIONER) - +#if CONFIG_BLE_MESH_PROVISIONER esp_err_t esp_ble_mesh_provisioner_set_node_name(uint16_t index, const char *name) { btc_ble_mesh_prov_args_t arg = {0}; @@ -312,6 +313,7 @@ esp_err_t esp_ble_mesh_provisioner_store_node_comp_data(uint16_t unicast_addr, arg.store_node_comp_data.unicast_addr = unicast_addr; arg.store_node_comp_data.length = length; arg.store_node_comp_data.data = data; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), btc_ble_mesh_prov_arg_deep_copy, btc_ble_mesh_prov_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -414,6 +416,7 @@ esp_err_t esp_ble_mesh_provisioner_add_local_app_key(const uint8_t app_key[16], } else { bzero(arg.add_local_app_key.app_key, 16); } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -437,6 +440,7 @@ esp_err_t esp_ble_mesh_provisioner_update_local_app_key(const uint8_t app_key[16 memcpy(arg.update_local_app_key.app_key, app_key, 16); arg.update_local_app_key.net_idx = net_idx; arg.update_local_app_key.app_idx = app_idx; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -466,6 +470,7 @@ esp_err_t esp_ble_mesh_provisioner_bind_app_key_to_local_model(uint16_t element_ arg.local_mod_app_bind.app_idx = app_idx; arg.local_mod_app_bind.model_id = model_id; arg.local_mod_app_bind.cid = company_id; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -491,6 +496,7 @@ esp_err_t esp_ble_mesh_provisioner_add_local_net_key(const uint8_t net_key[16], } else { bzero(arg.add_local_net_key.net_key, 16); } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -512,13 +518,14 @@ esp_err_t esp_ble_mesh_provisioner_update_local_net_key(const uint8_t net_key[16 memcpy(arg.update_local_net_key.net_key, net_key, 16); arg.update_local_net_key.net_idx = net_idx; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } const uint8_t *esp_ble_mesh_provisioner_get_local_net_key(uint16_t net_idx) { - return bt_mesh_provisioner_local_net_key_get(net_idx); + return bt_mesh_provisioner_net_key_get(net_idx); } #if CONFIG_BLE_MESH_PROVISIONER_RECV_HB @@ -760,9 +767,85 @@ uint8_t esp_ble_mesh_provisioner_get_free_settings_count(void) } #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ +#if CONFIG_BLE_MESH_CERT_BASED_PROV +esp_err_t esp_ble_mesh_provisioner_send_prov_records_get(uint16_t link_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + 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_PROVISIONER_SEND_PROV_RECORDS_GET; + + arg.send_prov_records_get.link_idx = link_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_send_prov_record_req(uint16_t link_idx, uint16_t record_id, + uint16_t frag_offset, uint16_t max_size) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (record_id >= ESP_BLE_MESH_PROV_RECORD_MAX_ID) { + return ESP_ERR_INVALID_ARG; + } + + 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_PROVISIONER_SEND_PROV_RECORD_REQUEST; + + arg.send_prov_record_req.link_idx = link_idx; + arg.send_prov_record_req.record_id = record_id; + arg.send_prov_record_req.frag_offset = frag_offset; + arg.send_prov_record_req.max_size = max_size; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_send_prov_invite(uint16_t link_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + 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_PROVISIONER_SEND_PROV_INVITE; + + arg.send_prov_invite.link_idx = link_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_provisioner_send_link_close(uint16_t link_idx) +{ + btc_ble_mesh_prov_args_t arg = {0}; + 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_PROVISIONER_SEND_LINK_CLOSE; + + arg.send_link_close.link_idx = link_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ #endif /* CONFIG_BLE_MESH_PROVISIONER */ -#if (CONFIG_BLE_MESH_FAST_PROV) +#if CONFIG_BLE_MESH_FAST_PROV const uint8_t *esp_ble_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx) { return bt_mesh_get_fast_prov_app_key(net_idx, app_idx); diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c index 017164a7c2..3f407b3a4f 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c @@ -31,13 +31,14 @@ static bool prov_bearers_valid(esp_ble_mesh_prov_bearer_t bearers) { if ((!(bearers & (ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT))) || (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - !(bearers & ESP_BLE_MESH_PROV_ADV)) || + !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + !(bearers & ESP_BLE_MESH_PROV_ADV)) || (!IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - !(bearers & ESP_BLE_MESH_PROV_GATT))) { + IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + !(bearers & ESP_BLE_MESH_PROV_GATT))) { return false; } + return true; } @@ -141,7 +142,7 @@ esp_err_t esp_ble_mesh_node_input_string(const char *string) msg.act = BTC_BLE_MESH_ACT_INPUT_STRING; memset(arg.input_string.string, 0, sizeof(arg.input_string.string)); strncpy(arg.input_string.string, string, - MIN(strlen(string), sizeof(arg.input_string.string))); + MIN(strlen(string), sizeof(arg.input_string.string))); return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); @@ -169,7 +170,7 @@ esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -#if (CONFIG_BLE_MESH_PROVISIONER) +#if CONFIG_BLE_MESH_PROVISIONER esp_err_t esp_ble_mesh_provisioner_read_oob_pub_key(uint8_t link_idx, uint8_t pub_key_x[32], uint8_t pub_key_y[32]) { @@ -212,7 +213,7 @@ esp_err_t esp_ble_mesh_provisioner_input_string(const char *string, uint8_t link memset(arg.provisioner_input_str.string, 0, sizeof(arg.provisioner_input_str.string)); strncpy(arg.provisioner_input_str.string, string, - MIN(strlen(string), sizeof(arg.provisioner_input_str.string))); + MIN(strlen(string), sizeof(arg.provisioner_input_str.string))); arg.provisioner_input_str.link_idx = link_idx; return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) @@ -305,6 +306,7 @@ esp_err_t esp_ble_mesh_provisioner_add_unprov_dev(esp_ble_mesh_unprov_dev_add_t memcpy(arg.provisioner_dev_add.add_dev.addr, add_dev->addr, sizeof(esp_ble_mesh_bd_addr_t)); memcpy(arg.provisioner_dev_add.add_dev.uuid, add_dev->uuid, 16); arg.provisioner_dev_add.flags = flags; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -339,6 +341,7 @@ esp_err_t esp_ble_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], arg.provisioner_prov_dev_with_addr.bearer = bearer; arg.provisioner_prov_dev_with_addr.oob_info = oob_info; arg.provisioner_prov_dev_with_addr.unicast_addr = unicast_addr; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -366,6 +369,7 @@ esp_err_t esp_ble_mesh_provisioner_delete_dev(esp_ble_mesh_device_delete_t *del_ } else if (del_dev->flag & DEL_DEV_UUID_FLAG) { memcpy(arg.provisioner_dev_del.del_dev.uuid, del_dev->uuid, 16); } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -392,6 +396,7 @@ esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, arg.set_dev_uuid_match.match_len = match_len; arg.set_dev_uuid_match.offset = offset; arg.set_dev_uuid_match.prov_after_match = prov_after_match; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -420,6 +425,7 @@ esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_inf } else if (prov_data_info->flag & PROV_DATA_IV_INDEX_FLAG) { arg.set_prov_data_info.prov_data.iv_index = prov_data_info->iv_index; } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -441,6 +447,7 @@ esp_err_t esp_ble_mesh_provisioner_set_static_oob_value(const uint8_t *value, ui arg.set_static_oob_val.length = length; memcpy(arg.set_static_oob_val.value, value, length); + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -461,23 +468,22 @@ esp_err_t esp_ble_mesh_provisioner_set_primary_elem_addr(uint16_t addr) msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_PRIMARY_ELEM_ADDR; arg.set_primary_elem_addr.addr = addr; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } - #endif /* CONFIG_BLE_MESH_PROVISIONER */ /* The following APIs are for fast provisioning */ -#if (CONFIG_BLE_MESH_FAST_PROV) - +#if CONFIG_BLE_MESH_FAST_PROV esp_err_t esp_ble_mesh_set_fast_prov_info(esp_ble_mesh_fast_prov_info_t *fast_prov_info) { btc_ble_mesh_prov_args_t arg = {0}; btc_msg_t msg = {0}; if (fast_prov_info == NULL || (fast_prov_info->offset + - fast_prov_info->match_len > ESP_BLE_MESH_OCTET16_LEN)) { + fast_prov_info->match_len > ESP_BLE_MESH_OCTET16_LEN)) { return ESP_ERR_INVALID_ARG; } @@ -497,6 +503,7 @@ esp_err_t esp_ble_mesh_set_fast_prov_info(esp_ble_mesh_fast_prov_info_t *fast_pr if (fast_prov_info->match_len) { memcpy(arg.set_fast_prov_info.match_val, fast_prov_info->match_val, fast_prov_info->match_len); } + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } @@ -517,8 +524,8 @@ esp_err_t esp_ble_mesh_set_fast_prov_action(esp_ble_mesh_fast_prov_action_t acti msg.act = BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION; arg.set_fast_prov_action.action = action; + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } - #endif /* CONFIG_BLE_MESH_FAST_PROV */ 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 cce62d63f6..582ea77557 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 @@ -11,6 +11,8 @@ #include "btc_ble_mesh_prov.h" #include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_local_data_operation_api.h" +#include "esp_ble_mesh_proxy_api.h" esp_err_t esp_ble_mesh_proxy_identity_enable(void) { @@ -166,3 +168,54 @@ esp_err_t esp_ble_mesh_proxy_client_remove_filter_addr(uint8_t conn_handle, uint return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), btc_ble_mesh_prov_arg_deep_copy, btc_ble_mesh_prov_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } + +#if CONFIG_BLE_MESH_DF_CLI +esp_err_t esp_ble_mesh_proxy_client_directed_proxy_set(uint8_t conn_handle, uint16_t net_idx, + uint8_t use_directed) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (use_directed > ESP_BLE_MESH_PROXY_CLI_DIRECTED_FORWARDING_ENABLE) { + return ESP_ERR_INVALID_ARG; + } + + 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_PROXY_CLIENT_DIRECTED_PROXY_SET; + + arg.proxy_client_directed_proxy_set.conn_handle = conn_handle; + arg.proxy_client_directed_proxy_set.net_idx = net_idx; + arg.proxy_client_directed_proxy_set.use_directed = use_directed; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), btc_ble_mesh_prov_arg_deep_copy, btc_ble_mesh_prov_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_DF_CLI */ + +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX +esp_err_t esp_ble_mesh_proxy_client_send_solic_pdu(uint8_t net_idx, uint16_t ssrc, uint16_t dst) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (esp_ble_mesh_find_element(ssrc) == NULL) { + return ESP_ERR_INVALID_ARG; + } + + 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_PROXY_CLIENT_SEND_SOLIC_PDU; + + arg.proxy_client_send_solic_pdu.net_idx = net_idx; + arg.proxy_client_send_solic_pdu.ssrc = ssrc; + arg.proxy_client_send_solic_pdu.dst = dst; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h index 80ab5707dc..6818ba18ae 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h @@ -76,7 +76,7 @@ typedef void (* esp_ble_mesh_ble_cb_t)(esp_ble_mesh_ble_cb_event_t event, /** * @brief Register BLE scanning callback. * - * @param[in] callback: Pointer to the BLE scaning callback function. + * @param[in] callback: Pointer to the BLE scanning callback function. * * @return ESP_OK on success or error code otherwise. * diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h index 8007868126..e5e7c721ed 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h @@ -200,6 +200,24 @@ esp_err_t esp_ble_mesh_node_add_local_app_key(const uint8_t app_key[16], uint16_ esp_err_t esp_ble_mesh_node_bind_app_key_to_local_model(uint16_t element_addr, uint16_t company_id, uint16_t model_id, uint16_t app_idx); +/** + * @brief This function used to enable directed forwarding and directed forwarding relay on self. + * + * @param[in] net_idx: NetKey Index. + * @param[in] directed_forwarding: Enable or Disable directed forwarding. + * @param[in] directed_forwarding_relay: Enable or Disable directed forwarding relay. + * + * @note If the directed forwarding was set to disable, the directed forwarding relay + * must also be set to disable. + * + * @return ESP_OK on success or error code otherwise. + * +*/ +#if CONFIG_BLE_MESH_DF_SRV +esp_err_t esp_ble_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay); +#endif + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h index 01af795138..2b512f1cd8 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h @@ -60,7 +60,7 @@ esp_err_t esp_ble_mesh_model_msg_opcode_init(uint8_t *data, uint32_t opcode); /** * @brief Initialize the user-defined client model. All user-defined client models * shall call this function to initialize the client model internal data. - * Node: Before calling this API, the op_pair_size and op_pair variabled within + * Node: Before calling this API, the op_pair_size and op_pair variables within * the user_data(defined using esp_ble_mesh_client_t_) of the client model * need to be initialized. * @@ -168,7 +168,7 @@ esp_err_t esp_ble_mesh_server_model_update_state(esp_ble_mesh_model_t *model, * @brief Reset the provisioning procedure of the local BLE Mesh node. * * @note All provisioning information in this node will be deleted and the node - * needs to be reprovisioned. The API function esp_ble_mesh_node_prov_enable() + * needs to be re-provisioned. The API function esp_ble_mesh_node_prov_enable() * needs to be called to start a new provisioning procedure. * * @return ESP_OK on success or error code otherwise. @@ -641,6 +641,55 @@ uint8_t esp_ble_mesh_provisioner_get_free_settings_count(void); */ const uint8_t *esp_ble_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx); +#if CONFIG_BLE_MESH_CERT_BASED_PROV +/** + * @brief This function is called by provisioner to send provisioning records + * get message. + * + * @param[in] link_idx: The provisioning link index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_send_prov_records_get(uint16_t link_idx); + +/** + * @brief This function is called by provisioner to send provisioning record + * request message. + * + * @param[in] link_idx: The provisioning link index. + * @param[in] record_id: The record identity. + * @param[in] frag_offset: The starting offset of the fragment. + * @param[in] max_size: The max record fragment size. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_send_prov_record_req(uint16_t link_idx, uint16_t record_id, + uint16_t frag_offset, uint16_t max_size); + +/** + * @brief This function is called by provisioner to send provisioning invite + * message. + * + * @param[in] link_idx: The provisioning link index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_send_prov_invite(uint16_t link_idx); + +/** + * @brief This function is called by provisioner to send link close + * + * @param[in] link_idx: The provisioning link index. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_send_link_close(uint16_t link_idx); +#endif /* #if CONFIG_BLE_MESH_CERT_BASED_PROV */ + #ifdef __cplusplus } #endif 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 c29e284481..b0f9c82104 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 @@ -13,6 +13,9 @@ extern "C" { #endif +#define ESP_BLE_MESH_PROXY_CLI_DIRECTED_FORWARDING_ENABLE 0x01 +#define ESP_BLE_MESH_PROXY_CLI_DIRECTED_FORWARDING_DISABLE 0x00 + /** * @brief Enable advertising with Node Identity. * @@ -111,6 +114,31 @@ esp_err_t esp_ble_mesh_proxy_client_add_filter_addr(uint8_t conn_handle, uint16_ esp_err_t esp_ble_mesh_proxy_client_remove_filter_addr(uint8_t conn_handle, uint16_t net_idx, uint16_t *addr, uint16_t addr_num); +/** + * @brief Proxy Client sets whether or not the Directed Proxy Server uses directed forwarding + * for Directed Proxy Client messages. + * + * @param[in] conn_handle: Proxy connection handle. + * @param[in] net_idx: Corresponding NetKey Index. + * @param[in] use_directed: Whether or not to send message by directed forwarding. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_proxy_client_directed_proxy_set(uint8_t conn_handle, uint16_t net_idx, + uint8_t use_directed); +/** + * @brief Proxy Client sends Solicitation PDU. + * + * @param[in] net_idx: Corresponding NetKey Index. + * @param[in] ssrc: Solicitation SRC, shall be one of its element address. + * @param[in] dst: Solicitation DST (TBD). + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_proxy_client_send_solic_pdu(uint8_t net_idx, uint16_t ssrc, uint16_t dst); + #ifdef __cplusplus } #endif 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 98677395a2..37f4bf05dc 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,25 +19,28 @@ extern "C" { #endif /*!< The maximum length of a BLE Mesh message, including Opcode, Payload and TransMIC */ -#define ESP_BLE_MESH_SDU_MAX_LEN 384 +#define ESP_BLE_MESH_SDU_MAX_LEN 384 /*!< Length of a short Mesh MIC. */ -#define ESP_BLE_MESH_MIC_SHORT 4 +#define ESP_BLE_MESH_MIC_SHORT 4 /*!< Length of a long Mesh MIC. */ -#define ESP_BLE_MESH_MIC_LONG 8 +#define ESP_BLE_MESH_MIC_LONG 8 /*!< The maximum length of a BLE Mesh provisioned node name */ -#define ESP_BLE_MESH_NODE_NAME_MAX_LEN 31 +#define ESP_BLE_MESH_NODE_NAME_MAX_LEN 31 /*!< The maximum length of a BLE Mesh unprovisioned device name */ -#define ESP_BLE_MESH_DEVICE_NAME_MAX_LEN DEVICE_NAME_SIZE +#define ESP_BLE_MESH_DEVICE_NAME_MAX_LEN DEVICE_NAME_SIZE /*!< The maximum length of settings user id */ -#define ESP_BLE_MESH_SETTINGS_UID_SIZE 20 +#define ESP_BLE_MESH_SETTINGS_UID_SIZE 20 + +/*!< The default value of Random Update Interval Steps */ +#define ESP_BLE_MESH_RAND_UPDATE_INTERVAL_DEFAULT 0x3C /*!< Invalid settings index */ -#define ESP_BLE_MESH_INVALID_SETTINGS_IDX 0xFF +#define ESP_BLE_MESH_INVALID_SETTINGS_IDX 0xFF /*!< Define the BLE Mesh octet 16 bytes size */ #define ESP_BLE_MESH_OCTET16_LEN 16 @@ -48,69 +51,86 @@ typedef uint8_t esp_ble_mesh_octet16_t[ESP_BLE_MESH_OCTET16_LEN]; typedef uint8_t esp_ble_mesh_octet8_t[ESP_BLE_MESH_OCTET8_LEN]; /*!< Invalid Company ID */ -#define ESP_BLE_MESH_CID_NVAL 0xFFFF +#define ESP_BLE_MESH_CID_NVAL 0xFFFF /*!< Special TTL value to request using configured default TTL */ -#define ESP_BLE_MESH_TTL_DEFAULT 0xFF +#define ESP_BLE_MESH_TTL_DEFAULT 0xFF /*!< Maximum allowed TTL value */ -#define ESP_BLE_MESH_TTL_MAX 0x7F +#define ESP_BLE_MESH_TTL_MAX 0x7F -#define ESP_BLE_MESH_ADDR_UNASSIGNED 0x0000 -#define ESP_BLE_MESH_ADDR_ALL_NODES 0xFFFF -#define ESP_BLE_MESH_ADDR_PROXIES 0xFFFC -#define ESP_BLE_MESH_ADDR_FRIENDS 0xFFFD -#define ESP_BLE_MESH_ADDR_RELAYS 0xFFFE +#define ESP_BLE_MESH_ADDR_UNASSIGNED 0x0000 +#define ESP_BLE_MESH_ADDR_ALL_NODES 0xFFFF +#define ESP_BLE_MESH_ADDR_PROXIES 0xFFFC +#define ESP_BLE_MESH_ADDR_FRIENDS 0xFFFD +#define ESP_BLE_MESH_ADDR_RELAYS 0xFFFE -#define ESP_BLE_MESH_KEY_UNUSED 0xFFFF -#define ESP_BLE_MESH_KEY_DEV 0xFFFE +#define ESP_BLE_MESH_KEY_UNUSED 0xFFFF +#define ESP_BLE_MESH_KEY_DEV 0xFFFE -#define ESP_BLE_MESH_KEY_PRIMARY 0x0000 -#define ESP_BLE_MESH_KEY_ANY 0xFFFF +#define ESP_BLE_MESH_KEY_PRIMARY 0x0000 +#define ESP_BLE_MESH_KEY_ANY 0xFFFF /*!< Primary Network Key index */ -#define ESP_BLE_MESH_NET_PRIMARY 0x000 +#define ESP_BLE_MESH_NET_PRIMARY 0x000 /*!< Relay state value */ -#define ESP_BLE_MESH_RELAY_DISABLED 0x00 -#define ESP_BLE_MESH_RELAY_ENABLED 0x01 -#define ESP_BLE_MESH_RELAY_NOT_SUPPORTED 0x02 +#define ESP_BLE_MESH_RELAY_DISABLED 0x00 +#define ESP_BLE_MESH_RELAY_ENABLED 0x01 +#define ESP_BLE_MESH_RELAY_NOT_SUPPORTED 0x02 /*!< Beacon state value */ -#define ESP_BLE_MESH_BEACON_DISABLED 0x00 -#define ESP_BLE_MESH_BEACON_ENABLED 0x01 +#define ESP_BLE_MESH_BEACON_DISABLED 0x00 +#define ESP_BLE_MESH_BEACON_ENABLED 0x01 + +#define ESP_BLE_MESH_PRIVATE_BEACON_DISABLE 0x00 +#define ESP_BLE_MESH_PRIVATE_BEACON_ENABLE 0x01 /*!< GATT Proxy state value */ -#define ESP_BLE_MESH_GATT_PROXY_DISABLED 0x00 -#define ESP_BLE_MESH_GATT_PROXY_ENABLED 0x01 -#define ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED 0x02 +#define ESP_BLE_MESH_GATT_PROXY_DISABLED 0x00 +#define ESP_BLE_MESH_GATT_PROXY_ENABLED 0x01 +#define ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED 0x02 + +#define ESP_BLE_MESH_PRIVATE_GATT_PROXY_DISABLED 0x00 +#define ESP_BLE_MESH_PRIVATE_GATT_PROXY_ENABLED 0x01 +#define ESP_BLE_MESH_PRIVATE_GATT_PROXY_NOT_SUPPORTED 0x02 + +#define ESP_BLE_MESH_PRIVATE_NODE_IDENTITY_DISABLED 0x00 +#define ESP_BLE_MESH_PRIVATE_NODE_IDENTITY_ENABLED 0x01 +#define ESP_BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED 0x02 /*!< Friend state value */ -#define ESP_BLE_MESH_FRIEND_DISABLED 0x00 -#define ESP_BLE_MESH_FRIEND_ENABLED 0x01 -#define ESP_BLE_MESH_FRIEND_NOT_SUPPORTED 0x02 +#define ESP_BLE_MESH_FRIEND_DISABLED 0x00 +#define ESP_BLE_MESH_FRIEND_ENABLED 0x01 +#define ESP_BLE_MESH_FRIEND_NOT_SUPPORTED 0x02 /*!< Node identity state value */ -#define ESP_BLE_MESH_NODE_IDENTITY_STOPPED 0x00 -#define ESP_BLE_MESH_NODE_IDENTITY_RUNNING 0x01 -#define ESP_BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02 +#define ESP_BLE_MESH_NODE_IDENTITY_STOPPED 0x00 +#define ESP_BLE_MESH_NODE_IDENTITY_RUNNING 0x01 +#define ESP_BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02 + +/*!< Subnet Bridge state value */ +#define ESP_BLE_MESH_SUBNET_BRIDGE_DISABLED 0x00 +#define ESP_BLE_MESH_SUBNET_BRIDGE_ENABLED 0x01 /*!< Supported features */ -#define ESP_BLE_MESH_FEATURE_RELAY BIT(0) -#define ESP_BLE_MESH_FEATURE_PROXY BIT(1) -#define ESP_BLE_MESH_FEATURE_FRIEND BIT(2) -#define ESP_BLE_MESH_FEATURE_LOW_POWER BIT(3) -#define ESP_BLE_MESH_FEATURE_ALL_SUPPORTED (ESP_BLE_MESH_FEATURE_RELAY | \ - ESP_BLE_MESH_FEATURE_PROXY | \ - ESP_BLE_MESH_FEATURE_FRIEND | \ - ESP_BLE_MESH_FEATURE_LOW_POWER) +#define ESP_BLE_MESH_FEATURE_RELAY BIT(0) +#define ESP_BLE_MESH_FEATURE_PROXY BIT(1) +#define ESP_BLE_MESH_FEATURE_FRIEND BIT(2) +#define ESP_BLE_MESH_FEATURE_LOW_POWER BIT(3) +#define ESP_BLE_MESH_FEATURE_ALL_SUPPORTED (ESP_BLE_MESH_FEATURE_RELAY | \ + ESP_BLE_MESH_FEATURE_PROXY | \ + ESP_BLE_MESH_FEATURE_FRIEND | \ + ESP_BLE_MESH_FEATURE_LOW_POWER) -#define ESP_BLE_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) -#define ESP_BLE_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xC000 && (addr) <= 0xFF00) -#define ESP_BLE_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xC000) -#define ESP_BLE_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xFF00 && (addr) <= 0xFFFB) +#define ESP_BLE_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) +#define ESP_BLE_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xC000 && (addr) <= 0xFF00) +#define ESP_BLE_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xC000) +#define ESP_BLE_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xFF00 && (addr) <= 0xFFFB) -#define ESP_BLE_MESH_INVALID_NODE_INDEX 0xFFFF +#define ESP_BLE_MESH_INVALID_NODE_INDEX 0xFFFF + +#define ESP_BLE_MESH_PROV_RECORD_MAX_ID 0x0013 /** @def ESP_BLE_MESH_TRANSMIT * @@ -238,7 +258,9 @@ typedef enum { ESP_BLE_MESH_PROV_OOB_NFC = BIT(4), ESP_BLE_MESH_PROV_OOB_NUMBER = BIT(5), ESP_BLE_MESH_PROV_OOB_STRING = BIT(6), - /* 7 - 10 are reserved */ + ESP_BLE_MESH_PROV_CERT_BASED = BIT(7), + ESP_BLE_MESH_PROV_RECORDS = BIT(8), + /* 9 - 10 are reserved */ ESP_BLE_MESH_PROV_OOB_ON_BOX = BIT(11), ESP_BLE_MESH_PROV_OOB_IN_BOX = BIT(12), ESP_BLE_MESH_PROV_OOB_ON_PAPER = BIT(13), @@ -317,34 +339,83 @@ typedef enum { .input_action = in_act, \ } -typedef uint8_t UINT8; -typedef uint16_t UINT16; -typedef uint32_t UINT32; -typedef uint64_t UINT64; - -#define BT_OCTET32_LEN 32 -typedef UINT8 BT_OCTET32[BT_OCTET32_LEN]; /* octet array: size 32 */ +typedef uint8_t UINT8 __attribute__((deprecated)); +typedef uint16_t UINT16 __attribute__((deprecated)); +typedef uint32_t UINT32 __attribute__((deprecated)); +typedef uint64_t UINT64 __attribute__((deprecated)); +#ifndef BT_OCTET32_LEN +#define BT_OCTET32_LEN 32 +typedef UINT8 BT_OCTET32[BT_OCTET32_LEN] __attribute__((deprecated)); +#endif #ifndef BD_ADDR_LEN #define BD_ADDR_LEN 6 -typedef uint8_t BD_ADDR[BD_ADDR_LEN]; +typedef uint8_t BD_ADDR[BD_ADDR_LEN] __attribute__((deprecated)); #endif typedef uint8_t esp_ble_mesh_bd_addr_t[BD_ADDR_LEN]; -#define ESP_BLE_MESH_ADDR_TYPE_PUBLIC 0x00 -#define ESP_BLE_MESH_ADDR_TYPE_RANDOM 0x01 -#define ESP_BLE_MESH_ADDR_TYPE_RPA_PUBLIC 0x02 -#define ESP_BLE_MESH_ADDR_TYPE_RPA_RANDOM 0x03 +#define ESP_BLE_MESH_ADDR_TYPE_PUBLIC 0x00 +#define ESP_BLE_MESH_ADDR_TYPE_RANDOM 0x01 +#define ESP_BLE_MESH_ADDR_TYPE_RPA_PUBLIC 0x02 +#define ESP_BLE_MESH_ADDR_TYPE_RPA_RANDOM 0x03 /// BLE device address type typedef uint8_t esp_ble_mesh_addr_type_t; +#define ESP_BLE_MESH_DIRECTED_FORWARDING_DISABLED 0x00 +#define ESP_BLE_MESH_DIRECTED_FORWARDING_ENABLED 0x01 + +#define ESP_BLE_MESH_DIRECTED_RELAY_DISABLED 0x00 +#define ESP_BLE_MESH_DIRECTED_RELAY_ENABLED 0x01 + +#define ESP_BLE_MESH_DIRECTED_PROXY_IGNORE 0xFF +#define ESP_BLE_MESH_DIRECTED_PROXY_USE_DEFAULT_IGNORE 0xFF +#define ESP_BLE_MESH_DIRECTED_FRIEND_IGNORE 0xFF + +#define ESP_BLE_MESH_DIRECTED_PROXY_DISABLED 0x00 +#define ESP_BLE_MESH_DIRECTED_PROXY_ENABLED 0x01 +#define ESP_BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED 0x02 + +#define ESP_BLE_MESH_DIRECTED_PROXY_USE_DEF_DISABLED 0x00 +#define ESP_BLE_MESH_DIRECTED_PROXY_USE_DEF_ENABLED 0x01 +#define ESP_BLE_MESH_DIRECTED_PROXY_USE_DEF_NOT_SUPPORTED 0x02 + +#define ESP_BLE_MESH_DIRECTED_FRIEND_DISABLED 0x00 +#define ESP_BLE_MESH_DIRECTED_FRIEND_ENABLED 0x01 +#define ESP_BLE_MESH_DIRECTED_FRIEND_NOT_SUPPORTED 0x02 + +#define ESP_BLE_MESH_DIRECTED_PUB_POLICY_FLOODING 0x00 +#define ESP_BLE_MESH_DIRECTED_PUB_POLICY_FORWARD 0x01 + +#define ESP_BLE_MESH_PROXY_USE_DIRECTED_DISABLED 0x00 +#define ESP_BLE_MESH_PROXY_USE_DIRECTED_ENABLED 0x01 + +#define ESP_BLE_MESH_FLOODING_CRED 0x00 /* Managed flooding security credentials */ +#define ESP_BLE_MESH_FRIENDSHIP_CRED 0x01 /* Friendship security credentials */ +#define ESP_BLE_MESH_DIRECTED_CRED 0x02 /* Directed security credentials */ + +#define ESP_BLE_MESH_TAG_SEND_SEGMENTED BIT(0) /* Tagged with send-segmented */ +#define ESP_BLE_MESH_TAG_IMMUTABLE_CRED BIT(1) /* Tagged with immutable-credentials */ +#define ESP_BLE_MESH_TAG_USE_DIRECTED BIT(2) /* Tagged with use-directed */ +#define ESP_BLE_MESH_TAG_RELAY BIT(3) /* Tagged as relay */ +#define ESP_BLE_MESH_TAG_FRIENDSHIP BIT(4) /* Tagged as a friendship PDU */ + +#define ESP_BLE_MESH_SEG_SZMIC_SHORT 0 /* Using 4-octets TransMIC for a segmented message */ +#define ESP_BLE_MESH_SEG_SZMIC_LONG 1 /* Using 8-octets TransMIC for a segmented message */ + /** BLE Mesh deinit parameters */ typedef struct { bool erase_flash; /*!< Indicate if erasing flash when deinit mesh stack */ } esp_ble_mesh_deinit_param_t; +/** Format of Unicast Address Range */ +typedef struct { + uint16_t len_present:1, /*!< Indicate the presence or absence of the RangeLength field */ + range_start:15; /*!< 15 least significant bits of the starting unicast address */ + uint8_t range_length; /*!< Number of addresses in the range (0x02 - 0xFF) */ +} esp_ble_mesh_uar_t; + typedef struct esp_ble_mesh_model esp_ble_mesh_model_t; /** Abstraction that describes a BLE Mesh Element. @@ -374,7 +445,8 @@ typedef struct { uint16_t publish_addr; /*!< Publish Address. */ uint16_t app_idx:12, /*!< Publish AppKey Index. */ cred:1, /*!< Friendship Credentials Flag. */ - send_rel:1; /*!< Force reliable sending (segment acks) */ + send_rel:1, /*!< Force reliable sending (segment acks) */ + send_szmic:1; /*!< Size of TransMIC when publishing a Segmented Access message */ uint8_t ttl; /*!< Publish Time to Live. */ uint8_t retransmit; /*!< Retransmit Count & Interval Steps. */ @@ -384,7 +456,11 @@ typedef struct { fast_period:1, /*!< Use FastPeriodDivisor */ count:3; /*!< Retransmissions left. */ - uint32_t period_start; /*!< Start of the current period. */ + uint32_t period_start; /*!< Start of the current period. */ + +#if CONFIG_BLE_MESH_DF_SRV + uint8_t directed_pub_policy; /*!< Directed publish policy */ +#endif /** @brief Publication buffer, containing the publication message. * @@ -402,7 +478,7 @@ typedef struct { struct k_delayed_work timer; /** Role of the device that is going to publish messages */ - uint8_t dev_role; + uint8_t dev_role __attribute__((deprecated)); } esp_ble_mesh_model_pub_t; /** @def ESP_BLE_MESH_MODEL_PUB_DEFINE @@ -418,7 +494,6 @@ typedef struct { static esp_ble_mesh_model_pub_t _name = { \ .update = (uint32_t)NULL, \ .msg = &bt_mesh_pub_msg_##_name, \ - .dev_role = _role, \ } /** @def ESP_BLE_MESH_MODEL_OP @@ -472,7 +547,7 @@ struct esp_ble_mesh_model { const uint16_t model_id; /*!< 16-bit model identifier */ struct { uint16_t company_id; /*!< 16-bit company identifier */ - uint16_t model_id; /*!< 16-bit model identifier */ + uint16_t model_id; /*!< 16-bit model identifier */ } vnd; /*!< Structure encapsulating a model ID with a company ID */ }; @@ -524,26 +599,41 @@ typedef struct { /** Destination address of a received message. Not used for sending. */ uint16_t recv_dst; - /** RSSI of received packet. Not used for sending. */ + /** RSSI of a received message. Not used for sending. */ int8_t recv_rssi; - /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl: 7; + /** Opcode of a received message. Not used for sending. */ + uint32_t recv_op; - /** Force sending reliably by using segment acknowledgement */ - uint8_t send_rel: 1; + /** Received TTL value. Not used for sending. */ + uint8_t recv_ttl; + + /** Security credentials of a received message. Not used for sending. */ + uint8_t recv_cred; + + /** Tag of a received message. Not used for sending. */ + uint8_t recv_tag; + + /** Force sending reliably by using segment acknowledgement. */ + uint8_t send_rel:1 __attribute__((deprecated)); + + /** Size of TransMIC when sending a Segmented Access message. */ + uint8_t send_szmic:1; /** TTL, or ESP_BLE_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; - /** Opcode of a received message. Not used for sending message. */ - uint32_t recv_op; + /** Security credentials used for sending the message */ + uint8_t send_cred; + + /** Tag used for sending the message. */ + uint8_t send_tag; /** Model corresponding to the message, no need to be initialized before sending message */ - esp_ble_mesh_model_t *model; + esp_ble_mesh_model_t *model __attribute__((deprecated)); /** Indicate if the message is sent by a node server model, no need to be initialized before sending message */ - bool srv_send; + bool srv_send __attribute__((deprecated)); } esp_ble_mesh_msg_ctx_t; /** Provisioning properties & capabilities. @@ -576,6 +666,9 @@ typedef struct { /** Callback used to notify to set OOB Public Key. Initialized by the stack. */ esp_ble_mesh_cb_t oob_pub_key_cb; + /** OOB type */ + uint8_t oob_type; + /** Static OOB value */ const uint8_t *static_val; /** Static OOB value length */ @@ -668,6 +761,12 @@ typedef struct { esp_ble_mesh_cb_t provisioner_link_close; /** Callback used to indicate that a device is provisioned. Initialized by the stack. */ esp_ble_mesh_cb_t provisioner_prov_comp; + /** Callback used to indicate that certificate based provisioning needs to start. Initialized by the stack. */ + esp_ble_mesh_cb_t cert_based_prov_start; + /** Callback used to indicate that provisioner has received provisioning records list successfully. Initialized by the stack. */ + esp_ble_mesh_cb_t records_list_get; + /** Callback used to indicate that provisioner has received a complete provisioning record successfully. Initialized by the stack. */ + esp_ble_mesh_cb_t prov_record_recv_comp; #endif /* CONFIG_BLE_MESH_PROVISIONER */ } esp_ble_mesh_prov_t; @@ -698,8 +797,8 @@ typedef uint8_t esp_ble_mesh_dev_add_flag_t; /** Information of the device which is going to be added for provisioning. */ typedef struct { - esp_ble_mesh_bd_addr_t addr; /*!< Device address */ - esp_ble_mesh_addr_type_t addr_type; /*!< Device address type */ + esp_ble_mesh_bd_addr_t addr; /*!< Device address */ + esp_ble_mesh_addr_type_t addr_type; /*!< Device address type */ uint8_t uuid[16]; /*!< Device UUID */ uint16_t oob_info; /*!< Device OOB Info */ /*!< ADD_DEV_START_PROV_NOW_FLAG shall not be set if the bearer has both PB-ADV and PB-GATT enabled */ @@ -710,14 +809,16 @@ typedef struct { #define DEL_DEV_UUID_FLAG BIT(1) /** Information of the device which is going to be deleted. */ typedef struct { + /** Union of Device information */ union { + /** Device address */ struct { - esp_ble_mesh_bd_addr_t addr; /*!< Device address */ - esp_ble_mesh_addr_type_t addr_type; /*!< Device address type */ + esp_ble_mesh_bd_addr_t addr; /*!< Device address */ + esp_ble_mesh_addr_type_t addr_type; /*!< Device address type */ }; - uint8_t uuid[16]; /*!< Device UUID */ + uint8_t uuid[16]; /*!< Device UUID */ }; - uint8_t flag; /*!< BIT0: device address; BIT1: device UUID */ + uint8_t flag; /*!< BIT0: device address; BIT1: device UUID */ } esp_ble_mesh_device_delete_t; #define PROV_DATA_NET_IDX_FLAG BIT(0) @@ -725,6 +826,7 @@ typedef struct { #define PROV_DATA_IV_INDEX_FLAG BIT(2) /** Information of the provisioner which is going to be updated. */ typedef struct { + /** Provisioning data */ union { uint16_t net_idx; /*!< NetKey Index */ uint8_t flags; /*!< Flags */ @@ -828,6 +930,13 @@ typedef enum { ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, /*!< Provisioner establish a BLE Mesh link event */ ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT, /*!< Provisioner close a BLE Mesh link event */ ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT, /*!< Provisioner provisioning done event */ + ESP_BLE_MESH_PROVISIONER_CERT_BASED_PROV_START_EVT, /*!< Provisioner initiate a certificate based provisioning */ + ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT, /*!< Provisioner receive provisioning records list event */ + ESP_BLE_MESH_PROVISIONER_PROV_RECORD_RECV_COMP_EVT, /*!< Provisioner receive provisioning record complete event */ + ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORDS_GET_EVT, /*!< Provisioner send provisioning records get to device event */ + ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORD_REQUEST_EVT, /*!< Provisioner send provisioning record request to device event */ + ESP_BLE_MESH_PROVISIONER_SEND_PROV_INVITE_EVT, /*!< Provisioner send provisioning invite to device event */ + ESP_BLE_MESH_PROVISIONER_SEND_LINK_CLOSE_EVT, /*!< Provisioner send link close to device event */ ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, /*!< Provisioner add a device to the list which contains devices that are waiting/going to be provisioned completion event */ ESP_BLE_MESH_PROVISIONER_PROV_DEV_WITH_ADDR_COMP_EVT, /*!< Provisioner start to provision an unprovisioned device completion event */ ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT, /*!< Provisioner delete a device from the list, close provisioning link with the device completion event */ @@ -877,8 +986,10 @@ typedef enum { ESP_BLE_MESH_PROXY_CLIENT_SET_FILTER_TYPE_COMP_EVT, /*!< Proxy Client set filter type completion event */ ESP_BLE_MESH_PROXY_CLIENT_ADD_FILTER_ADDR_COMP_EVT, /*!< Proxy Client add filter address completion event */ ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT, /*!< Proxy Client remove filter address completion event */ + ESP_BLE_MESH_PROXY_CLIENT_DIRECTED_PROXY_SET_COMP_EVT, /*!< Proxy Client directed proxy set completion event */ ESP_BLE_MESH_PROXY_SERVER_CONNECTED_EVT, /*!< Proxy Server establishes connection successfully event */ ESP_BLE_MESH_PROXY_SERVER_DISCONNECTED_EVT, /*!< Proxy Server terminates connection successfully event */ + ESP_BLE_MESH_PROXY_CLIENT_SEND_SOLIC_PDU_COMP_EVT, /*!< Proxy Client send Solicitation PDU completion event */ ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT, /*!< Local model subscribes group address completion event */ ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT, /*!< Local model unsubscribes group address completion event */ ESP_BLE_MESH_DEINIT_MESH_COMP_EVT, /*!< De-initialize BLE Mesh stack completion event */ @@ -924,6 +1035,7 @@ typedef union { */ struct ble_mesh_link_close_evt_param { esp_ble_mesh_prov_bearer_t bearer; /*!< Type of the bearer used when device link is closed */ + uint8_t reason; /*!< Reason of the closed provisioning link */ } node_prov_link_close; /*!< Event parameter of ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT */ /** * @brief ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT @@ -1030,7 +1142,7 @@ typedef union { esp_ble_mesh_bd_addr_t addr; /*!< Device address of the unprovisioned device */ esp_ble_mesh_addr_type_t addr_type; /*!< Device address type */ uint16_t oob_info; /*!< OOB Info of the unprovisioned device */ - uint8_t adv_type; /*!< Avertising type of the unprovisioned device */ + uint8_t adv_type; /*!< Advertising type of the unprovisioned device */ esp_ble_mesh_prov_bearer_t bearer; /*!< Bearer of the unprovisioned device */ int8_t rssi; /*!< RSSI of the received advertising packet */ } provisioner_recv_unprov_adv_pkt; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT */ @@ -1075,6 +1187,7 @@ typedef union { esp_ble_mesh_input_action_t action; /*!< Action of device Input OOB Authentication */ uint8_t size; /*!< Size of device Input OOB Authentication */ uint8_t link_idx; /*!< Index of the provisioning link */ + /** Union of output OOB */ union { char string[8]; /*!< String output by the Provisioner */ uint32_t number; /*!< Number output by the Provisioner */ @@ -1097,6 +1210,62 @@ typedef union { uint8_t element_num; /*!< Element count of the provisioned device */ uint16_t netkey_idx; /*!< NetKey Index of the provisioned device */ } provisioner_prov_complete; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_CERT_BASED_PROV_START_EVT + */ + struct ble_mesh_provisioner_cert_based_prov_start_evt_param { + uint16_t link_idx; /*!< Index of the provisioning link */ + } provisioner_cert_based_prov_start; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_CERT_BASED_PROV_START_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT + */ + struct ble_mesh_provisioner_recv_prov_records_list_evt_param { + uint16_t link_idx; /*!< Index of the provisioning link */ + uint16_t len; /*!< Length of message */ + uint8_t *msg; /*!< Lists the Record IDs of the provisioning records stored on the Provisionee */ + } recv_provisioner_records_list; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_PROV_RECORD_RECV_COMP_EVT + */ + struct ble_mesh_provisioner_prov_record_recv_comp_evt_param { + uint8_t status; /*!< Indicates whether or not the request was handled successfully */ + uint16_t link_idx; /*!< Index of the provisioning link */ + uint16_t record_id; /*!< Identifies the provisioning record for which the request is made */ + uint16_t frag_offset; /*!< The starting offset of the requested fragment in the provisioning record data */ + uint16_t total_len; /*!< Total length of the provisioning record data stored on the Provisionee */ + uint8_t *record; /*!< Provisioning record data fragment */ + } provisioner_prov_record_recv_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_PROV_RECORD_RECV_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORDS_GET_EVT + */ + struct ble_mesh_provisioner_send_prov_records_get_evt_param { + int err_code; /*!< Indicate the result of send Provisioning Records List Get message */ + uint16_t link_idx; /*!< Index of the provisioning link */ + } provisioner_send_records_get; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORDS_GET_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORD_REQUEST_EVT + */ + struct ble_mesh_provisioner_send_prov_record_req_evt_param { + int err_code; /*!< Indicate the result of send Provisioning Record Request message */ + uint16_t link_idx; /*!< Index of the provisioning link */ + uint16_t record_id; /*!< Identifies the provisioning record for which the request is made */ + uint16_t frag_offset; /*!< The starting offset of the requested fragment in the provisioning record data */ + uint16_t max_size; /*!< The maximum size of the provisioning record fragment that the Provisioner can receive */ + } provisioner_send_record_req; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORD_REQUEST_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SEND_PROV_INVITE_EVT + */ + struct ble_mesh_provisioner_send_prov_invite_evt_param { + uint16_t link_idx; /*!< Index of the provisioning link */ + int err_code; /*!< Indicate the result of send Provisioning Invite message */ + } provisioner_send_prov_invite; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SEND_PROV_INVITE_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SEND_LINK_CLOSE_EVT + */ + struct ble_mesh_provisioner_send_link_close_evt_param { + uint16_t link_idx; /*!< Index of the provisioning link */ + int err_code; /*!< Indicate the result of send Link Close message */ + } provisioner_send_link_close; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_SEND_LINK_CLOSE_EVT */ /** * @brief ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT */ @@ -1461,6 +1630,14 @@ typedef union { uint8_t conn_handle; /*!< Proxy connection handle */ uint16_t net_idx; /*!< Corresponding NetKey Index */ } proxy_client_remove_filter_addr_comp; /*!< Event parameter of ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROXY_CLIENT_DIRECTED_PROXY_CONTROL_COMP_EVT + */ + struct ble_mesh_proxy_client_directed_proxy_set_param { + int err_code; /*!< Indicate the result of Proxy Client directed proxy control address */ + uint8_t conn_handle; /*!< Proxy connection handle */ + uint16_t net_idx; /*!< Corresponding NetKey Index */ + } proxy_client_directed_proxy_set_comp; /*!< Event parameter of ESP_BLE_MESH_PROXY_CLIENT_DIRECTED_PROXY_SET_COMP_EVT */ /** * @brief ESP_BLE_MESH_PROXY_SERVER_CONNECTED_EVT */ @@ -1474,6 +1651,15 @@ typedef union { uint8_t conn_handle; /*!< Proxy connection handle */ uint8_t reason; /*!< Proxy disconnect reason */ } proxy_server_disconnected; /*!< Event parameter of ESP_BLE_MESH_PROXY_SERVER_DISCONNECTED_EVT */ + /** + * @brief ESP_BLE_MESH_PROXY_CLIENT_SEND_SOLIC_PDU_COMP_EVT + */ + struct { + int err_code; /*!< Indicate the result of Proxy Client send Solicitation PDU */ + uint16_t net_idx; /*!< Corresponding NetKey Index */ + uint16_t ssrc; /*!< Solicitation SRC */ + uint16_t dst; /*!< Solicitation DST */ + } proxy_client_send_solic_pdu_comp; /*!< Event parameter of ESP_BLE_MESH_PROXY_CLIENT_SEND_SOLIC_PDU_COMP_EVT */ /** * @brief ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT */ @@ -1500,7 +1686,7 @@ typedef union { struct ble_mesh_deinit_mesh_comp_param { int err_code; /*!< Indicate the result of BLE Mesh deinitialization */ } deinit_mesh_comp; /*!< Event parameter of ESP_BLE_MESH_DEINIT_MESH_COMP_EVT */ -} esp_ble_mesh_prov_cb_param_t; +} esp_ble_mesh_prov_cb_param_t; /*!< Event parameters of ESP_BLE_MESH_DEINIT_MESH_COMP_EVT */ /** * @brief BLE Mesh models related Model ID and Opcode definitions @@ -1511,6 +1697,24 @@ typedef union { #define ESP_BLE_MESH_MODEL_ID_CONFIG_CLI 0x0001 #define ESP_BLE_MESH_MODEL_ID_HEALTH_SRV 0x0002 #define ESP_BLE_MESH_MODEL_ID_HEALTH_CLI 0x0003 +#define ESP_BLE_MESH_MODEL_ID_RPR_SRV 0x0004 +#define ESP_BLE_MESH_MODEL_ID_RPR_CLI 0x0005 +#define ESP_BLE_MESH_MODEL_ID_DF_SRV 0x0006 +#define ESP_BLE_MESH_MODEL_ID_DF_CLI 0x0007 +#define ESP_BLE_MESH_MODEL_ID_BRC_SRV 0x0008 +#define ESP_BLE_MESH_MODEL_ID_BRC_CLI 0x0009 +#define ESP_BLE_MESH_MODEL_ID_PRB_SRV 0x000A +#define ESP_BLE_MESH_MODEL_ID_PRB_CLI 0x000B +#define ESP_BLE_MESH_MODEL_ID_ODP_SRV 0x000C +#define ESP_BLE_MESH_MODEL_ID_ODP_CLI 0x000D +#define ESP_BLE_MESH_MODEL_ID_SAR_SRV 0x000E +#define ESP_BLE_MESH_MODEL_ID_SAR_CLI 0x000F +#define ESP_BLE_MESH_MODEL_ID_AGG_SRV 0x0010 +#define ESP_BLE_MESH_MODEL_ID_AGG_CLI 0x0011 +#define ESP_BLE_MESH_MODEL_ID_LCD_SRV 0x0012 +#define ESP_BLE_MESH_MODEL_ID_LCD_CLI 0x0013 +#define ESP_BLE_MESH_MODEL_ID_SRPL_SRV 0x0014 +#define ESP_BLE_MESH_MODEL_ID_SRPL_CLI 0x0015 /*!< Models from the Mesh Model Specification */ #define ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000 @@ -1565,6 +1769,8 @@ typedef union { #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 +#define ESP_BLE_MESH_MODEL_ID_MBT_SRV 0x1400 +#define ESP_BLE_MESH_MODEL_ID_MBT_CLI 0x1401 /** * esp_ble_mesh_opcode_config_client_get_t belongs to esp_ble_mesh_opcode_t, this typedef is only @@ -1686,6 +1892,10 @@ typedef uint8_t esp_ble_mesh_cfg_status_t; #define ESP_BLE_MESH_CFG_STATUS_CANNOT_SET 0x0F #define ESP_BLE_MESH_CFG_STATUS_UNSPECIFIED_ERROR 0x10 #define ESP_BLE_MESH_CFG_STATUS_INVALID_BINDING 0x11 +#define ESP_BLE_MESH_CFG_STATUS_INVALID_PATH_ENTRY 0x12 +#define ESP_BLE_MESH_CFG_STATUS_CANNOT_GET 0x13 +#define ESP_BLE_MESH_CFG_STATUS_OBSOLETE_INFO 0x14 +#define ESP_BLE_MESH_CFG_STATUS_INVALID_BEARER 0x15 /** * esp_ble_mesh_opcode_health_client_get_t belongs to esp_ble_mesh_opcode_t, this typedef is @@ -2037,11 +2247,12 @@ typedef struct { /** Client Model user data context. */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the client model. Initialized by the stack. */ - int op_pair_size; /*!< Size of the op_pair */ + uint32_t op_pair_size; /*!< Size of the op_pair */ const esp_ble_mesh_client_op_pair_t *op_pair; /*!< Table containing get/set message opcode and corresponding status message opcode */ uint32_t publish_status; /*!< Callback used to handle the received unsolicited message. Initialized by the stack. */ void *internal_data; /*!< Pointer to the internal data of client model */ - uint8_t msg_role; /*!< Role of the device (Node/Provisioner) that is going to send messages */ + void *vendor_data; /*!< Pointer to the vendor data of client model */ + uint8_t msg_role __attribute__((deprecated)); /*!< Role of the device (Node/Provisioner) that is going to send messages */ } esp_ble_mesh_client_t; /** Common parameters of the messages sent by Client Model. */ @@ -2051,7 +2262,7 @@ typedef struct { esp_ble_mesh_msg_ctx_t ctx; /*!< The context used to send message */ int32_t msg_timeout; /*!< Timeout value (ms) to get response to the sent message */ /*!< Note: if using default timeout value in menuconfig, make sure to set this value to 0 */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + uint8_t msg_role __attribute__((deprecated)); /*!< Role of the device - Node/Provisioner */ } esp_ble_mesh_client_common_param_t; /** diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h index 31369d8956..b444465e3e 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h @@ -42,7 +42,7 @@ extern "C" { NULL, NULL, cli_data) /** Configuration Server Model context */ -typedef struct esp_ble_mesh_cfg_srv { +typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to Configuration Server Model */ uint8_t net_transmit; /*!< Network Transmit state */ @@ -316,7 +316,7 @@ typedef struct { } esp_ble_mesh_cfg_net_transmit_set_t; /** Parameters of Config Model Heartbeat Publication Set. */ -typedef struct { +typedef struct { uint16_t dst; /*!< Destination address for Heartbeat messages */ uint8_t count; /*!< Number of Heartbeat messages to be sent */ uint8_t period; /*!< Period for sending Heartbeat messages */ @@ -610,6 +610,7 @@ typedef enum { * @brief Configuration Server model related context. */ +/** Parameters of Config Model Publication Set */ typedef struct { uint16_t element_addr; /*!< Element Address */ uint16_t pub_addr; /*!< Publish Address */ @@ -622,6 +623,19 @@ typedef struct { uint16_t model_id; /*!< Model ID */ } esp_ble_mesh_state_change_cfg_mod_pub_set_t; +/** Parameters of Config Model Publication Virtual Address Set */ +typedef struct { + uint16_t element_addr; /*!< Element Address */ + uint8_t label_uuid[16]; /*!< Label UUID */ + uint16_t app_idx; /*!< AppKey Index */ + bool cred_flag; /*!< Friendship Credential Flag */ + uint8_t pub_ttl; /*!< Publish TTL */ + uint8_t pub_period; /*!< Publish Period */ + uint8_t pub_retransmit; /*!< Publish Retransmit */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_state_change_cfg_mod_pub_va_set_t; + /** Parameters of Config Model Subscription Add */ typedef struct { uint16_t element_addr; /*!< Element Address */ @@ -705,6 +719,7 @@ typedef union { * The recv_op in ctx can be used to decide which state is changed. */ esp_ble_mesh_state_change_cfg_mod_pub_set_t mod_pub_set; /*!< Config Model Publication Set */ + esp_ble_mesh_state_change_cfg_mod_pub_va_set_t mod_pub_va_set; /*!< Config Model Publication Virtual Address Set */ esp_ble_mesh_state_change_cfg_model_sub_add_t mod_sub_add; /*!< Config Model Subscription Add */ esp_ble_mesh_state_change_cfg_model_sub_delete_t mod_sub_delete; /*!< Config Model Subscription Delete */ esp_ble_mesh_state_change_cfg_netkey_add_t netkey_add; /*!< Config NetKey Add */ diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h index 48f45f5e4f..c610c77a96 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h @@ -134,7 +134,7 @@ typedef struct { typedef struct { bool op_en; /*!< Indicate if optional parameters are included */ uint16_t ctl_lightness; /*!< Target value of light ctl lightness state */ - uint16_t ctl_temperatrue; /*!< Target value of light ctl temperature state */ + uint16_t ctl_temperature; /*!< Target value of light ctl temperature state */ int16_t ctl_delta_uv; /*!< Target value of light ctl delta UV state */ uint8_t tid; /*!< Transaction ID */ uint8_t trans_time; /*!< Time to complete state transition (optional) */ @@ -144,7 +144,7 @@ typedef struct { /** Parameters of Light CTL Temperature Set */ typedef struct { bool op_en; /*!< Indicate if optional parameters are included */ - uint16_t ctl_temperatrue; /*!< Target value of light ctl temperature state */ + uint16_t ctl_temperature; /*!< Target value of light ctl temperature state */ int16_t ctl_delta_uv; /*!< Target value of light ctl delta UV state */ uint8_t tid; /*!< Transaction ID */ uint8_t trans_time; /*!< Time to complete state transition (optional) */ diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h index 4f051a0b26..ba72c2238d 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h @@ -141,7 +141,7 @@ typedef struct { } esp_ble_mesh_sensor_settings_status_cb_t; /** Parameters of Sensor Setting Status */ -typedef struct { +typedef struct { bool op_en; /*!< Indicate id optional parameters are included */ uint16_t sensor_property_id; /*!< Property ID identifying a sensor */ uint16_t sensor_setting_property_id; /*!< Setting ID identifying a setting within a sensor */ diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h index 07e5a5ba01..34700f8b72 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h @@ -468,7 +468,7 @@ esp_err_t esp_ble_mesh_time_scene_client_set_state(esp_ble_mesh_client_common_pa #define ESP_BLE_MESH_TIME_NONE 0x00 /*!< Time Role - None */ #define ESP_BLE_MESH_TIME_AUTHORITY 0x01 /*!< Time Role - Mesh Time Authority */ #define ESP_BLE_MESH_TIME_RELAY 0x02 /*!< Time Role - Mesh Time Relay */ -#define ESP_BLE_MESH_TIME_CLINET 0x03 /*!< Time Role - Mesh Time Client */ +#define ESP_BLE_MESH_TIME_CLIENT 0x03 /*!< Time Role - Mesh Time Client */ #define ESP_BLE_MESH_SCENE_SUCCESS 0x00 /*!< Scene operation - Success */ #define ESP_BLE_MESH_SCENE_REG_FULL 0x01 /*!< Scene operation - Scene Register Full */ @@ -482,7 +482,7 @@ typedef struct { uint8_t uncertainty; /*!< The value of the Uncertainty field */ uint8_t time_zone_offset_curr; /*!< The value of the Time Zone Offset Current field */ uint8_t time_zone_offset_new; /*!< The value of the Time Zone Offset New state */ - uint8_t tai_zone_change[5]; /*!< The value of the TAI of Zone Chaneg field */ + uint8_t tai_zone_change[5]; /*!< The value of the TAI of Zone Change field */ uint16_t time_authority : 1, /*!< The value of the Time Authority bit */ tai_utc_delta_curr : 15; /*!< The value of the TAI-UTC Delta Current state */ uint16_t tai_utc_delta_new : 15; /*!< The value of the TAI-UTC Delta New state */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c index 2f6115f6e4..c1802e1137 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c @@ -7,8 +7,8 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_config_model.h" -#include "foundation.h" #include "esp_ble_mesh_config_model_api.h" #if CONFIG_BLE_MESH_CFG_CLI @@ -50,7 +50,7 @@ void btc_ble_mesh_config_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void dst->cfg_client_get_state.get_state = (esp_ble_mesh_cfg_client_get_state_t *)bt_mesh_malloc(sizeof(esp_ble_mesh_cfg_client_get_state_t)); if (dst->cfg_client_get_state.get_state) { memcpy(dst->cfg_client_get_state.get_state, src->cfg_client_get_state.get_state, - sizeof(esp_ble_mesh_cfg_client_get_state_t)); + sizeof(esp_ble_mesh_cfg_client_get_state_t)); } else { BT_ERR("%s, Out of memory, act %d", __func__, msg->act); } @@ -70,7 +70,7 @@ void btc_ble_mesh_config_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void dst->cfg_client_set_state.set_state = (esp_ble_mesh_cfg_client_set_state_t *)bt_mesh_malloc(sizeof(esp_ble_mesh_cfg_client_set_state_t)); if (dst->cfg_client_set_state.set_state) { memcpy(dst->cfg_client_set_state.set_state, src->cfg_client_set_state.set_state, - sizeof(esp_ble_mesh_cfg_client_set_state_t)); + sizeof(esp_ble_mesh_cfg_client_set_state_t)); } else { BT_ERR("%s, Out of memory, act %d", __func__, msg->act); } @@ -143,8 +143,8 @@ static void btc_ble_mesh_config_client_copy_req_data(btc_msg_t *msg, void *p_des case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: if (p_src_data->params) { switch (p_src_data->params->opcode) { - case OP_DEV_COMP_DATA_GET: - case OP_DEV_COMP_DATA_STATUS: + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: if (p_src_data->status_cb.comp_data_status.composition_data) { length = p_src_data->status_cb.comp_data_status.composition_data->len; p_dest_data->status_cb.comp_data_status.composition_data = bt_mesh_alloc_buf(length); @@ -157,10 +157,10 @@ static void btc_ble_mesh_config_client_copy_req_data(btc_msg_t *msg, void *p_des p_src_data->status_cb.comp_data_status.composition_data->len); } break; - case OP_MOD_SUB_GET: - case OP_MOD_SUB_GET_VND: - case OP_MOD_SUB_LIST: - case OP_MOD_SUB_LIST_VND: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_GET: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_GET: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_LIST: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_LIST: if (p_src_data->status_cb.model_sub_list.sub_addr) { length = p_src_data->status_cb.model_sub_list.sub_addr->len; p_dest_data->status_cb.model_sub_list.sub_addr = bt_mesh_alloc_buf(length); @@ -173,8 +173,8 @@ static void btc_ble_mesh_config_client_copy_req_data(btc_msg_t *msg, void *p_des p_src_data->status_cb.model_sub_list.sub_addr->len); } break; - case OP_NET_KEY_GET: - case OP_NET_KEY_LIST: + case ESP_BLE_MESH_MODEL_OP_NET_KEY_GET: + case ESP_BLE_MESH_MODEL_OP_NET_KEY_LIST: if (p_src_data->status_cb.netkey_list.net_idx) { length = p_src_data->status_cb.netkey_list.net_idx->len; p_dest_data->status_cb.netkey_list.net_idx = bt_mesh_alloc_buf(length); @@ -187,8 +187,8 @@ static void btc_ble_mesh_config_client_copy_req_data(btc_msg_t *msg, void *p_des p_src_data->status_cb.netkey_list.net_idx->len); } break; - case OP_APP_KEY_GET: - case OP_APP_KEY_LIST: + case ESP_BLE_MESH_MODEL_OP_APP_KEY_GET: + case ESP_BLE_MESH_MODEL_OP_APP_KEY_LIST: if (p_src_data->status_cb.appkey_list.app_idx) { length = p_src_data->status_cb.appkey_list.app_idx->len; p_dest_data->status_cb.appkey_list.app_idx = bt_mesh_alloc_buf(length); @@ -201,10 +201,10 @@ static void btc_ble_mesh_config_client_copy_req_data(btc_msg_t *msg, void *p_des p_src_data->status_cb.appkey_list.app_idx->len); } break; - case OP_SIG_MOD_APP_GET: - case OP_VND_MOD_APP_GET: - case OP_SIG_MOD_APP_LIST: - case OP_VND_MOD_APP_LIST: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_GET: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_GET: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_LIST: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_LIST: if (p_src_data->status_cb.model_app_list.app_idx) { length = p_src_data->status_cb.model_app_list.app_idx->len; p_dest_data->status_cb.model_app_list.app_idx = bt_mesh_alloc_buf(length); @@ -245,28 +245,28 @@ static void btc_ble_mesh_config_client_free_req_data(btc_msg_t *msg) case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: if (arg->params) { switch (arg->params->opcode) { - case OP_DEV_COMP_DATA_GET: - case OP_DEV_COMP_DATA_STATUS: + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: bt_mesh_free_buf(arg->status_cb.comp_data_status.composition_data); break; - case OP_MOD_SUB_GET: - case OP_MOD_SUB_GET_VND: - case OP_MOD_SUB_LIST: - case OP_MOD_SUB_LIST_VND: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_GET: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_GET: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_SUB_LIST: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_SUB_LIST: bt_mesh_free_buf(arg->status_cb.model_sub_list.sub_addr); break; - case OP_NET_KEY_GET: - case OP_NET_KEY_LIST: + case ESP_BLE_MESH_MODEL_OP_NET_KEY_GET: + case ESP_BLE_MESH_MODEL_OP_NET_KEY_LIST: bt_mesh_free_buf(arg->status_cb.netkey_list.net_idx); break; - case OP_APP_KEY_GET: - case OP_APP_KEY_LIST: + case ESP_BLE_MESH_MODEL_OP_APP_KEY_GET: + case ESP_BLE_MESH_MODEL_OP_APP_KEY_LIST: bt_mesh_free_buf(arg->status_cb.appkey_list.app_idx); break; - case OP_SIG_MOD_APP_GET: - case OP_VND_MOD_APP_GET: - case OP_SIG_MOD_APP_LIST: - case OP_VND_MOD_APP_LIST: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_GET: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_GET: + case ESP_BLE_MESH_MODEL_OP_SIG_MODEL_APP_LIST: + case ESP_BLE_MESH_MODEL_OP_VENDOR_MODEL_APP_LIST: bt_mesh_free_buf(arg->status_cb.model_app_list.app_idx); break; default: @@ -287,8 +287,6 @@ static void btc_ble_mesh_config_client_callback(esp_ble_mesh_cfg_client_cb_param { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_CONFIG_CLIENT)) { return; @@ -311,7 +309,7 @@ void bt_mesh_config_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -349,14 +347,14 @@ void bt_mesh_config_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_config_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_config_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_config_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -367,7 +365,6 @@ void btc_ble_mesh_config_client_publish_callback(uint32_t opcode, struct bt_mesh bt_mesh_config_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_CONFIG_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } static int btc_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param_t *params, @@ -400,15 +397,7 @@ static int btc_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param break; } - param.opcode = params->opcode; - param.model = (struct bt_mesh_model *)params->model; - param.ctx.net_idx = params->ctx.net_idx; - param.ctx.app_idx = BLE_MESH_KEY_DEV; - param.ctx.addr = params->ctx.addr; - param.ctx.send_rel = params->ctx.send_rel; - param.ctx.send_ttl = params->ctx.send_ttl; - param.msg_timeout = params->msg_timeout; - param.msg_role = params->msg_role; + btc_ble_mesh_set_client_common_param(params, ¶m, true); switch (param.opcode) { case ESP_BLE_MESH_MODEL_OP_BEACON_GET: @@ -461,8 +450,6 @@ static int btc_ble_mesh_config_client_get_state(esp_ble_mesh_client_common_param BT_ERR("Invalid Configuration Get opcode 0x%04x", param.opcode); return -EINVAL; } - - return 0; } static int btc_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param_t *params, @@ -480,15 +467,7 @@ static int btc_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param return -EINVAL; } - param.opcode = params->opcode; - param.model = (struct bt_mesh_model *)params->model; - param.ctx.net_idx = params->ctx.net_idx; - param.ctx.app_idx = BLE_MESH_KEY_DEV; - param.ctx.addr = params->ctx.addr; - param.ctx.send_rel = params->ctx.send_rel; - param.ctx.send_ttl = params->ctx.send_ttl; - param.msg_timeout = params->msg_timeout; - param.msg_role = params->msg_role; + btc_ble_mesh_set_client_common_param(params, ¶m, true); switch (param.opcode) { case ESP_BLE_MESH_MODEL_OP_BEACON_SET: @@ -609,8 +588,6 @@ static int btc_ble_mesh_config_client_set_state(esp_ble_mesh_client_common_param BT_ERR("Invalid Configuration Set opcode 0x%04x", param.opcode); return -EINVAL; } - - return 0; } void btc_ble_mesh_config_client_call_handler(btc_msg_t *msg) @@ -649,7 +626,6 @@ void btc_ble_mesh_config_client_call_handler(btc_msg_t *msg) } btc_ble_mesh_config_client_arg_deep_free(msg); - return; } void btc_ble_mesh_config_client_cb_handler(btc_msg_t *msg) @@ -670,7 +646,6 @@ void btc_ble_mesh_config_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_config_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_CFG_CLI */ @@ -691,8 +666,6 @@ static void btc_ble_mesh_config_server_callback(esp_ble_mesh_cfg_server_cb_param { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_CONFIG_SERVER)) { return; @@ -705,14 +678,15 @@ static void btc_ble_mesh_config_server_callback(esp_ble_mesh_cfg_server_cb_param btc_transfer_context(&msg, cb_params, cb_params == NULL ? 0 : sizeof(esp_ble_mesh_cfg_server_cb_param_t), NULL, NULL); } -void bt_mesh_config_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_config_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len) { esp_ble_mesh_cfg_server_cb_param_t cb_params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.value)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -737,11 +711,10 @@ void bt_mesh_config_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model cb_params.ctx.send_ttl = ctx->send_ttl; if (val && len) { - memcpy(&cb_params.value, val, MIN(len, sizeof(cb_params.value))); + memcpy(&cb_params.value, val, len); } btc_ble_mesh_config_server_callback(&cb_params, act); - return; } void btc_ble_mesh_config_server_cb_handler(btc_msg_t *msg) diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c index f36074a6e7..b6680f9978 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c @@ -7,6 +7,7 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_generic_model.h" #include "esp_ble_mesh_generic_model_api.h" @@ -357,8 +358,6 @@ static void btc_ble_mesh_generic_client_callback(esp_ble_mesh_generic_client_cb_ { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_GENERIC_CLIENT)) { return; @@ -381,7 +380,7 @@ void bt_mesh_generic_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -419,14 +418,14 @@ void bt_mesh_generic_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_generic_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_generic_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_generic_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -437,15 +436,13 @@ void btc_ble_mesh_generic_client_publish_callback(uint32_t opcode, struct bt_mes bt_mesh_generic_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_GENERIC_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } void btc_ble_mesh_generic_client_call_handler(btc_msg_t *msg) { - esp_ble_mesh_client_common_param_t *params = NULL; - btc_ble_mesh_generic_client_args_t *arg = NULL; esp_ble_mesh_generic_client_cb_param_t cb = {0}; - bt_mesh_client_common_param_t common = {0}; + btc_ble_mesh_generic_client_args_t *arg = NULL; + bt_mesh_client_common_param_t param = {0}; if (!msg) { BT_ERR("%s, Invalid parameter", __func__); @@ -455,52 +452,31 @@ void btc_ble_mesh_generic_client_call_handler(btc_msg_t *msg) arg = (btc_ble_mesh_generic_client_args_t *)(msg->arg); switch (msg->act) { - case BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE: { - params = arg->generic_client_get_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_GET_STATE: + btc_ble_mesh_set_client_common_param(arg->generic_client_get_state.params, ¶m, false); cb.params = arg->generic_client_get_state.params; - cb.error_code = bt_mesh_generic_client_get_state(&common, arg->generic_client_get_state.get_state); + cb.error_code = bt_mesh_generic_client_get_state(¶m, arg->generic_client_get_state.get_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_generic_client_callback(&cb, ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT); } break; - } - case BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE: { - params = arg->generic_client_set_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_GENERIC_CLIENT_SET_STATE: + btc_ble_mesh_set_client_common_param(arg->generic_client_set_state.params, ¶m, false); cb.params = arg->generic_client_set_state.params; - cb.error_code = bt_mesh_generic_client_set_state(&common, arg->generic_client_set_state.set_state); + cb.error_code = bt_mesh_generic_client_set_state(¶m, arg->generic_client_set_state.set_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_generic_client_callback(&cb, ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT); } break; - } default: break; } btc_ble_mesh_generic_client_arg_deep_free(msg); - return; } void btc_ble_mesh_generic_client_cb_handler(btc_msg_t *msg) @@ -521,7 +497,6 @@ void btc_ble_mesh_generic_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_generic_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */ @@ -674,8 +649,6 @@ static void btc_ble_mesh_generic_server_callback(esp_ble_mesh_generic_server_cb_ { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_GENERIC_SERVER)) { return; @@ -689,14 +662,15 @@ static void btc_ble_mesh_generic_server_callback(esp_ble_mesh_generic_server_cb_ btc_ble_mesh_generic_server_copy_req_data, btc_ble_mesh_generic_server_free_req_data); } -void bt_mesh_generic_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_generic_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len) { esp_ble_mesh_generic_server_cb_param_t cb_params = {0}; uint8_t act = 0U; - if (model == NULL || ctx == NULL) { + if (model == NULL || ctx == NULL || len > sizeof(cb_params.value)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -725,13 +699,13 @@ void bt_mesh_generic_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model cb_params.ctx.recv_dst = ctx->recv_dst; cb_params.ctx.recv_rssi = ctx->recv_rssi; cb_params.ctx.send_ttl = ctx->send_ttl; + cb_params.ctx.recv_cred = ctx->recv_cred; if (val && len) { - memcpy(&cb_params.value, val, MIN(len, sizeof(cb_params.value))); + memcpy(&cb_params.value, val, len); } btc_ble_mesh_generic_server_callback(&cb_params, act); - return; } void btc_ble_mesh_generic_server_cb_handler(btc_msg_t *msg) @@ -752,7 +726,6 @@ void btc_ble_mesh_generic_server_cb_handler(btc_msg_t *msg) } btc_ble_mesh_generic_server_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_GENERIC_SERVER */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c index 49f90d930b..75ae22c208 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c @@ -7,8 +7,8 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_health_model.h" -#include "foundation.h" #include "esp_ble_mesh_health_model_api.h" #if CONFIG_BLE_MESH_HEALTH_CLI @@ -136,7 +136,7 @@ static void btc_ble_mesh_health_client_copy_req_data(btc_msg_t *msg, void *p_des case ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT: if (p_src_data->params) { switch (p_src_data->params->opcode) { - case OP_HEALTH_CURRENT_STATUS: + case ESP_BLE_MESH_MODEL_OP_HEALTH_CURRENT_STATUS: if (p_src_data->status_cb.current_status.fault_array) { length = p_src_data->status_cb.current_status.fault_array->len; p_dest_data->status_cb.current_status.fault_array = bt_mesh_alloc_buf(length); @@ -149,10 +149,10 @@ static void btc_ble_mesh_health_client_copy_req_data(btc_msg_t *msg, void *p_des p_src_data->status_cb.current_status.fault_array->len); } break; - case OP_HEALTH_FAULT_GET: - case OP_HEALTH_FAULT_CLEAR: - case OP_HEALTH_FAULT_TEST: - case OP_HEALTH_FAULT_STATUS: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_STATUS: if (p_src_data->status_cb.fault_status.fault_array) { length = p_src_data->status_cb.fault_status.fault_array->len; p_dest_data->status_cb.fault_status.fault_array = bt_mesh_alloc_buf(length); @@ -193,13 +193,13 @@ static void btc_ble_mesh_health_client_free_req_data(btc_msg_t *msg) case ESP_BLE_MESH_HEALTH_CLIENT_PUBLISH_EVT: if (arg->params) { switch (arg->params->opcode) { - case OP_HEALTH_CURRENT_STATUS: + case ESP_BLE_MESH_MODEL_OP_HEALTH_CURRENT_STATUS: bt_mesh_free_buf(arg->status_cb.current_status.fault_array); break; - case OP_HEALTH_FAULT_GET: - case OP_HEALTH_FAULT_CLEAR: - case OP_HEALTH_FAULT_TEST: - case OP_HEALTH_FAULT_STATUS: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_GET: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_CLEAR: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_TEST: + case ESP_BLE_MESH_MODEL_OP_HEALTH_FAULT_STATUS: bt_mesh_free_buf(arg->status_cb.fault_status.fault_array); break; default: @@ -220,8 +220,6 @@ static void btc_ble_mesh_health_client_callback(esp_ble_mesh_health_client_cb_pa { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_HEALTH_CLIENT)) { return; @@ -244,7 +242,7 @@ void bt_mesh_health_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -282,14 +280,14 @@ void bt_mesh_health_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_health_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_health_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_health_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -300,7 +298,6 @@ void btc_ble_mesh_health_publish_callback(uint32_t opcode, struct bt_mesh_model bt_mesh_health_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_HEALTH_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } static int btc_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param_t *params, @@ -318,15 +315,7 @@ static int btc_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param return -EINVAL; } - param.opcode = params->opcode; - param.model = (struct bt_mesh_model *)params->model; - param.ctx.net_idx = params->ctx.net_idx; - param.ctx.app_idx = params->ctx.app_idx; - param.ctx.addr = params->ctx.addr; - param.ctx.send_rel = params->ctx.send_rel; - param.ctx.send_ttl = params->ctx.send_ttl; - param.msg_timeout = params->msg_timeout; - param.msg_role = params->msg_role; + btc_ble_mesh_set_client_common_param(params, ¶m, false); switch (param.opcode) { case ESP_BLE_MESH_MODEL_OP_ATTENTION_GET: @@ -339,8 +328,6 @@ static int btc_ble_mesh_health_client_get_state(esp_ble_mesh_client_common_param BT_ERR("Invalid Health Get opcode 0x%04x", param.opcode); return -EINVAL; } - - return 0; } static int btc_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_t *params, @@ -353,15 +340,7 @@ static int btc_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param return -EINVAL; } - param.opcode = params->opcode; - param.model = (struct bt_mesh_model *)params->model; - param.ctx.net_idx = params->ctx.net_idx; - param.ctx.app_idx = params->ctx.app_idx; - param.ctx.addr = params->ctx.addr; - param.ctx.send_rel = params->ctx.send_rel; - param.ctx.send_ttl = params->ctx.send_ttl; - param.msg_timeout = params->msg_timeout; - param.msg_role = params->msg_role; + btc_ble_mesh_set_client_common_param(params, ¶m, false); switch (param.opcode) { case ESP_BLE_MESH_MODEL_OP_ATTENTION_SET: @@ -384,8 +363,6 @@ static int btc_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param BT_ERR("Invalid Health Set opcode 0x%04x", param.opcode); return -EINVAL; } - - return 0; } void btc_ble_mesh_health_client_call_handler(btc_msg_t *msg) @@ -426,7 +403,6 @@ void btc_ble_mesh_health_client_call_handler(btc_msg_t *msg) } btc_ble_mesh_health_client_arg_deep_free(msg); - return; } void btc_ble_mesh_health_client_cb_handler(btc_msg_t *msg) @@ -447,7 +423,6 @@ void btc_ble_mesh_health_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_health_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_HEALTH_CLI */ @@ -531,8 +506,6 @@ static void btc_ble_mesh_health_server_callback(esp_ble_mesh_health_server_cb_pa { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_HEALTH_SERVER)) { return; @@ -570,7 +543,6 @@ void btc_ble_mesh_health_server_call_handler(btc_msg_t *msg) } btc_ble_mesh_health_server_arg_deep_free(msg); - return; } void btc_ble_mesh_health_server_cb_handler(btc_msg_t *msg) @@ -591,7 +563,6 @@ void btc_ble_mesh_health_server_cb_handler(btc_msg_t *msg) } btc_ble_mesh_health_server_free_req_data(msg); - return; } void btc_ble_mesh_health_server_fault_clear(struct bt_mesh_model *model, uint16_t company_id) diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c index ea3d5917e7..3195c513f5 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c @@ -7,6 +7,7 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_lighting_model.h" #include "esp_ble_mesh_lighting_model_api.h" @@ -79,7 +80,7 @@ void btc_ble_mesh_lighting_client_arg_deep_free(btc_msg_t *msg) { btc_ble_mesh_lighting_client_args_t *arg = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -165,7 +166,7 @@ static void btc_ble_mesh_lighting_client_free_req_data(btc_msg_t *msg) { esp_ble_mesh_light_client_cb_param_t *arg = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -201,8 +202,6 @@ static void btc_ble_mesh_lighting_client_callback(esp_ble_mesh_light_client_cb_p { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_LIGHTING_CLIENT)) { return; @@ -225,7 +224,7 @@ void bt_mesh_lighting_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -263,14 +262,14 @@ void bt_mesh_lighting_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_lighting_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_lighting_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_lighting_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -281,17 +280,15 @@ void btc_ble_mesh_lighting_client_publish_callback(uint32_t opcode, struct bt_me bt_mesh_lighting_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_LIGHTING_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } void btc_ble_mesh_lighting_client_call_handler(btc_msg_t *msg) { - esp_ble_mesh_client_common_param_t *params = NULL; btc_ble_mesh_lighting_client_args_t *arg = NULL; esp_ble_mesh_light_client_cb_param_t cb = {0}; - bt_mesh_client_common_param_t common = {0}; + bt_mesh_client_common_param_t param = {0}; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -299,59 +296,38 @@ void btc_ble_mesh_lighting_client_call_handler(btc_msg_t *msg) arg = (btc_ble_mesh_lighting_client_args_t *)(msg->arg); switch (msg->act) { - case BTC_BLE_MESH_ACT_LIGHTING_CLIENT_GET_STATE: { - params = arg->light_client_get_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_LIGHTING_CLIENT_GET_STATE: + btc_ble_mesh_set_client_common_param(arg->light_client_get_state.params, ¶m, false); cb.params = arg->light_client_get_state.params; - cb.error_code = bt_mesh_light_client_get_state(&common, arg->light_client_get_state.get_state); + cb.error_code = bt_mesh_light_client_get_state(¶m, arg->light_client_get_state.get_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_lighting_client_callback(&cb, ESP_BLE_MESH_LIGHT_CLIENT_GET_STATE_EVT); } break; - } - case BTC_BLE_MESH_ACT_LIGHTING_CLIENT_SET_STATE: { - params = arg->light_client_set_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_LIGHTING_CLIENT_SET_STATE: + btc_ble_mesh_set_client_common_param(arg->light_client_set_state.params, ¶m, false); cb.params = arg->light_client_set_state.params; - cb.error_code = bt_mesh_light_client_set_state(&common, arg->light_client_set_state.set_state); + cb.error_code = bt_mesh_light_client_set_state(¶m, arg->light_client_set_state.set_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_lighting_client_callback(&cb, ESP_BLE_MESH_LIGHT_CLIENT_SET_STATE_EVT); } break; - } default: break; } btc_ble_mesh_lighting_client_arg_deep_free(msg); - return; } void btc_ble_mesh_lighting_client_cb_handler(btc_msg_t *msg) { esp_ble_mesh_light_client_cb_param_t *param = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -365,7 +341,6 @@ void btc_ble_mesh_lighting_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_lighting_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */ @@ -462,13 +437,13 @@ static void btc_ble_mesh_lighting_server_free_req_data(btc_msg_t *msg) switch (msg->act) { case ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT: if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET || - arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) { + arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) { bt_mesh_free_buf(arg->value.state_change.lc_property_set.property_value); } break; case ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT: if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET || - arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) { + arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) { bt_mesh_free_buf(arg->value.set.lc_property.property_value); } break; @@ -486,8 +461,6 @@ static void btc_ble_mesh_lighting_server_callback(esp_ble_mesh_lighting_server_c { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_LIGHTING_SERVER)) { return; @@ -501,14 +474,15 @@ static void btc_ble_mesh_lighting_server_callback(esp_ble_mesh_lighting_server_c btc_ble_mesh_lighting_server_copy_req_data, btc_ble_mesh_lighting_server_free_req_data); } -void bt_mesh_lighting_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_lighting_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len) { esp_ble_mesh_lighting_server_cb_param_t cb_params = {0}; uint8_t act = 0U; - if (model == NULL || ctx == NULL) { + if (model == NULL || ctx == NULL || len > sizeof(cb_params.value)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -542,11 +516,10 @@ void bt_mesh_lighting_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_mode cb_params.ctx.send_ttl = ctx->send_ttl; if (val && len) { - memcpy(&cb_params.value, val, MIN(len, sizeof(cb_params.value))); + memcpy(&cb_params.value, val, len); } btc_ble_mesh_lighting_server_callback(&cb_params, act); - return; } void btc_ble_mesh_lighting_server_cb_handler(btc_msg_t *msg) @@ -567,7 +540,6 @@ void btc_ble_mesh_lighting_server_cb_handler(btc_msg_t *msg) } btc_ble_mesh_lighting_server_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */ 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 b29820bec5..927e923ec5 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 @@ -10,10 +10,20 @@ #include "btc_ble_mesh_prov.h" #include "btc_ble_mesh_config_model.h" #include "btc_ble_mesh_health_model.h" +#include "btc_ble_mesh_prb_model.h" #include "btc_ble_mesh_generic_model.h" #include "btc_ble_mesh_time_scene_model.h" #include "btc_ble_mesh_sensor_model.h" #include "btc_ble_mesh_lighting_model.h" +#include "btc_ble_mesh_brc_model.h" +#include "btc_ble_mesh_odp_model.h" +#include "btc_ble_mesh_srpl_model.h" +#include "btc_ble_mesh_agg_model.h" +#include "btc_ble_mesh_sar_model.h" +#include "btc_ble_mesh_lcd_model.h" +#include "btc_ble_mesh_rpr_model.h" +#include "btc_ble_mesh_df_model.h" +#include "btc_ble_mesh_mbt_model.h" #include "adv.h" #include "mesh/kernel.h" @@ -22,6 +32,7 @@ #include "access.h" #include "prov_node.h" #include "settings_uid.h" +#include "proxy_common.h" #include "proxy_server.h" #include "proxy_client.h" #include "prov_pvnr.h" @@ -53,6 +64,8 @@ #include "mesh/state_binding.h" #include "local.h" +#include "mesh_v1.1/utils.h" + #include "esp_ble_mesh_common_api.h" #include "esp_ble_mesh_provisioning_api.h" #include "esp_ble_mesh_networking_api.h" @@ -152,6 +165,65 @@ void btc_ble_mesh_prov_arg_deep_free(btc_msg_t *msg) } } +static void btc_ble_mesh_prov_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_prov_cb_param_t *p_dest_data = (esp_ble_mesh_prov_cb_param_t *)p_dest; + esp_ble_mesh_prov_cb_param_t *p_src_data = (esp_ble_mesh_prov_cb_param_t *)p_src; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { +#if CONFIG_BLE_MESH_CERT_BASED_PROV + case ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT: { + if (p_src_data->recv_provisioner_records_list.msg) { + p_dest_data->recv_provisioner_records_list.msg = (uint8_t *)bt_mesh_alloc_buf(p_src_data->recv_provisioner_records_list.len); + if (!p_dest_data->recv_provisioner_records_list.msg) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->recv_provisioner_records_list.msg, + p_src_data->recv_provisioner_records_list.msg, + p_src_data->recv_provisioner_records_list.len); + } + break; + } +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + default: + break; + } +} + +static void btc_ble_mesh_prov_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_prov_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_prov_cb_param_t *)(msg->arg); + + switch (msg->act) { +#if CONFIG_BLE_MESH_CERT_BASED_PROV + case ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT: { + if (arg->recv_provisioner_records_list.msg) { + bt_mesh_free(arg->recv_provisioner_records_list.msg); + } + break; + } +#else + ARG_UNUSED(arg); +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + default: + break; + } +} + void btc_ble_mesh_model_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { btc_ble_mesh_model_args_t *dst = (btc_ble_mesh_model_args_t *)p_dest; @@ -225,8 +297,6 @@ void btc_ble_mesh_model_arg_deep_free(btc_msg_t *msg) default: break; } - - return; } static void btc_ble_mesh_model_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) @@ -357,8 +427,6 @@ static bt_status_t btc_ble_mesh_model_callback(esp_ble_mesh_model_cb_param_t *pa btc_msg_t msg = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_MODEL)) { return BT_STATUS_SUCCESS; @@ -389,7 +457,6 @@ static void btc_ble_mesh_server_model_op_cb(struct bt_mesh_model *model, mesh_param.model_operation.msg = buf->data; btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_OPERATION_EVT); - return; } static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model, @@ -427,7 +494,6 @@ static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model, } bt_mesh_client_model_unlock(); - return; } static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work) @@ -446,7 +512,7 @@ static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); mesh_param.client_send_timeout.opcode = node->opcode; - mesh_param.client_send_timeout.model = (esp_ble_mesh_model_t *)ctx.model; + mesh_param.client_send_timeout.model = (esp_ble_mesh_model_t *)node->model; mesh_param.client_send_timeout.ctx = (esp_ble_mesh_msg_ctx_t *)&ctx; bt_mesh_client_free_node(node); btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT); @@ -454,7 +520,6 @@ static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work) } bt_mesh_client_model_unlock(); - return; } static void btc_ble_mesh_model_send_comp_cb(esp_ble_mesh_model_t *model, @@ -469,7 +534,6 @@ static void btc_ble_mesh_model_send_comp_cb(esp_ble_mesh_model_t *model, mesh_param.model_send_comp.ctx = ctx; btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_SEND_COMP_EVT); - return; } static void btc_ble_mesh_model_publish_comp_cb(esp_ble_mesh_model_t *model, int err) @@ -480,7 +544,6 @@ static void btc_ble_mesh_model_publish_comp_cb(esp_ble_mesh_model_t *model, int mesh_param.model_publish_comp.model = model; btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT); - return; } static int btc_ble_mesh_model_publish_update(struct bt_mesh_model *mod) @@ -488,8 +551,6 @@ static int btc_ble_mesh_model_publish_update(struct bt_mesh_model *mod) esp_ble_mesh_model_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.model_publish_update.model = (esp_ble_mesh_model_t *)mod; ret = btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT); @@ -508,7 +569,6 @@ static void btc_ble_mesh_server_model_update_state_comp_cb(esp_ble_mesh_model_t mesh_param.server_model_update_state.type = type; btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_SERVER_MODEL_UPDATE_STATE_COMP_EVT); - return; } #endif /* CONFIG_BLE_MESH_SERVER_MODEL */ @@ -517,8 +577,6 @@ static bt_status_t btc_ble_mesh_prov_callback(esp_ble_mesh_prov_cb_param_t *para btc_msg_t msg = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_PROV)) { return BT_STATUS_SUCCESS; @@ -528,20 +586,26 @@ static bt_status_t btc_ble_mesh_prov_callback(esp_ble_mesh_prov_cb_param_t *para msg.pid = BTC_PID_PROV; msg.act = act; - ret = btc_transfer_context(&msg, param, param == NULL ? 0 : sizeof(esp_ble_mesh_prov_cb_param_t), NULL, NULL); + ret = btc_transfer_context(&msg, param, param == NULL ? 0 : sizeof(esp_ble_mesh_prov_cb_param_t), + btc_ble_mesh_prov_copy_req_data, btc_ble_mesh_prov_free_req_data); if (ret != BT_STATUS_SUCCESS) { BT_ERR("btc_transfer_context failed"); } return ret; } +#if CONFIG_BLE_MESH_DF_SRV +int btc_ble_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay) +{ + return bt_mesh_enable_directed_forwarding(net_idx, directed_forwarding, directed_forwarding_relay); +} +#endif /* CONFIG_BLE_MESH_DF_SRV */ + #if CONFIG_BLE_MESH_NODE static void btc_ble_mesh_oob_pub_key_cb(void) { - BT_DBG("%s", __func__); - btc_ble_mesh_prov_callback(NULL, ESP_BLE_MESH_NODE_PROV_OOB_PUB_KEY_EVT); - return; } static int btc_ble_mesh_output_number_cb(bt_mesh_output_action_t act, uint32_t num) @@ -549,8 +613,6 @@ static int btc_ble_mesh_output_number_cb(bt_mesh_output_action_t act, uint32_t n esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.node_prov_output_num.action = (esp_ble_mesh_output_action_t)act; mesh_param.node_prov_output_num.number = num; @@ -563,10 +625,8 @@ static int btc_ble_mesh_output_string_cb(const char *str) esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - strncpy(mesh_param.node_prov_output_str.string, str, - MIN(strlen(str), sizeof(mesh_param.node_prov_output_str.string))); + MIN(strlen(str), sizeof(mesh_param.node_prov_output_str.string))); ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT); return (ret == BT_STATUS_SUCCESS) ? 0 : -1; @@ -577,8 +637,6 @@ static int btc_ble_mesh_input_cb(bt_mesh_input_action_t act, uint8_t size) esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.node_prov_input.action = (esp_ble_mesh_input_action_t)act; mesh_param.node_prov_input.size = size; @@ -590,24 +648,19 @@ static void btc_ble_mesh_link_open_cb(bt_mesh_prov_bearer_t bearer) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.node_prov_link_open.bearer = (esp_ble_mesh_prov_bearer_t)bearer; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT); - return; } -static void btc_ble_mesh_link_close_cb(bt_mesh_prov_bearer_t bearer) +static void btc_ble_mesh_link_close_cb(bt_mesh_prov_bearer_t bearer, uint8_t reason) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.node_prov_link_close.bearer = (esp_ble_mesh_prov_bearer_t)bearer; + mesh_param.node_prov_link_close.reason = reason; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT); - return; } static void btc_ble_mesh_complete_cb(uint16_t net_idx, const uint8_t net_key[16], @@ -615,8 +668,6 @@ static void btc_ble_mesh_complete_cb(uint16_t net_idx, const uint8_t net_key[16] { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.node_prov_complete.net_idx = net_idx; memcpy(mesh_param.node_prov_complete.net_key, net_key, 16); mesh_param.node_prov_complete.addr = addr; @@ -624,15 +675,11 @@ static void btc_ble_mesh_complete_cb(uint16_t net_idx, const uint8_t net_key[16] mesh_param.node_prov_complete.iv_index = iv_index; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT); - return; } static void btc_ble_mesh_reset_cb(void) { - BT_DBG("%s", __func__); - btc_ble_mesh_prov_callback(NULL, ESP_BLE_MESH_NODE_PROV_RESET_EVT); - return; } const uint8_t *btc_ble_mesh_node_get_local_net_key(uint16_t net_idx) @@ -650,20 +697,14 @@ static void btc_ble_mesh_prov_register_complete_cb(int err_code) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.prov_register_comp.err_code = err_code; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROV_REGISTER_COMP_EVT); - return; } static void btc_ble_mesh_prov_set_complete_cb(esp_ble_mesh_prov_cb_param_t *param, uint8_t act) { - BT_DBG("%s", __func__); - btc_ble_mesh_prov_callback(param, act); - return; } #if CONFIG_BLE_MESH_PROVISIONER @@ -674,10 +715,8 @@ static void btc_ble_mesh_provisioner_recv_unprov_adv_pkt_cb(const uint8_t addr[6 { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - if (addr == NULL || dev_uuid == NULL || - (bearer != BLE_MESH_PROV_ADV && bearer != BLE_MESH_PROV_GATT)) { + (bearer != BLE_MESH_PROV_ADV && bearer != BLE_MESH_PROV_GATT)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -691,7 +730,6 @@ static void btc_ble_mesh_provisioner_recv_unprov_adv_pkt_cb(const uint8_t addr[6 mesh_param.provisioner_recv_unprov_adv_pkt.rssi = rssi; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT); - return; } static int btc_ble_mesh_provisioner_prov_read_oob_pub_key_cb(uint8_t link_idx) @@ -699,8 +737,6 @@ static int btc_ble_mesh_provisioner_prov_read_oob_pub_key_cb(uint8_t link_idx) esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_read_oob_pub_key.link_idx = link_idx; ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_EVT); @@ -713,8 +749,6 @@ static int btc_ble_mesh_provisioner_prov_input_cb(uint8_t method, bt_mesh_output esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_input.method = (esp_ble_mesh_oob_method_t)method; mesh_param.provisioner_prov_input.action = (esp_ble_mesh_output_action_t)act; mesh_param.provisioner_prov_input.size = size; @@ -730,8 +764,6 @@ static int btc_ble_mesh_provisioner_prov_output_cb(uint8_t method, bt_mesh_input esp_ble_mesh_prov_cb_param_t mesh_param = {0}; bt_status_t ret = BT_STATUS_SUCCESS; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_output.method = (esp_ble_mesh_oob_method_t)method; mesh_param.provisioner_prov_output.action = (esp_ble_mesh_input_action_t)act; mesh_param.provisioner_prov_output.size = size; @@ -750,25 +782,19 @@ static void btc_ble_mesh_provisioner_link_open_cb(bt_mesh_prov_bearer_t bearer) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_link_open.bearer = (esp_ble_mesh_prov_bearer_t)bearer; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT); - return; } static void btc_ble_mesh_provisioner_link_close_cb(bt_mesh_prov_bearer_t bearer, uint8_t reason) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_link_close.bearer = (esp_ble_mesh_prov_bearer_t)bearer; mesh_param.provisioner_prov_link_close.reason = reason; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT); - return; } static void btc_ble_mesh_provisioner_prov_complete_cb(uint16_t node_idx, const uint8_t device_uuid[16], @@ -777,8 +803,6 @@ static void btc_ble_mesh_provisioner_prov_complete_cb(uint16_t node_idx, const u { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.provisioner_prov_complete.node_idx = node_idx; mesh_param.provisioner_prov_complete.unicast_addr = unicast_addr; mesh_param.provisioner_prov_complete.element_num = element_num; @@ -786,9 +810,45 @@ static void btc_ble_mesh_provisioner_prov_complete_cb(uint16_t node_idx, const u memcpy(mesh_param.provisioner_prov_complete.device_uuid, device_uuid, sizeof(esp_ble_mesh_octet16_t)); btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT); - return; } +#if CONFIG_BLE_MESH_CERT_BASED_PROV +static void btc_ble_mesh_provisioner_cert_based_prov_start_cb(uint16_t link_idx) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + + mesh_param.provisioner_cert_based_prov_start.link_idx = link_idx; + + btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_CERT_BASED_PROV_START_EVT); +} + +static void btc_ble_mesh_provisioner_records_list_get_cb(uint16_t link_idx, struct net_buf_simple *buf) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + + mesh_param.recv_provisioner_records_list.link_idx = link_idx; + mesh_param.recv_provisioner_records_list.len = buf->len; + mesh_param.recv_provisioner_records_list.msg = buf->data; + + btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_RECV_PROV_RECORDS_LIST_EVT); +} + +static void btc_ble_mesh_provisioner_record_recv_comp_cb(uint8_t status, uint16_t link_idx, uint16_t record_id, + uint16_t frag_offset, uint16_t total_len, uint8_t *record) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + + mesh_param.provisioner_prov_record_recv_comp.status = status; + mesh_param.provisioner_prov_record_recv_comp.link_idx = link_idx; + mesh_param.provisioner_prov_record_recv_comp.record_id = record_id; + mesh_param.provisioner_prov_record_recv_comp.frag_offset = frag_offset; + mesh_param.provisioner_prov_record_recv_comp.total_len = total_len; + mesh_param.provisioner_prov_record_recv_comp.record = record; + + btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_RECORD_RECV_COMP_EVT); +} +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + esp_ble_mesh_node_t *btc_ble_mesh_provisioner_get_node_with_uuid(const uint8_t uuid[16]) { return (esp_ble_mesh_node_t *)bt_mesh_provisioner_get_node_with_uuid(uuid); @@ -856,13 +916,10 @@ static void btc_ble_mesh_node_recv_heartbeat_cb(uint8_t hops, uint16_t feature) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; - BT_DBG("%s", __func__); - mesh_param.heartbeat_msg_recv.hops = hops; mesh_param.heartbeat_msg_recv.feature = feature; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_HEARTBEAT_MESSAGE_RECV_EVT); - return; } #if CONFIG_BLE_MESH_LOW_POWER @@ -871,8 +928,6 @@ static void btc_ble_mesh_lpn_cb(uint16_t friend_addr, bool established) esp_ble_mesh_prov_cb_param_t mesh_param = {0}; uint8_t act = 0U; - BT_DBG("%s", __func__); - if (established) { mesh_param.lpn_friendship_establish.friend_addr = friend_addr; act = ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT; @@ -882,7 +937,6 @@ static void btc_ble_mesh_lpn_cb(uint16_t friend_addr, bool established) } btc_ble_mesh_prov_callback(&mesh_param, act); - return; } #endif /* CONFIG_BLE_MESH_LOW_POWER */ @@ -892,8 +946,6 @@ void btc_ble_mesh_friend_cb(bool establish, uint16_t lpn_addr, uint8_t reason) esp_ble_mesh_prov_cb_param_t mesh_param = {0}; uint8_t act = 0U; - BT_DBG("%s", __func__); - if (!BLE_MESH_ADDR_IS_UNICAST(lpn_addr)) { BT_ERR("Not a unicast lpn address 0x%04x", lpn_addr); return; @@ -909,7 +961,6 @@ void btc_ble_mesh_friend_cb(bool establish, uint16_t lpn_addr, uint8_t reason) } btc_ble_mesh_prov_callback(&mesh_param, act); - return; } #endif /* CONFIG_BLE_MESH_FRIEND */ @@ -924,8 +975,6 @@ static void btc_ble_mesh_proxy_client_adv_recv_cb(const bt_mesh_addr_t *addr, ui return; } - BT_DBG("%s", __func__); - mesh_param.proxy_client_recv_adv_pkt.addr_type = addr->type; memcpy(mesh_param.proxy_client_recv_adv_pkt.addr, addr->val, BD_ADDR_LEN); mesh_param.proxy_client_recv_adv_pkt.net_idx = ctx->net_id.net_idx; @@ -933,7 +982,6 @@ static void btc_ble_mesh_proxy_client_adv_recv_cb(const bt_mesh_addr_t *addr, ui mesh_param.proxy_client_recv_adv_pkt.rssi = rssi; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_CLIENT_RECV_ADV_PKT_EVT); - return; } static void btc_ble_mesh_proxy_client_connect_cb(const bt_mesh_addr_t *addr, @@ -946,15 +994,12 @@ static void btc_ble_mesh_proxy_client_connect_cb(const bt_mesh_addr_t *addr, return; } - BT_DBG("%s", __func__); - mesh_param.proxy_client_connected.addr_type = addr->type; memcpy(mesh_param.proxy_client_connected.addr, addr->val, BD_ADDR_LEN); mesh_param.proxy_client_connected.conn_handle = conn_handle; mesh_param.proxy_client_connected.net_idx = net_idx; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_CLIENT_CONNECTED_EVT); - return; } static void btc_ble_mesh_proxy_client_disconnect_cb(const bt_mesh_addr_t *addr, uint8_t conn_handle, @@ -967,8 +1012,6 @@ static void btc_ble_mesh_proxy_client_disconnect_cb(const bt_mesh_addr_t *addr, return; } - BT_DBG("%s", __func__); - mesh_param.proxy_client_disconnected.addr_type = addr->type; memcpy(mesh_param.proxy_client_disconnected.addr, addr->val, BD_ADDR_LEN); mesh_param.proxy_client_disconnected.conn_handle = conn_handle; @@ -976,7 +1019,6 @@ static void btc_ble_mesh_proxy_client_disconnect_cb(const bt_mesh_addr_t *addr, mesh_param.proxy_client_disconnected.reason = reason; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_CLIENT_DISCONNECTED_EVT); - return; } static void btc_ble_mesh_proxy_client_filter_status_recv_cb(uint8_t conn_handle, uint16_t src, uint16_t net_idx, @@ -989,8 +1031,6 @@ static void btc_ble_mesh_proxy_client_filter_status_recv_cb(uint8_t conn_handle, return; } - BT_DBG("%s", __func__); - mesh_param.proxy_client_recv_filter_status.conn_handle = conn_handle; mesh_param.proxy_client_recv_filter_status.server_addr = src; mesh_param.proxy_client_recv_filter_status.net_idx = net_idx; @@ -998,7 +1038,6 @@ static void btc_ble_mesh_proxy_client_filter_status_recv_cb(uint8_t conn_handle, mesh_param.proxy_client_recv_filter_status.list_size = list_size; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_CLIENT_RECV_FILTER_STATUS_EVT); - return; } #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ @@ -1012,8 +1051,6 @@ static void btc_ble_mesh_proxy_server_connect_cb(uint8_t conn_handle) return; } - BT_DBG("%s", __func__); - mesh_param.proxy_server_connected.conn_handle = conn_handle; btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_SERVER_CONNECTED_EVT); @@ -1028,8 +1065,6 @@ static void btc_ble_mesh_proxy_server_disconnect_cb(uint8_t conn_handle, uint8_t return; } - BT_DBG("%s", __func__); - mesh_param.proxy_server_disconnected.conn_handle = conn_handle; mesh_param.proxy_server_disconnected.reason = reason; @@ -1046,7 +1081,7 @@ int btc_ble_mesh_client_model_init(esp_ble_mesh_model_t *model) __ASSERT(model && model->op, "Invalid parameter"); esp_ble_mesh_model_op_t *op = model->op; - while (op != NULL && op->opcode != 0) { + while (op && op->opcode != 0) { op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_client_model_op_cb; op++; } @@ -1119,6 +1154,100 @@ extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb; #endif /* CONFIG_BLE_MESH_HEALTH_CLI */ +/* Bridge Configuration Models */ +#if CONFIG_BLE_MESH_BRC_SRV +extern const struct bt_mesh_model_op bt_mesh_brc_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_brc_srv_cb; +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +#if CONFIG_BLE_MESH_BRC_CLI +typedef bt_mesh_client_user_data_t bt_mesh_brc_client_t; +extern const struct bt_mesh_model_op bt_mesh_brc_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_brc_cli_cb; +#endif /* CONFIG_BLE_MESH_BRC_CLI */ + +/* Mesh Private Beacon Models */ +#if CONFIG_BLE_MESH_PRB_SRV +extern const struct bt_mesh_model_op bt_mesh_prb_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_prb_srv_cb; +#endif /* CONFIG_BLE_MESH_PRB_SRV */ +#if CONFIG_BLE_MESH_PRB_CLI +typedef bt_mesh_client_user_data_t bt_mesh_prb_client_t; +extern const struct bt_mesh_model_op bt_mesh_prb_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_prb_cli_cb; +#endif /* CONFIG_BLE_MESH_PRB_CLI */ + +#if CONFIG_BLE_MESH_ODP_SRV +extern const struct bt_mesh_model_op bt_mesh_odp_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_odp_srv_cb; +#endif /* CONFIG_BLE_MESH_ODP_SRV */ +#if CONFIG_BLE_MESH_ODP_CLI +typedef bt_mesh_client_user_data_t bt_mesh_odp_client_t; +extern const struct bt_mesh_model_op bt_mesh_odp_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_odp_cli_cb; +#endif /* CONFIG_BLE_MESH_ODP_CLI */ + +#if CONFIG_BLE_MESH_SRPL_SRV +extern const struct bt_mesh_model_op bt_mesh_srpl_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_srpl_srv_cb; +#endif /* CONFIG_BLE_MESH_SRPL_SRV */ +#if CONFIG_BLE_MESH_SRPL_CLI +typedef bt_mesh_client_user_data_t bt_mesh_srpl_client_t; +extern const struct bt_mesh_model_op bt_mesh_srpl_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_srpl_cli_cb; +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ + +#if CONFIG_BLE_MESH_AGG_SRV +extern const struct bt_mesh_model_op bt_mesh_agg_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_agg_srv_cb; +#endif /* CONFIG_BLE_MESH_AGG_SRV */ +#if CONFIG_BLE_MESH_AGG_CLI +typedef bt_mesh_client_user_data_t bt_mesh_agg_client_t; +extern const struct bt_mesh_model_op bt_mesh_agg_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_agg_cli_cb; +#endif /* CONFIG_BLE_MESH_AGG_CLI */ + +#if CONFIG_BLE_MESH_SAR_SRV +extern const struct bt_mesh_model_op bt_mesh_sar_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_sar_srv_cb; +#endif /* CONFIG_BLE_MESH_SAR_SRV */ +#if CONFIG_BLE_MESH_SAR_CLI +typedef bt_mesh_client_user_data_t bt_mesh_sar_client_t; +extern const struct bt_mesh_model_op bt_mesh_sar_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_sar_cli_cb; +#endif /* CONFIG_BLE_MESH_SAR_CLI */ + +#if CONFIG_BLE_MESH_LCD_SRV +extern const struct bt_mesh_model_op bt_mesh_lcd_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_lcd_srv_cb; +#endif /* CONFIG_BLE_MESH_LCD_SRV */ +#if CONFIG_BLE_MESH_LCD_CLI +typedef bt_mesh_client_user_data_t bt_mesh_lcd_client_t; +extern const struct bt_mesh_model_op bt_mesh_lcd_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_lcd_cli_cb; +#endif /* CONFIG_BLE_MESH_LCD_CLI */ + +/* Remote Provisioning models */ +#if CONFIG_BLE_MESH_RPR_SRV +extern const struct bt_mesh_model_op bt_mesh_rpr_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_rpr_srv_cb; +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +#if CONFIG_BLE_MESH_RPR_CLI +typedef bt_mesh_client_user_data_t bt_mesh_rpr_client_t; +extern const struct bt_mesh_model_op bt_mesh_rpr_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_rpr_cli_cb; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ + +/* Directed Forwarding Configuration Models */ +#if CONFIG_BLE_MESH_DF_SRV +extern const struct bt_mesh_model_op bt_mesh_df_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_df_srv_cb; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +#if CONFIG_BLE_MESH_DF_CLI +typedef bt_mesh_client_user_data_t bt_mesh_df_client_t; +extern const struct bt_mesh_model_op bt_mesh_df_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_df_cli_cb; +#endif /* CONFIG_BLE_MESH_DF_CLI */ + /* Generic Client Models */ #if CONFIG_BLE_MESH_GENERIC_CLIENT extern const struct bt_mesh_model_op bt_mesh_gen_onoff_cli_op[]; @@ -1242,6 +1371,17 @@ extern const struct bt_mesh_model_cb bt_mesh_sensor_srv_cb; extern const struct bt_mesh_model_cb bt_mesh_sensor_setup_srv_cb; #endif /* CONFIG_BLE_MESH_SENSOR_SERVER */ +/* Blob Transfer Models */ +#if CONFIG_BLE_MESH_MBT_SRV +extern const struct bt_mesh_model_op bt_mesh_mbt_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_mbt_srv_cb; +#endif /* CONFIG_BLE_MESH_MBT_SRV */ +#if CONFIG_BLE_MESH_MBT_CLI +typedef bt_mesh_client_user_data_t bt_mesh_mbt_client_t; +extern const struct bt_mesh_model_op bt_mesh_mbt_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_mbt_cli_cb; +#endif /* CONFIG_BLE_MESH_MBT_CLI */ + static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) { if (!model) { @@ -1271,11 +1411,15 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_cfg_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_cfg_cli_cb; bt_mesh_config_client_t *cli = (bt_mesh_config_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_config_client_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_CFG_CLI: + __ASSERT(0, "Configuration Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_CFG_CLI */ #if CONFIG_BLE_MESH_HEALTH_SRV case BLE_MESH_MODEL_ID_HEALTH_SRV: { @@ -1290,24 +1434,258 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) } break; } +#else + case BLE_MESH_MODEL_ID_HEALTH_SRV: + __ASSERT(0, "Health Server model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_HEALTH_SRV */ #if CONFIG_BLE_MESH_HEALTH_CLI case BLE_MESH_MODEL_ID_HEALTH_CLI: { model->op = (esp_ble_mesh_model_op_t *)bt_mesh_health_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_health_cli_cb; bt_mesh_health_client_t *cli = (bt_mesh_health_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_health_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_HEALTH_CLI: + __ASSERT(0, "Health Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_HEALTH_CLI */ +#if CONFIG_BLE_MESH_BRC_SRV + case BLE_MESH_MODEL_ID_BRC_SRV: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_brc_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_brc_srv_cb; + break; + } +#else + case BLE_MESH_MODEL_ID_BRC_SRV: + __ASSERT(0, "Bridge Configuration Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +#if CONFIG_BLE_MESH_BRC_CLI + case BLE_MESH_MODEL_ID_BRC_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_brc_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_brc_cli_cb; + bt_mesh_brc_client_t *cli = (bt_mesh_brc_client_t *)model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_brc_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_BRC_CLI: + __ASSERT(0, "Bridge Configuration Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_BRC_CLI */ +#if CONFIG_BLE_MESH_PRB_SRV + case BLE_MESH_MODEL_ID_PRB_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_prb_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_prb_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_PRB_SRV: + __ASSERT(0, "Mesh Private Beacon Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_PRB_SRV */ +#if CONFIG_BLE_MESH_PRB_CLI + case BLE_MESH_MODEL_ID_PRB_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_prb_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_prb_cli_cb; + bt_mesh_prb_client_t *cli = (bt_mesh_prb_client_t *)model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_prb_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_PRB_CLI: + __ASSERT(0, "Mesh Private Beacon Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_PRB_CLI */ +#if CONFIG_BLE_MESH_ODP_CLI + case BLE_MESH_MODEL_ID_ODP_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_odp_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_odp_cli_cb; + bt_mesh_odp_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_odp_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_ODP_CLI: + __ASSERT(0, "On-Demand Private Proxy Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_ODP_CLI */ +#if CONFIG_BLE_MESH_ODP_SRV + case BLE_MESH_MODEL_ID_ODP_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_odp_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_odp_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_ODP_SRV: + __ASSERT(0, "On-Demand Private Proxy Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_ODP_SRV */ +#if CONFIG_BLE_MESH_SRPL_CLI + case BLE_MESH_MODEL_ID_SRPL_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_srpl_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_srpl_cli_cb; + bt_mesh_srpl_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_srpl_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_SRPL_CLI: + __ASSERT(0, "Solicitation PDU RPL Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ +#if CONFIG_BLE_MESH_SRPL_SRV + case BLE_MESH_MODEL_ID_SRPL_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_srpl_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_srpl_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_SRPL_SRV: + __ASSERT(0, "Solicitation PDU RPL Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_SRPL_SRV */ +#if CONFIG_BLE_MESH_AGG_CLI + case BLE_MESH_MODEL_ID_AGG_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_agg_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_agg_cli_cb; + bt_mesh_agg_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_agg_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_AGG_CLI: + __ASSERT(0, "Opcodes Aggregator Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_AGG_CLI */ +#if CONFIG_BLE_MESH_AGG_SRV + case BLE_MESH_MODEL_ID_AGG_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_agg_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_agg_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_AGG_SRV: + __ASSERT(0, "Opcodes Aggregator Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_AGG_SRV */ +#if CONFIG_BLE_MESH_SAR_CLI + case BLE_MESH_MODEL_ID_SAR_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_sar_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_sar_cli_cb; + bt_mesh_sar_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_sar_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_SAR_CLI: + __ASSERT(0, "SAR Configuration Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_SAR_CLI */ +#if CONFIG_BLE_MESH_SAR_SRV + case BLE_MESH_MODEL_ID_SAR_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_sar_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_sar_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_SAR_SRV: + __ASSERT(0, "SAR Configuration Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_SAR_SRV */ +#if CONFIG_BLE_MESH_LCD_CLI + case BLE_MESH_MODEL_ID_LCD_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_lcd_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lcd_cli_cb; + bt_mesh_lcd_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_lcd_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_LCD_CLI: + __ASSERT(0, "Large Comp Data Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_LCD_CLI */ +#if CONFIG_BLE_MESH_LCD_SRV + case BLE_MESH_MODEL_ID_LCD_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_lcd_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lcd_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_LCD_SRV: + __ASSERT(0, "Large Comp Data Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_LCD_SRV */ +#if CONFIG_BLE_MESH_RPR_CLI + case BLE_MESH_MODEL_ID_RPR_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_rpr_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_rpr_cli_cb; + bt_mesh_rpr_client_t *cli = model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_rpr_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_RPR_CLI: + __ASSERT(0, "Remote Provisioning Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +#if CONFIG_BLE_MESH_RPR_SRV + case BLE_MESH_MODEL_ID_RPR_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_rpr_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_rpr_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_RPR_SRV: + __ASSERT(0, "Remote Provisioning Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +#if CONFIG_BLE_MESH_DF_CLI + case BLE_MESH_MODEL_ID_DF_CLI: { + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_df_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_df_cli_cb; + bt_mesh_df_client_t *cli = (bt_mesh_df_client_t *)model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_df_client_recv_pub_cb; + } + break; + } +#else + case BLE_MESH_MODEL_ID_DF_CLI: + __ASSERT(0, "Directed Forwarding Client model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_DF_CLI */ +#if CONFIG_BLE_MESH_DF_SRV + case BLE_MESH_MODEL_ID_DF_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_df_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_df_srv_cb; + break; +#else + case BLE_MESH_MODEL_ID_DF_SRV: + __ASSERT(0, "Directed Forwarding Server model is not enabled"); + break; +#endif /* CONFIG_BLE_MESH_DF_SRV */ #if CONFIG_BLE_MESH_GENERIC_CLIENT case BLE_MESH_MODEL_ID_GEN_ONOFF_CLI: { model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_onoff_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_onoff_client_t *cli = (bt_mesh_gen_onoff_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1316,7 +1694,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_level_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_level_client_t *cli = (bt_mesh_gen_level_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1325,7 +1703,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_def_trans_time_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_def_trans_time_client_t *cli = (bt_mesh_gen_def_trans_time_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1334,7 +1712,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_onoff_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_power_onoff_client_t *cli = (bt_mesh_gen_power_onoff_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1343,7 +1721,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_level_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_power_level_client_t *cli = (bt_mesh_gen_power_level_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1352,7 +1730,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_battery_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_battery_client_t *cli = (bt_mesh_gen_battery_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1361,7 +1739,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_location_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_location_client_t *cli = (bt_mesh_gen_location_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; @@ -1370,18 +1748,29 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_property_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_generic_client_cb; bt_mesh_gen_property_client_t *cli = (bt_mesh_gen_property_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_generic_client_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_GEN_ONOFF_CLI: + case BLE_MESH_MODEL_ID_GEN_LEVEL_CLI: + case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI: + case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI: + case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI: + case BLE_MESH_MODEL_ID_GEN_BATTERY_CLI: + case BLE_MESH_MODEL_ID_GEN_LOCATION_CLI: + case BLE_MESH_MODEL_ID_GEN_PROP_CLI: + __ASSERT(0, "Generic Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */ #if CONFIG_BLE_MESH_LIGHTING_CLIENT case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI: { model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lightness_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lighting_client_cb; bt_mesh_light_lightness_client_t *cli = (bt_mesh_light_lightness_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_lighting_client_publish_callback; } break; @@ -1390,7 +1779,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_ctl_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lighting_client_cb; bt_mesh_light_ctl_client_t *cli = (bt_mesh_light_ctl_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_lighting_client_publish_callback; } break; @@ -1399,7 +1788,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_hsl_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lighting_client_cb; bt_mesh_light_hsl_client_t *cli = (bt_mesh_light_hsl_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_lighting_client_publish_callback; } break; @@ -1408,7 +1797,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_xyl_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lighting_client_cb; bt_mesh_light_xyl_client_t *cli = (bt_mesh_light_xyl_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_lighting_client_publish_callback; } break; @@ -1417,29 +1806,41 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lc_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_lighting_client_cb; bt_mesh_light_lc_client_t *cli = (bt_mesh_light_lc_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_lighting_client_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI: + case BLE_MESH_MODEL_ID_LIGHT_CTL_CLI: + case BLE_MESH_MODEL_ID_LIGHT_HSL_CLI: + case BLE_MESH_MODEL_ID_LIGHT_XYL_CLI: + case BLE_MESH_MODEL_ID_LIGHT_LC_CLI: + __ASSERT(0, "Lighting Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */ #if CONFIG_BLE_MESH_SENSOR_CLI case BLE_MESH_MODEL_ID_SENSOR_CLI: { model->op = (esp_ble_mesh_model_op_t *)bt_mesh_sensor_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_sensor_client_cb; bt_mesh_sensor_client_t *cli = (bt_mesh_sensor_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_sensor_client_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_SENSOR_CLI: + __ASSERT(0, "Sensor Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_SENSOR_CLI */ #if CONFIG_BLE_MESH_TIME_SCENE_CLIENT case BLE_MESH_MODEL_ID_TIME_CLI: { model->op = (esp_ble_mesh_model_op_t *)bt_mesh_time_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_time_scene_client_cb; bt_mesh_time_client_t *cli = (bt_mesh_time_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_time_scene_client_publish_callback; } break; @@ -1448,7 +1849,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scene_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_time_scene_client_cb; bt_mesh_scene_client_t *cli = (bt_mesh_scene_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_time_scene_client_publish_callback; } break; @@ -1457,11 +1858,17 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scheduler_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_time_scene_client_cb; bt_mesh_scheduler_client_t *cli = (bt_mesh_scheduler_client_t *)model->user_data; - if (cli != NULL) { + if (cli) { cli->publish_status = btc_ble_mesh_time_scene_client_publish_callback; } break; } +#else + case BLE_MESH_MODEL_ID_TIME_CLI: + case BLE_MESH_MODEL_ID_SCENE_CLI: + case BLE_MESH_MODEL_ID_SCHEDULER_CLI: + __ASSERT(0, "Time Scene Client model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */ #if CONFIG_BLE_MESH_GENERIC_SERVER case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: @@ -1562,6 +1969,23 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; } break; +#else + case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: + case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV: + case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV: + case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: + case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: + case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: + case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV: + case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV: + case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV: + case BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV: + case BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV: + case BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV: + case BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV: + case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV: + __ASSERT(0, "Generic Server model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_GENERIC_SERVER */ #if CONFIG_BLE_MESH_LIGHTING_SERVER case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV: @@ -1655,6 +2079,22 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; } break; +#else + case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV: + case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV: + case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV: + case BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV: + case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV: + case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV: + case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV: + case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV: + case BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV: + case BLE_MESH_MODEL_ID_LIGHT_XYL_SRV: + case BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV: + case BLE_MESH_MODEL_ID_LIGHT_LC_SRV: + case BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV: + __ASSERT(0, "Lighting Server model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */ #if CONFIG_BLE_MESH_TIME_SCENE_SERVER case BLE_MESH_MODEL_ID_TIME_SRV: @@ -1701,6 +2141,15 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; } break; +#else + case BLE_MESH_MODEL_ID_TIME_SRV: + case BLE_MESH_MODEL_ID_TIME_SETUP_SRV: + case BLE_MESH_MODEL_ID_SCENE_SRV: + case BLE_MESH_MODEL_ID_SCENE_SETUP_SRV: + case BLE_MESH_MODEL_ID_SCHEDULER_SRV: + case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV: + __ASSERT(0, "Time Scene Server model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */ #if CONFIG_BLE_MESH_SENSOR_SERVER case BLE_MESH_MODEL_ID_SENSOR_SRV: @@ -1717,7 +2166,31 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; } break; +#else + case BLE_MESH_MODEL_ID_SENSOR_SRV: + case BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV: + __ASSERT(0, "Sensor Server model is not enabled"); + break; #endif /* CONFIG_BLE_MESH_SENSOR_SERVER */ +#if CONFIG_BLE_MESH_MBT_CLI + case BLE_MESH_MODEL_ID_MBT_CLI: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_mbt_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_mbt_cli_cb; + bt_mesh_mbt_client_t *cli = (bt_mesh_mbt_client_t *)model->user_data; + if (cli) { + cli->publish_status = btc_ble_mesh_mbt_client_publish_callback; + } + break; +#endif /* CONFIG_BLE_MESH_MBT_CLI */ +#if CONFIG_BLE_MESH_MBT_SRV + case BLE_MESH_MODEL_ID_MBT_SRV: + model->op = (esp_ble_mesh_model_op_t *)bt_mesh_mbt_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_mbt_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_MBT_SRV */ default: goto set_vnd_op; } @@ -1728,11 +2201,10 @@ set_vnd_op: model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; } esp_ble_mesh_model_op_t *op = model->op; - while (op != NULL && op->opcode != 0) { + while (op && op->opcode != 0) { op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_server_model_op_cb; op++; } - return; } void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) @@ -1791,6 +2263,11 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) arg->mesh_init.prov->provisioner_link_close = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_link_close_cb; arg->mesh_init.prov->provisioner_prov_comp = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_prov_complete_cb; bt_mesh_provisioner_adv_pkt_cb_register(btc_ble_mesh_provisioner_recv_unprov_adv_pkt_cb); +#if CONFIG_BLE_MESH_CERT_BASED_PROV + arg->mesh_init.prov->cert_based_prov_start = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_cert_based_prov_start_cb; + arg->mesh_init.prov->records_list_get = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_records_list_get_cb; + arg->mesh_init.prov->prov_record_recv_comp = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_record_recv_comp_cb; +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ #endif /* CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_LOW_POWER bt_mesh_lpn_set_cb(btc_ble_mesh_lpn_cb); @@ -1872,12 +2349,12 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) break; #endif /* CONFIG_BLE_MESH_NODE */ #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER case BTC_BLE_MESH_ACT_SET_DEVICE_NAME: act = ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT; param.node_set_unprov_dev_name_comp.err_code = bt_mesh_set_device_name(arg->set_device_name.name); break; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER case BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE: act = ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT; param.node_proxy_identity_enable_comp.err_code = bt_mesh_proxy_identity_enable(); @@ -2145,6 +2622,44 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) ¶m.provisioner_delete_settings_with_uid_comp.index); break; #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ +#if CONFIG_BLE_MESH_CERT_BASED_PROV + extern int bt_mesh_provisioner_send_prov_records_get(uint16_t link_idx); + extern int bt_mesh_provisioner_send_prov_record_req(uint16_t link_idx, uint16_t record_id, + uint16_t frag_offset, uint16_t max_size); + extern int bt_mesh_provisioner_send_prov_invite(uint16_t link_idx); + extern int bt_mesh_provisioner_send_link_close(uint16_t link_idx); + + case BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_RECORDS_GET: + act = ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORDS_GET_EVT; + param.provisioner_send_records_get.link_idx = arg->send_prov_records_get.link_idx; + param.provisioner_send_records_get.err_code = + bt_mesh_provisioner_send_prov_records_get(arg->send_prov_records_get.link_idx); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_RECORD_REQUEST: + act = ESP_BLE_MESH_PROVISIONER_SEND_PROV_RECORD_REQUEST_EVT; + param.provisioner_send_record_req.link_idx = arg->send_prov_record_req.link_idx; + param.provisioner_send_record_req.record_id = arg->send_prov_record_req.record_id; + param.provisioner_send_record_req.frag_offset = arg->send_prov_record_req.frag_offset; + param.provisioner_send_record_req.max_size = arg->send_prov_record_req.max_size; + param.provisioner_send_record_req.err_code = + bt_mesh_provisioner_send_prov_record_req(arg->send_prov_record_req.link_idx, + arg->send_prov_record_req.record_id, + arg->send_prov_record_req.frag_offset, + arg->send_prov_record_req.max_size); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_INVITE: + act = ESP_BLE_MESH_PROVISIONER_SEND_PROV_INVITE_EVT; + param.provisioner_send_prov_invite.link_idx = arg->send_prov_invite.link_idx; + param.provisioner_send_prov_invite.err_code = + bt_mesh_provisioner_send_prov_invite(arg->send_prov_invite.link_idx); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SEND_LINK_CLOSE: + act = ESP_BLE_MESH_PROVISIONER_SEND_LINK_CLOSE_EVT; + param.provisioner_send_link_close.link_idx = arg->send_link_close.link_idx; + param.provisioner_send_link_close.err_code = + bt_mesh_provisioner_send_link_close(arg->send_link_close.link_idx); + break; +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ #endif /* CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_FAST_PROV case BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO: @@ -2154,8 +2669,6 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) arg->set_fast_prov_info.unicast_max); param.set_fast_prov_info_comp.status_net_idx = bt_mesh_set_fast_prov_net_idx(arg->set_fast_prov_info.net_idx); - bt_mesh_set_fast_prov_flags_iv_index(arg->set_fast_prov_info.flags, - arg->set_fast_prov_info.iv_index); param.set_fast_prov_info_comp.status_match = bt_mesh_provisioner_set_dev_uuid_match(arg->set_fast_prov_info.offset, arg->set_fast_prov_info.match_len, @@ -2239,6 +2752,39 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) arg->proxy_client_remove_filter_addr.net_idx, &pdu); break; } +#if CONFIG_BLE_MESH_DF_CLI + case BTC_BLE_MESH_ACT_PROXY_CLIENT_DIRECTED_PROXY_SET: { + uint8_t elem_cnt = bt_mesh_elem_count(); + struct bt_mesh_proxy_cfg_pdu pdu = { + .opcode = BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL, + .direct_proxy_ctrl.use_directed = arg->proxy_client_directed_proxy_set.use_directed, + }; + if (pdu.direct_proxy_ctrl.use_directed) { + pdu.direct_proxy_ctrl.proxy_client_uar.len_present = (elem_cnt >= 2); + pdu.direct_proxy_ctrl.proxy_client_uar.range_start = bt_mesh_primary_addr(); + pdu.direct_proxy_ctrl.proxy_client_uar.range_length = (elem_cnt >= 2 ? elem_cnt : 0); + } + act = ESP_BLE_MESH_PROXY_CLIENT_DIRECTED_PROXY_SET_COMP_EVT; + param.proxy_client_directed_proxy_set_comp.conn_handle = arg->proxy_client_directed_proxy_set.conn_handle; + param.proxy_client_directed_proxy_set_comp.net_idx = arg->proxy_client_directed_proxy_set.net_idx; + param.proxy_client_directed_proxy_set_comp.err_code = + bt_mesh_proxy_client_cfg_send(arg->proxy_client_directed_proxy_set.conn_handle, + arg->proxy_client_directed_proxy_set.net_idx, &pdu); + break; + } +#endif +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + case BTC_BLE_MESH_ACT_PROXY_CLIENT_SEND_SOLIC_PDU: + act = ESP_BLE_MESH_PROXY_CLIENT_SEND_SOLIC_PDU_COMP_EVT; + param.proxy_client_send_solic_pdu_comp.net_idx = arg->proxy_client_send_solic_pdu.net_idx; + param.proxy_client_send_solic_pdu_comp.ssrc = arg->proxy_client_send_solic_pdu.ssrc; + param.proxy_client_send_solic_pdu_comp.dst = arg->proxy_client_send_solic_pdu.dst; + param.proxy_client_send_solic_pdu_comp.err_code = + bt_mesh_proxy_client_solic_send(arg->proxy_client_send_solic_pdu.net_idx, + arg->proxy_client_send_solic_pdu.ssrc, + arg->proxy_client_send_solic_pdu.dst); + break; +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ case BTC_BLE_MESH_ACT_MODEL_SUBSCRIBE_GROUP_ADDR: act = ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT; @@ -2279,7 +2825,6 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) btc_ble_mesh_prov_set_complete_cb(¶m, act); btc_ble_mesh_prov_arg_deep_free(msg); - return; } void btc_ble_mesh_prov_cb_handler(btc_msg_t *msg) @@ -2298,6 +2843,8 @@ void btc_ble_mesh_prov_cb_handler(btc_msg_t *msg) } else { BT_ERR("%s, Unknown act %d", __func__, msg->act); } + + btc_ble_mesh_prov_free_req_data(msg); } void btc_ble_mesh_model_call_handler(btc_msg_t *msg) @@ -2314,16 +2861,6 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg) switch (msg->act) { case BTC_BLE_MESH_ACT_MODEL_PUBLISH: { - if (arg->model_publish.device_role == PROVISIONER) { - /* Currently Provisioner only supports client model */ - err = bt_mesh_set_client_model_role((struct bt_mesh_model *)arg->model_publish.model, - arg->model_publish.device_role); - if (err) { - BT_ERR("Failed to set client role"); - btc_ble_mesh_model_publish_comp_cb(arg->model_publish.model, err); - break; - } - } err = bt_mesh_model_publish((struct bt_mesh_model *)arg->model_publish.model); btc_ble_mesh_model_publish_comp_cb(arg->model_publish.model, err); break; @@ -2339,7 +2876,6 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg) } net_buf_simple_add_mem(buf, arg->model_send.data, arg->model_send.length); - arg->model_send.ctx->srv_send = true; err = bt_mesh_model_send((struct bt_mesh_model *)arg->model_send.model, (struct bt_mesh_msg_ctx *)arg->model_send.ctx, @@ -2361,16 +2897,16 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg) net_buf_simple_add_mem(buf, arg->model_send.data, arg->model_send.length); bt_mesh_client_common_param_t param = { - .opcode = arg->model_send.opcode, - .model = (struct bt_mesh_model *)arg->model_send.model, - .ctx.net_idx = arg->model_send.ctx->net_idx, - .ctx.app_idx = arg->model_send.ctx->app_idx, - .ctx.addr = arg->model_send.ctx->addr, - .ctx.send_rel = arg->model_send.ctx->send_rel, - .ctx.send_ttl = arg->model_send.ctx->send_ttl, - .ctx.srv_send = false, - .msg_timeout = arg->model_send.msg_timeout, - .msg_role = arg->model_send.device_role, + .opcode = arg->model_send.opcode, + .model = (struct bt_mesh_model *)arg->model_send.model, + .ctx.net_idx = arg->model_send.ctx->net_idx, + .ctx.app_idx = arg->model_send.ctx->app_idx, + .ctx.addr = arg->model_send.ctx->addr, + .ctx.send_szmic = arg->model_send.ctx->send_szmic, + .ctx.send_ttl = arg->model_send.ctx->send_ttl, + .ctx.send_cred = arg->model_send.ctx->send_cred, + .ctx.send_tag = arg->model_send.ctx->send_tag, + .msg_timeout = arg->model_send.msg_timeout, }; err = bt_mesh_client_send_msg(¶m, buf, arg->model_send.need_rsp, btc_ble_mesh_client_model_timeout_cb); @@ -2394,7 +2930,6 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg) } btc_ble_mesh_model_arg_deep_free(msg); - return; } void btc_ble_mesh_model_cb_handler(btc_msg_t *msg) @@ -2415,5 +2950,4 @@ void btc_ble_mesh_model_cb_handler(btc_msg_t *msg) } btc_ble_mesh_model_free_req_data(msg); - return; } diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c index ae32c6586a..0a29fe9049 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c @@ -7,6 +7,7 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_sensor_model.h" #include "esp_ble_mesh_sensor_model_api.h" @@ -439,8 +440,6 @@ static void btc_ble_mesh_sensor_client_callback(esp_ble_mesh_sensor_client_cb_pa { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_SENSOR_CLIENT)) { return; @@ -463,7 +462,7 @@ void bt_mesh_sensor_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -501,14 +500,14 @@ void bt_mesh_sensor_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_sensor_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_sensor_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_sensor_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -519,15 +518,13 @@ void btc_ble_mesh_sensor_client_publish_callback(uint32_t opcode, struct bt_mesh bt_mesh_sensor_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_SENSOR_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } void btc_ble_mesh_sensor_client_call_handler(btc_msg_t *msg) { - esp_ble_mesh_client_common_param_t *params = NULL; - btc_ble_mesh_sensor_client_args_t *arg = NULL; esp_ble_mesh_sensor_client_cb_param_t cb = {0}; - bt_mesh_client_common_param_t common = {0}; + btc_ble_mesh_sensor_client_args_t *arg = NULL; + bt_mesh_client_common_param_t param = {0}; if (!msg) { BT_ERR("%s, Invalid parameter", __func__); @@ -537,52 +534,31 @@ void btc_ble_mesh_sensor_client_call_handler(btc_msg_t *msg) arg = (btc_ble_mesh_sensor_client_args_t *)(msg->arg); switch (msg->act) { - case BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE: { - params = arg->sensor_client_get_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_GET_STATE: + btc_ble_mesh_set_client_common_param(arg->sensor_client_get_state.params, ¶m, false); cb.params = arg->sensor_client_get_state.params; - cb.error_code = bt_mesh_sensor_client_get_state(&common, arg->sensor_client_get_state.get_state); + cb.error_code = bt_mesh_sensor_client_get_state(¶m, arg->sensor_client_get_state.get_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_sensor_client_callback(&cb, ESP_BLE_MESH_SENSOR_CLIENT_GET_STATE_EVT); } break; - } - case BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE: { - params = arg->sensor_client_set_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_SENSOR_CLIENT_SET_STATE: + btc_ble_mesh_set_client_common_param(arg->sensor_client_set_state.params, ¶m, false); cb.params = arg->sensor_client_set_state.params; - cb.error_code = bt_mesh_sensor_client_set_state(&common, arg->sensor_client_set_state.set_state); + cb.error_code = bt_mesh_sensor_client_set_state(¶m, arg->sensor_client_set_state.set_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_sensor_client_callback(&cb, ESP_BLE_MESH_SENSOR_CLIENT_SET_STATE_EVT); } break; - } default: break; } btc_ble_mesh_sensor_client_arg_deep_free(msg); - return; } void btc_ble_mesh_sensor_client_cb_handler(btc_msg_t *msg) @@ -603,7 +579,6 @@ void btc_ble_mesh_sensor_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_sensor_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_SENSOR_CLI */ @@ -771,7 +746,7 @@ static void btc_ble_mesh_sensor_server_free_req_data(btc_msg_t *msg) switch (msg->act) { case ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT: if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET || - arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) { + arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) { bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.trigger_delta_down); bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.trigger_delta_up); bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.fast_cadence_low); @@ -790,7 +765,7 @@ static void btc_ble_mesh_sensor_server_free_req_data(btc_msg_t *msg) break; case ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT: if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET || - arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) { + arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) { bt_mesh_free_buf(arg->value.set.sensor_cadence.cadence); } else if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET || arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK) { @@ -806,8 +781,6 @@ static void btc_ble_mesh_sensor_server_callback(esp_ble_mesh_sensor_server_cb_pa { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_SENSOR_SERVER)) { return; @@ -821,14 +794,15 @@ static void btc_ble_mesh_sensor_server_callback(esp_ble_mesh_sensor_server_cb_pa btc_ble_mesh_sensor_server_copy_req_data, btc_ble_mesh_sensor_server_free_req_data); } -void bt_mesh_sensor_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_sensor_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len) { esp_ble_mesh_sensor_server_cb_param_t cb_params = {0}; uint8_t act = 0U; - if (model == NULL || ctx == NULL) { + if (model == NULL || ctx == NULL || len > sizeof(cb_params.value)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -859,11 +833,10 @@ void bt_mesh_sensor_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model cb_params.ctx.send_ttl = ctx->send_ttl; if (val && len) { - memcpy(&cb_params.value, val, MIN(len, sizeof(cb_params.value))); + memcpy(&cb_params.value, val, len); } btc_ble_mesh_sensor_server_callback(&cb_params, act); - return; } void btc_ble_mesh_sensor_server_cb_handler(btc_msg_t *msg) @@ -884,7 +857,6 @@ void btc_ble_mesh_sensor_server_cb_handler(btc_msg_t *msg) } btc_ble_mesh_sensor_server_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_SENSOR_SERVER */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c index 977a42836f..a8556a9023 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c @@ -7,6 +7,7 @@ #include #include +#include "btc_ble_mesh_model_common.h" #include "btc_ble_mesh_time_scene_model.h" #include "esp_ble_mesh_time_scene_model_api.h" @@ -79,7 +80,7 @@ void btc_ble_mesh_time_scene_client_arg_deep_free(btc_msg_t *msg) { btc_ble_mesh_time_scene_client_args_t *arg = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -166,7 +167,7 @@ static void btc_ble_mesh_time_scene_client_free_req_data(btc_msg_t *msg) { esp_ble_mesh_time_scene_client_cb_param_t *arg = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -203,8 +204,6 @@ static void btc_ble_mesh_time_scene_client_callback(esp_ble_mesh_time_scene_clie { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_TIME_SCENE_CLIENT)) { return; @@ -227,7 +226,7 @@ void bt_mesh_time_scene_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, esp_ble_mesh_client_common_param_t params = {0}; uint8_t act = 0U; - if (!model || !ctx) { + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -265,14 +264,14 @@ void bt_mesh_time_scene_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, cb_params.params = ¶ms; if (val && len) { - memcpy(&cb_params.status_cb, val, MIN(len, sizeof(cb_params.status_cb))); + memcpy(&cb_params.status_cb, val, len); } btc_ble_mesh_time_scene_client_callback(&cb_params, act); - return; } -void btc_ble_mesh_time_scene_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_time_scene_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -283,17 +282,15 @@ void btc_ble_mesh_time_scene_client_publish_callback(uint32_t opcode, struct bt_ bt_mesh_time_scene_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_PUBLISH, model, ctx, buf->data, buf->len); - return; } void btc_ble_mesh_time_scene_client_call_handler(btc_msg_t *msg) { - btc_ble_mesh_time_scene_client_args_t *arg = NULL; - esp_ble_mesh_client_common_param_t *params = NULL; esp_ble_mesh_time_scene_client_cb_param_t cb = {0}; - bt_mesh_client_common_param_t common = {0}; + btc_ble_mesh_time_scene_client_args_t *arg = NULL; + bt_mesh_client_common_param_t param = {0}; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -301,59 +298,38 @@ void btc_ble_mesh_time_scene_client_call_handler(btc_msg_t *msg) arg = (btc_ble_mesh_time_scene_client_args_t *)(msg->arg); switch (msg->act) { - case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE: { - params = arg->time_scene_client_get_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_GET_STATE: + btc_ble_mesh_set_client_common_param(arg->time_scene_client_get_state.params, ¶m, false); cb.params = arg->time_scene_client_get_state.params; - cb.error_code = bt_mesh_time_scene_client_get_state(&common, arg->time_scene_client_get_state.get_state); + cb.error_code = bt_mesh_time_scene_client_get_state(¶m, arg->time_scene_client_get_state.get_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_time_scene_client_callback(&cb, ESP_BLE_MESH_TIME_SCENE_CLIENT_GET_STATE_EVT); } break; - } - case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE: { - params = arg->time_scene_client_set_state.params; - common.opcode = params->opcode; - common.model = (struct bt_mesh_model *)params->model; - common.ctx.net_idx = params->ctx.net_idx; - common.ctx.app_idx = params->ctx.app_idx; - common.ctx.addr = params->ctx.addr; - common.ctx.send_rel = params->ctx.send_rel; - common.ctx.send_ttl = params->ctx.send_ttl; - common.msg_timeout = params->msg_timeout; - common.msg_role = params->msg_role; + case BTC_BLE_MESH_ACT_TIME_SCENE_CLIENT_SET_STATE: + btc_ble_mesh_set_client_common_param(arg->time_scene_client_set_state.params, ¶m, false); cb.params = arg->time_scene_client_set_state.params; - cb.error_code = bt_mesh_time_scene_client_set_state(&common, arg->time_scene_client_set_state.set_state); + cb.error_code = bt_mesh_time_scene_client_set_state(¶m, arg->time_scene_client_set_state.set_state); if (cb.error_code) { /* If send failed, callback error_code to app layer immediately */ btc_ble_mesh_time_scene_client_callback(&cb, ESP_BLE_MESH_TIME_SCENE_CLIENT_SET_STATE_EVT); } break; - } default: break; } btc_ble_mesh_time_scene_client_arg_deep_free(msg); - return; } void btc_ble_mesh_time_scene_client_cb_handler(btc_msg_t *msg) { esp_ble_mesh_time_scene_client_cb_param_t *param = NULL; - if (!msg || !msg->arg) { + if (!msg) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -367,7 +343,6 @@ void btc_ble_mesh_time_scene_client_cb_handler(btc_msg_t *msg) } btc_ble_mesh_time_scene_client_free_req_data(msg); - return; } #endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */ @@ -390,8 +365,6 @@ static void btc_ble_mesh_time_scene_server_callback(esp_ble_mesh_time_scene_serv { btc_msg_t msg = {0}; - BT_DBG("%s", __func__); - /* If corresponding callback is not registered, event will not be posted. */ if (!btc_profile_cb_get(BTC_PID_TIME_SCENE_SERVER)) { return; @@ -404,14 +377,15 @@ static void btc_ble_mesh_time_scene_server_callback(esp_ble_mesh_time_scene_serv btc_transfer_context(&msg, cb_params, cb_params == NULL ? 0 : sizeof(esp_ble_mesh_time_scene_server_cb_param_t), NULL, NULL); } -void bt_mesh_time_scene_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_time_scene_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len) { esp_ble_mesh_time_scene_server_cb_param_t cb_params = {0}; uint8_t act = 0U; - if (model == NULL || ctx == NULL) { + if (model == NULL || ctx == NULL || len > sizeof(cb_params.value)) { BT_ERR("%s, Invalid parameter", __func__); return; } @@ -445,11 +419,10 @@ void bt_mesh_time_scene_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_mo cb_params.ctx.send_ttl = ctx->send_ttl; if (val && len) { - memcpy(&cb_params.value, val, MIN(len, sizeof(cb_params.value))); + memcpy(&cb_params.value, val, len); } btc_ble_mesh_time_scene_server_callback(&cb_params, act); - return; } void btc_ble_mesh_time_scene_server_cb_handler(btc_msg_t *msg) @@ -468,8 +441,6 @@ void btc_ble_mesh_time_scene_server_cb_handler(btc_msg_t *msg) } else { BT_ERR("%s, Unknown act %d", __func__, msg->act); } - - return; } #endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */ diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h index ce81b6c261..9b8e6fd3b8 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h @@ -47,7 +47,8 @@ void btc_ble_mesh_config_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void void btc_ble_mesh_config_client_arg_deep_free(btc_msg_t *msg); -void btc_ble_mesh_config_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_config_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -63,7 +64,8 @@ typedef enum { BTC_BLE_MESH_EVT_CONFIG_SERVER_MAX, } btc_ble_mesh_config_server_evt_t; -void bt_mesh_config_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_config_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h index d06785094d..e7c98a23ad 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h @@ -47,7 +47,8 @@ void btc_ble_mesh_generic_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, voi void btc_ble_mesh_generic_client_arg_deep_free(btc_msg_t *msg); -void btc_ble_mesh_generic_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_generic_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -63,7 +64,8 @@ typedef enum { BTC_BLE_MESH_EVT_GENERIC_SERVER_MAX, } btc_ble_mesh_generic_server_evt_t; -void bt_mesh_generic_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_generic_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h index a04745485b..46da456827 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h @@ -47,7 +47,8 @@ void btc_ble_mesh_health_client_call_handler(btc_msg_t *msg); void btc_ble_mesh_health_client_cb_handler(btc_msg_t *msg); -void btc_ble_mesh_health_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_health_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h index 45ca7ee14b..3ec2cd7ded 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h @@ -47,7 +47,8 @@ void btc_ble_mesh_lighting_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, vo void btc_ble_mesh_lighting_client_arg_deep_free(btc_msg_t *msg); -void btc_ble_mesh_lighting_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_lighting_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -64,7 +65,8 @@ typedef enum { BTC_BLE_MESH_EVT_LIGHTING_SERVER_MAX, } btc_ble_mesh_lighting_server_evt_t; -void bt_mesh_lighting_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_lighting_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h new file mode 100644 index 0000000000..8c1f1d37b9 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_MODEL_COMMON_H_ +#define _BTC_BLE_MESH_MODEL_COMMON_H_ + +#include "btc/btc_manage.h" + +#include "mesh/access.h" +#include "mesh/client_common.h" +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void btc_ble_mesh_set_client_common_param(esp_ble_mesh_client_common_param_t *input, + bt_mesh_client_common_param_t *output, + bool use_dev_key) +{ + if (input && output) { + output->opcode = input->opcode; + output->model = (struct bt_mesh_model *)input->model; + output->ctx.net_idx = input->ctx.net_idx; + output->ctx.app_idx = use_dev_key ? BLE_MESH_KEY_DEV : input->ctx.app_idx; + output->ctx.addr = input->ctx.addr; + output->ctx.send_szmic = input->ctx.send_szmic; + output->ctx.send_ttl = input->ctx.send_ttl; + output->ctx.send_cred = input->ctx.send_cred; + output->ctx.send_tag = input->ctx.send_tag; + output->msg_timeout = input->msg_timeout; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_MODEL_COMMON_H_ */ 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 e09a454a1f..efdae7f337 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 @@ -12,7 +12,6 @@ #include "mesh/config.h" #include "mesh/main.h" #include "fast_prov.h" -#include "prov_pvnr.h" #include "esp_ble_mesh_defs.h" #ifdef __cplusplus @@ -65,6 +64,10 @@ typedef enum { BTC_BLE_MESH_ACT_PROVISIONER_CLOSE_SETTINGS_WITH_UID, BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_INDEX, BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_UID, + BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_RECORDS_GET, + BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_RECORD_REQUEST, + BTC_BLE_MESH_ACT_PROVISIONER_SEND_PROV_INVITE, + BTC_BLE_MESH_ACT_PROVISIONER_SEND_LINK_CLOSE, BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO, BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION, BTC_BLE_MESH_ACT_LPN_ENABLE, @@ -75,6 +78,8 @@ typedef enum { BTC_BLE_MESH_ACT_PROXY_CLIENT_SET_FILTER_TYPE, BTC_BLE_MESH_ACT_PROXY_CLIENT_ADD_FILTER_ADDR, BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR, + BTC_BLE_MESH_ACT_PROXY_CLIENT_DIRECTED_PROXY_SET, + BTC_BLE_MESH_ACT_PROXY_CLIENT_SEND_SOLIC_PDU, BTC_BLE_MESH_ACT_MODEL_SUBSCRIBE_GROUP_ADDR, BTC_BLE_MESH_ACT_MODEL_UNSUBSCRIBE_GROUP_ADDR, BTC_BLE_MESH_ACT_DEINIT_MESH, @@ -248,6 +253,21 @@ typedef union { struct { char uid[ESP_BLE_MESH_SETTINGS_UID_SIZE + 1]; } delete_settings_with_uid; + struct { + uint16_t link_idx; + } send_prov_records_get; + struct { + uint16_t link_idx; + uint16_t record_id; + uint16_t frag_offset; + uint16_t max_size; + } send_prov_record_req; + struct { + uint16_t link_idx; + } send_prov_invite; + struct { + uint16_t link_idx; + } send_link_close; struct ble_mesh_set_fast_prov_info_args { uint16_t unicast_min; uint16_t unicast_max; @@ -295,6 +315,16 @@ typedef union { uint16_t addr_num; uint16_t *addr; } proxy_client_remove_filter_addr; + struct ble_mesh_proxy_client_directed_proxy_set_args { + uint8_t conn_handle; + uint16_t net_idx; + uint8_t use_directed; + } proxy_client_directed_proxy_set; + struct { + uint16_t net_idx; + uint16_t ssrc; + uint16_t dst; + } proxy_client_send_solic_pdu; struct ble_mesh_model_sub_group_addr_args { uint16_t element_addr; uint16_t company_id; @@ -315,7 +345,7 @@ typedef union { typedef union { struct ble_mesh_model_publish_args { esp_ble_mesh_model_t *model; - uint8_t device_role; + uint8_t device_role __attribute__((deprecated)); } model_publish; struct ble_mesh_model_send_args { esp_ble_mesh_model_t *model; @@ -324,7 +354,7 @@ typedef union { bool need_rsp; uint16_t length; uint8_t *data; - uint8_t device_role; + uint8_t device_role __attribute__((deprecated)); int32_t msg_timeout; } model_send; struct ble_mesh_server_model_update_state_args { @@ -389,6 +419,11 @@ void btc_ble_mesh_model_cb_handler(btc_msg_t *msg); void btc_ble_mesh_prov_call_handler(btc_msg_t *msg); void btc_ble_mesh_prov_cb_handler(btc_msg_t *msg); +#if CONFIG_BLE_MESH_DF_SRV +int btc_ble_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay); +#endif + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h index 3d216c7fa9..bc4a3ca427 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h @@ -47,7 +47,8 @@ void btc_ble_mesh_sensor_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void void btc_ble_mesh_sensor_client_arg_deep_free(btc_msg_t *msg); -void btc_ble_mesh_sensor_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_sensor_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -63,7 +64,8 @@ typedef enum { BTC_BLE_MESH_EVT_SENSOR_SERVER_MAX, } btc_ble_mesh_sensor_server_evt_t; -void bt_mesh_sensor_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_sensor_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len); diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h index 6c878dc776..e18c60df3e 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h @@ -45,7 +45,10 @@ void btc_ble_mesh_time_scene_client_cb_handler(btc_msg_t *msg); void btc_ble_mesh_time_scene_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); -void btc_ble_mesh_time_scene_client_publish_callback(uint32_t opcode, struct bt_mesh_model *model, +void btc_ble_mesh_time_scene_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_time_scene_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -62,7 +65,8 @@ typedef enum { BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_MAX, } btc_ble_mesh_time_scene_server_evt_t; -void bt_mesh_time_scene_server_cb_evt_to_btc(uint8_t evt_type, struct bt_mesh_model *model, +void bt_mesh_time_scene_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const uint8_t *val, size_t len); diff --git a/components/bt/esp_ble_mesh/common/buf.c b/components/bt/esp_ble_mesh/common/buf.c index cc240e07c5..f1c9559dd0 100644 --- a/components/bt/esp_ble_mesh/common/buf.c +++ b/components/bt/esp_ble_mesh/common/buf.c @@ -281,7 +281,7 @@ uint32_t net_buf_simple_pull_le24(struct net_buf_simple *buf) { struct uint24 { uint32_t u24:24; - } __packed val; + } __attribute__((packed)) val; val = UNALIGNED_GET((struct uint24 *)buf->data); net_buf_simple_pull(buf, sizeof(val)); @@ -293,7 +293,7 @@ uint32_t net_buf_simple_pull_be24(struct net_buf_simple *buf) { struct uint24 { uint32_t u24:24; - } __packed val; + } __attribute__((packed)) val; val = UNALIGNED_GET((struct uint24 *)buf->data); net_buf_simple_pull(buf, sizeof(val)); @@ -325,7 +325,7 @@ uint64_t net_buf_simple_pull_le48(struct net_buf_simple *buf) { struct uint48 { uint64_t u48:48; - } __packed val; + } __attribute__((packed)) val; val = UNALIGNED_GET((struct uint48 *)buf->data); net_buf_simple_pull(buf, sizeof(val)); @@ -337,7 +337,7 @@ uint64_t net_buf_simple_pull_be48(struct net_buf_simple *buf) { struct uint48 { uint64_t u48:48; - } __packed val; + } __attribute__((packed)) val; val = UNALIGNED_GET((struct uint48 *)buf->data); net_buf_simple_pull(buf, sizeof(val)); @@ -459,7 +459,7 @@ struct net_buf *net_buf_ref(struct net_buf *buf) return buf; } -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG void net_buf_unref_debug(struct net_buf *buf, const char *func, int line) #else void net_buf_unref(struct net_buf *buf) @@ -471,7 +471,7 @@ void net_buf_unref(struct net_buf *buf) struct net_buf *frags = buf->frags; struct net_buf_pool *pool = NULL; -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG if (!buf->ref) { NET_BUF_ERR("%s():%d: buf %p double free", func, line, buf); @@ -491,7 +491,7 @@ void net_buf_unref(struct net_buf *buf) pool = buf->pool; pool->uninit_count++; -#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) +#if CONFIG_BLE_MESH_NET_BUF_POOL_USAGE pool->avail_count++; NET_BUF_DBG("Unref, pool %p, avail_count %d, uninit_count %d", pool, pool->avail_count, pool->uninit_count); @@ -533,7 +533,7 @@ static uint8_t *data_alloc(struct net_buf *buf, size_t *size, int32_t timeout) return pool->alloc->cb->alloc(buf, size, timeout); } -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG struct net_buf *net_buf_alloc_len_debug(struct net_buf_pool *pool, size_t size, int32_t timeout, const char *func, int line) #else @@ -594,7 +594,7 @@ success: net_buf_reset(buf); pool->uninit_count--; -#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) +#if CONFIG_BLE_MESH_NET_BUF_POOL_USAGE pool->avail_count--; NET_BUF_ASSERT(pool->avail_count >= 0); #endif @@ -602,7 +602,7 @@ success: return buf; } -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, int32_t timeout, const char *func, int line) @@ -656,7 +656,7 @@ struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag) return head; } -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG struct net_buf *net_buf_frag_del_debug(struct net_buf *parent, struct net_buf *frag, const char *func, int line) @@ -678,7 +678,7 @@ struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag) frag->frags = NULL; -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG net_buf_unref_debug(frag, func, line); #else net_buf_unref(frag); diff --git a/components/bt/esp_ble_mesh/common/common.c b/components/bt/esp_ble_mesh/common/common.c index 60696aa565..87f0c6a7bc 100644 --- a/components/bt/esp_ble_mesh/common/common.c +++ b/components/bt/esp_ble_mesh/common/common.c @@ -72,25 +72,6 @@ void bt_mesh_free_buf(struct net_buf_simple *buf) } } -uint8_t bt_mesh_get_device_role(struct bt_mesh_model *model, bool srv_send) -{ - bt_mesh_client_user_data_t *client = NULL; - - if (srv_send) { - BT_DBG("Message is sent by a server model"); - return NODE; - } - - if (!model || !model->user_data) { - BT_ERR("%s, Invalid parameter", __func__); - return ROLE_NVAL; - } - - client = (bt_mesh_client_user_data_t *)model->user_data; - - return client->msg_role; -} - int bt_mesh_rand(void *buf, size_t len) { if (buf == NULL || len == 0) { diff --git a/components/bt/esp_ble_mesh/common/include/mesh/buf.h b/components/bt/esp_ble_mesh/common/include/mesh/buf.h index 4664626a62..5e5538b1d0 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/buf.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/buf.h @@ -816,7 +816,7 @@ struct net_buf_pool { /** Number of uninitialized buffers */ uint16_t uninit_count; -#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) +#if CONFIG_BLE_MESH_NET_BUF_POOL_USAGE /** Amount of available buffers in the pool. */ int16_t avail_count; @@ -837,7 +837,7 @@ struct net_buf_pool { struct net_buf *const __bufs; }; -#if defined(CONFIG_BLE_MESH_NET_BUF_POOL_USAGE) +#if CONFIG_BLE_MESH_NET_BUF_POOL_USAGE #define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _destroy) \ { \ .alloc = _alloc, \ @@ -962,11 +962,11 @@ int net_buf_id(struct net_buf *buf); * * @return New buffer or NULL if out of buffers. */ -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, int32_t timeout, const char *func, int line); #define net_buf_alloc_fixed(_pool, _timeout) \ - net_buf_alloc_fixed_debug(_pool, _timeout, __func__, __LINE__) + net_buf_alloc_fixed_debug(_pool, _timeout, __func__, __LINE__) #else struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, int32_t timeout); #endif @@ -1031,7 +1031,7 @@ struct net_buf *net_buf_slist_get(sys_slist_t *list); * * @param buf A valid pointer on a buffer */ -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG void net_buf_unref_debug(struct net_buf *buf, const char *func, int line); #define net_buf_unref(_buf) \ net_buf_unref_debug(_buf, __func__, __LINE__) @@ -1630,12 +1630,12 @@ struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag); * @return Pointer to the buffer following the fragment, or NULL if it * had no further fragments. */ -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) +#if CONFIG_BLE_MESH_NET_BUF_LOG struct net_buf *net_buf_frag_del_debug(struct net_buf *parent, struct net_buf *frag, const char *func, int line); #define net_buf_frag_del(_parent, _frag) \ - net_buf_frag_del_debug(_parent, _frag, __func__, __LINE__) + net_buf_frag_del_debug(_parent, _frag, __func__, __LINE__) #else struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag); #endif diff --git a/components/bt/esp_ble_mesh/common/include/mesh/byteorder.h b/components/bt/esp_ble_mesh/common/include/mesh/byteorder.h index 85fe44a47c..6926b80475 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/byteorder.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/byteorder.h @@ -335,7 +335,7 @@ static inline void sys_put_le16(uint16_t val, uint8_t dst[2]) * @brief Put a 24-bit integer as little-endian to arbitrary location. * * Put a 24-bit integer, originally in host endianness, to a - * potentially unaligned memory location in littel-endian format. + * potentially unaligned memory location in little-endian format. * * @param val 24-bit integer in host endianness. * @param dst Destination memory address to store the result. diff --git a/components/bt/esp_ble_mesh/common/include/mesh/common.h b/components/bt/esp_ble_mesh/common/include/mesh/common.h index 14f8f78e90..db6c1d372a 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/common.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/common.h @@ -51,20 +51,6 @@ struct net_buf_simple *bt_mesh_alloc_buf(uint16_t size); */ void bt_mesh_free_buf(struct net_buf_simple *buf); -/** - * @brief This function gets device role for stack internal use. - * - * @Note Currently Provisioner only support client models, Node supports - * client models and server models. Hence if srv_send is set to be - * TRUE, then role NODE will be returned. - * - * @param[in] model: Pointer to the model structure - * @param[in] srv_send: Indicate if the message is sent by a server model - * - * @return 0 - Node, 1 - Provisioner - */ -uint8_t bt_mesh_get_device_role(struct bt_mesh_model *model, bool srv_send); - int bt_mesh_rand(void *buf, size_t len); #ifdef __cplusplus diff --git a/components/bt/esp_ble_mesh/common/include/mesh/config.h b/components/bt/esp_ble_mesh/common/include/mesh/config.h index d75a4588c3..ab06eda8f0 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/config.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/config.h @@ -13,6 +13,17 @@ extern "C" { #endif +#ifndef CONFIG_BLE_MESH_PBA_SAME_TIME +#define CONFIG_BLE_MESH_PBA_SAME_TIME 0 +#endif + +#ifndef CONFIG_BLE_MESH_PBG_SAME_TIME +#define CONFIG_BLE_MESH_PBG_SAME_TIME 0 +#endif + +#define CONFIG_BLE_MESH_PRIVATE_BEACON (CONFIG_BLE_MESH_PRB_SRV || \ + CONFIG_BLE_MESH_PRB_CLI) + #define CONFIG_BLE_MESH_GENERIC_CLIENT (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI || \ CONFIG_BLE_MESH_GENERIC_LEVEL_CLI || \ CONFIG_BLE_MESH_GENERIC_DEF_TRANS_TIME_CLI || \ @@ -40,6 +51,9 @@ extern "C" { #define CONFIG_BLE_MESH_BLE_COEX_SUPPORT (CONFIG_BLE_MESH_SUPPORT_BLE_ADV || \ CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) +#define CONFIG_BLE_MESH_PROXY_SOLIC (CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX) + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/common/include/mesh/mutex.h b/components/bt/esp_ble_mesh/common/include/mesh/mutex.h index 0b364a65f7..ee89750029 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/mutex.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/mutex.h @@ -27,6 +27,11 @@ void bt_mesh_mutex_free(bt_mesh_mutex_t *mutex); void bt_mesh_mutex_lock(bt_mesh_mutex_t *mutex); void bt_mesh_mutex_unlock(bt_mesh_mutex_t *mutex); +void bt_mesh_r_mutex_create(bt_mesh_mutex_t *mutex); +void bt_mesh_r_mutex_free(bt_mesh_mutex_t *mutex); +void bt_mesh_r_mutex_lock(bt_mesh_mutex_t *mutex); +void bt_mesh_r_mutex_unlock(bt_mesh_mutex_t *mutex); + void bt_mesh_alarm_lock(void); void bt_mesh_alarm_unlock(void); diff --git a/components/bt/esp_ble_mesh/common/include/mesh/timer.h b/components/bt/esp_ble_mesh/common/include/mesh/timer.h index f29c06fcc5..e1296aa820 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/timer.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/timer.h @@ -50,15 +50,15 @@ struct k_work; typedef void (*k_work_handler_t)(struct k_work *work); struct k_work { - void *_reserved; k_work_handler_t handler; int index; + void *user_data; }; #define _K_WORK_INITIALIZER(work_handler) \ { \ - ._reserved = NULL, \ .handler = work_handler, \ + .user_data = NULL, \ } /** @@ -119,6 +119,18 @@ struct k_work { */ #define K_HOURS(h) K_MINUTES((h) * 60) +/** + * @brief Generate timeout delay from days. + * + * This macro generates a timeout delay that that instructs a kernel API + * to wait up to @a d days to perform the requested operation. + * + * @param d Duration in days. + * + * @return Timeout delay value. + */ +#define K_DAYS(d) K_HOURS((d) * 24) + /** * @brief Generate infinite timeout delay. * diff --git a/components/bt/esp_ble_mesh/common/include/mesh/trace.h b/components/bt/esp_ble_mesh/common/include/mesh/trace.h index 1ff7be41b2..48f604f1c2 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/trace.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/trace.h @@ -92,7 +92,7 @@ extern "C" { #define BT_DBG(fmt, args...) #endif -#if defined(CONFIG_BLE_MESH_NET_BUF_LOG) && (!CONFIG_BLE_MESH_NO_LOG) +#if (CONFIG_BLE_MESH_NET_BUF_LOG && !CONFIG_BLE_MESH_NO_LOG) #define NET_BUF_ERR(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_ERROR) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, ERROR)) BLE_MESH_PRINT_E(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) #define NET_BUF_WARN(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_WARN) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, WARN)) BLE_MESH_PRINT_W(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) #define NET_BUF_INFO(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_INFO) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, INFO)) BLE_MESH_PRINT_I(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) @@ -106,7 +106,7 @@ extern "C" { #define NET_BUF_ASSERT(cond) #endif -#if defined(CONFIG_BLE_MESH_NET_BUF_SIMPLE_LOG) && (!CONFIG_BLE_MESH_NO_LOG) +#if (CONFIG_BLE_MESH_NET_BUF_SIMPLE_LOG && !CONFIG_BLE_MESH_NO_LOG) #define NET_BUF_SIMPLE_ERR(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_ERROR) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, ERROR)) BLE_MESH_PRINT_E(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) #define NET_BUF_SIMPLE_WARN(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_WARN) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, WARN)) BLE_MESH_PRINT_W(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) #define NET_BUF_SIMPLE_INFO(fmt, args...) do {if ((BLE_MESH_NET_BUF_LOG_LEVEL >= BLE_MESH_LOG_LEVEL_INFO) && BLE_MESH_LOG_LEVEL_CHECK(BLE_MESH_NET_BUF, INFO)) BLE_MESH_PRINT_I(BLE_MESH_TRACE_TAG, fmt, ## args);} while(0) diff --git a/components/bt/esp_ble_mesh/common/include/mesh/utils.h b/components/bt/esp_ble_mesh/common/include/mesh/utils.h index f815e52781..e5572afc3e 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/utils.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/utils.h @@ -26,13 +26,13 @@ extern "C" { * Those are available for 32 bits architectures: */ #ifndef POINTER_TO_UINT -#define POINTER_TO_UINT(x) ((uint32_t) (x)) +#define POINTER_TO_UINT(x) ((uint32_t) (x)) #endif #ifndef UINT_TO_POINTER #define UINT_TO_POINTER(x) ((void *) (x)) #endif #ifndef POINTER_TO_INT -#define POINTER_TO_INT(x) ((int32_t) (x)) +#define POINTER_TO_INT(x) ((int32_t) (x)) #endif #ifndef INT_TO_POINTER #define INT_TO_POINTER(x) ((void *) (x)) @@ -108,7 +108,7 @@ extern "C" { * evaluation version. */ #ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif /** @brief Return smaller value of two provided expressions. @@ -117,15 +117,15 @@ extern "C" { * evaluation version. */ #ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef BIT -#define BIT(n) (1UL << (n)) +#define BIT(n) (1UL << (n)) #endif #ifndef BIT_MASK -#define BIT_MASK(n) (BIT(n) - 1) +#define BIT_MASK(n) (BIT(n) - 1) #endif /** diff --git a/components/bt/esp_ble_mesh/common/mutex.c b/components/bt/esp_ble_mesh/common/mutex.c index 18015a99d5..6c3b2bf6f7 100644 --- a/components/bt/esp_ble_mesh/common/mutex.c +++ b/components/bt/esp_ble_mesh/common/mutex.c @@ -74,10 +74,54 @@ void bt_mesh_mutex_unlock(bt_mesh_mutex_t *mutex) } } -static inline void bt_mesh_alarm_mutex_new(void) +void bt_mesh_r_mutex_create(bt_mesh_mutex_t *mutex) { - if (!alarm_lock.mutex) { - bt_mesh_mutex_create(&alarm_lock); + if (!mutex) { + BT_ERR("Create, invalid recursive mutex"); + return; + } + +#if CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC +#if CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL + mutex->buffer = heap_caps_calloc_prefer(1, sizeof(StaticQueue_t), 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#elif CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_IRAM_8BIT + mutex->buffer = heap_caps_calloc_prefer(1, sizeof(StaticQueue_t), 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#endif + __ASSERT(mutex->buffer, "Failed to create recursive mutex buffer"); + mutex->mutex = xSemaphoreCreateRecursiveMutexStatic(mutex->buffer); + __ASSERT(mutex->mutex, "Failed to create static recursive mutex"); +#else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC */ + mutex->mutex = xSemaphoreCreateRecursiveMutex(); + __ASSERT(mutex->mutex, "Failed to create recursive mutex"); +#endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC */ +} + +void bt_mesh_r_mutex_free(bt_mesh_mutex_t *mutex) +{ + bt_mesh_mutex_free(mutex); +} + +void bt_mesh_r_mutex_lock(bt_mesh_mutex_t *mutex) +{ + if (!mutex) { + BT_ERR("Lock, invalid recursive mutex"); + return; + } + + if (mutex->mutex) { + xSemaphoreTakeRecursive(mutex->mutex, portMAX_DELAY); + } +} + +void bt_mesh_r_mutex_unlock(bt_mesh_mutex_t *mutex) +{ + if (!mutex) { + BT_ERR("Unlock, invalid recursive mutex"); + return; + } + + if (mutex->mutex) { + xSemaphoreGiveRecursive(mutex->mutex); } } @@ -91,13 +135,6 @@ void bt_mesh_alarm_unlock(void) bt_mesh_mutex_unlock(&alarm_lock); } -static inline void bt_mesh_list_mutex_new(void) -{ - if (!list_lock.mutex) { - bt_mesh_mutex_create(&list_lock); - } -} - void bt_mesh_list_lock(void) { bt_mesh_mutex_lock(&list_lock); @@ -108,13 +145,6 @@ void bt_mesh_list_unlock(void) bt_mesh_mutex_unlock(&list_lock); } -static inline void bt_mesh_buf_mutex_new(void) -{ - if (!buf_lock.mutex) { - bt_mesh_mutex_create(&buf_lock); - } -} - void bt_mesh_buf_lock(void) { bt_mesh_mutex_lock(&buf_lock); @@ -125,13 +155,6 @@ void bt_mesh_buf_unlock(void) bt_mesh_mutex_unlock(&buf_lock); } -static inline void bt_mesh_atomic_mutex_new(void) -{ - if (!atomic_lock.mutex) { - bt_mesh_mutex_create(&atomic_lock); - } -} - void bt_mesh_atomic_lock(void) { bt_mesh_mutex_lock(&atomic_lock); @@ -144,38 +167,18 @@ void bt_mesh_atomic_unlock(void) void bt_mesh_mutex_init(void) { - bt_mesh_alarm_mutex_new(); - bt_mesh_list_mutex_new(); - bt_mesh_buf_mutex_new(); - bt_mesh_atomic_mutex_new(); + bt_mesh_mutex_create(&alarm_lock); + bt_mesh_mutex_create(&list_lock); + bt_mesh_mutex_create(&buf_lock); + bt_mesh_mutex_create(&atomic_lock); } #if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_alarm_mutex_free(void) -{ - bt_mesh_mutex_free(&alarm_lock); -} - -static inline void bt_mesh_list_mutex_free(void) -{ - bt_mesh_mutex_free(&list_lock); -} - -static inline void bt_mesh_buf_mutex_free(void) -{ - bt_mesh_mutex_free(&buf_lock); -} - -static inline void bt_mesh_atomic_mutex_free(void) -{ - bt_mesh_mutex_free(&atomic_lock); -} - void bt_mesh_mutex_deinit(void) { - bt_mesh_alarm_mutex_free(); - bt_mesh_list_mutex_free(); - bt_mesh_buf_mutex_free(); - bt_mesh_atomic_mutex_free(); + bt_mesh_mutex_free(&alarm_lock); + bt_mesh_mutex_free(&list_lock); + bt_mesh_mutex_free(&buf_lock); + bt_mesh_mutex_free(&atomic_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/common/timer.c b/components/bt/esp_ble_mesh/common/timer.c index 540849e6d4..74fe3b492e 100644 --- a/components/bt/esp_ble_mesh/common/timer.c +++ b/components/bt/esp_ble_mesh/common/timer.c @@ -12,12 +12,12 @@ #include "osi/alarm.h" #include "osi/hash_functions.h" +#include "mesh/config.h" #include "mesh/common.h" -#include "prov_pvnr.h" static hash_map_t *bm_alarm_hash_map; -static const size_t BLE_MESH_GENERAL_ALARM_HASH_MAP_SIZE = 20 + CONFIG_BLE_MESH_PBA_SAME_TIME + \ - CONFIG_BLE_MESH_PBG_SAME_TIME; +static const size_t BLE_MESH_ALARM_HASH_MAP_SIZE = 20 + CONFIG_BLE_MESH_PBA_SAME_TIME + + CONFIG_BLE_MESH_PBG_SAME_TIME; typedef struct alarm_t { /* timer id point to here */ @@ -45,7 +45,7 @@ uint32_t k_uptime_get_32(void) void bt_mesh_timer_init(void) { - bm_alarm_hash_map = hash_map_new(BLE_MESH_GENERAL_ALARM_HASH_MAP_SIZE, + bm_alarm_hash_map = hash_map_new(BLE_MESH_ALARM_HASH_MAP_SIZE, hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); __ASSERT(bm_alarm_hash_map, "Failed to create hash map"); @@ -73,42 +73,53 @@ int k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler) k_work_init(&work->work, handler); bt_mesh_alarm_lock(); - if (!hash_map_has_key(bm_alarm_hash_map, (void *)work)) { - alarm = osi_alarm_new("bt_mesh", (osi_alarm_callback_t)handler, (void *)&work->work, 0); - if (alarm == NULL) { - BT_ERR("Alarm not created"); - bt_mesh_alarm_unlock(); - return -EIO; - } - if (!hash_map_set(bm_alarm_hash_map, work, (void *)alarm)) { - BT_ERR("Alarm not set"); - bt_mesh_alarm_unlock(); - return -EIO; - } - } alarm = hash_map_get(bm_alarm_hash_map, work); - if (alarm == NULL) { - BT_ERR("Init, alarm not found"); + if (alarm) { + BT_ERR("Init, alarm already exists"); bt_mesh_alarm_unlock(); - return -ENODEV; + return -EEXIST; + } + + alarm = osi_alarm_new("bt_mesh", (osi_alarm_callback_t)handler, (void *)&work->work, 0); + if (alarm == NULL) { + BT_ERR("Init, alarm not created"); + bt_mesh_alarm_unlock(); + return -EIO; + } + + if (!hash_map_set(bm_alarm_hash_map, work, (void *)alarm)) { + BT_ERR("Init, alarm not set"); + bt_mesh_alarm_unlock(); + return -EIO; } // Just init the work timer only, don't start it. osi_alarm_cancel(alarm); + bt_mesh_alarm_unlock(); + return 0; } int k_delayed_work_submit(struct k_delayed_work *work, int32_t delay) { + osi_alarm_t *alarm = NULL; + if (!work || !bm_alarm_hash_map) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + /* If delay is 0, call the corresponding timeout handler. */ + if (delay == 0) { + k_work_submit(&work->work); + return 0; + } + bt_mesh_alarm_lock(); - osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + + alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("Submit, alarm not found"); bt_mesh_alarm_unlock(); @@ -118,19 +129,30 @@ int k_delayed_work_submit(struct k_delayed_work *work, int32_t delay) // Cancel the alarm first, before start the alarm. osi_alarm_cancel(alarm); osi_alarm_set(alarm, delay); + bt_mesh_alarm_unlock(); + return 0; } int k_delayed_work_submit_periodic(struct k_delayed_work *work, int32_t period) { + osi_alarm_t *alarm = NULL; + if (!work || !bm_alarm_hash_map) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + /* If period is 0, call the corresponding timeout handler. */ + if (period == 0) { + k_work_submit(&work->work); + return 0; + } + bt_mesh_alarm_lock(); - osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + + alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("Submit, alarm not found"); bt_mesh_alarm_unlock(); @@ -140,19 +162,24 @@ int k_delayed_work_submit_periodic(struct k_delayed_work *work, int32_t period) /* Cancel the alarm first before starting it. */ osi_alarm_cancel(alarm); osi_alarm_set_periodic(alarm, period); + bt_mesh_alarm_unlock(); + return 0; } int k_delayed_work_cancel(struct k_delayed_work *work) { + osi_alarm_t *alarm = NULL; + if (!work || !bm_alarm_hash_map) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_alarm_lock(); - osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + + alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("Cancel, alarm not found"); bt_mesh_alarm_unlock(); @@ -161,19 +188,24 @@ int k_delayed_work_cancel(struct k_delayed_work *work) osi_alarm_cancel(alarm); alarm->deadline_us = 0; + bt_mesh_alarm_unlock(); + return 0; } int k_delayed_work_free(struct k_delayed_work *work) { + osi_alarm_t *alarm = NULL; + if (!work || !bm_alarm_hash_map) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_alarm_lock(); - osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, work); + + alarm = hash_map_get(bm_alarm_hash_map, work); if (alarm == NULL) { BT_WARN("Free, alarm not found"); bt_mesh_alarm_unlock(); @@ -182,12 +214,15 @@ int k_delayed_work_free(struct k_delayed_work *work) osi_alarm_cancel(alarm); hash_map_erase(bm_alarm_hash_map, work); + bt_mesh_alarm_unlock(); + return 0; } int32_t k_delayed_work_remaining_get(struct k_delayed_work *work) { + osi_alarm_t *alarm = NULL; int32_t time = 0; if (!work || !bm_alarm_hash_map) { @@ -196,7 +231,8 @@ int32_t k_delayed_work_remaining_get(struct k_delayed_work *work) } bt_mesh_alarm_lock(); - osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); + + alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("Get time, alarm not found"); bt_mesh_alarm_unlock(); @@ -204,6 +240,8 @@ int32_t k_delayed_work_remaining_get(struct k_delayed_work *work) } time = osi_alarm_get_remaining_ms(alarm); + bt_mesh_alarm_unlock(); + return time; } diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 446cb13e8a..51bf870bda 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -12,6 +12,8 @@ #include "mesh.h" #include "adv.h" +#include "lpn.h" +#include "friend.h" #include "transport.h" #include "access.h" #include "foundation.h" @@ -20,11 +22,18 @@ #include "fast_prov.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + #define BLE_MESH_SDU_MAX_LEN 384 -static const struct bt_mesh_comp *dev_comp; +extern const struct bt_mesh_comp *comp_0; static uint16_t dev_primary_addr; +static int model_send(struct bt_mesh_model *model, + struct bt_mesh_net_tx *tx, bool implicit_bind, + struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data); + void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, @@ -33,13 +42,13 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, { int i, j; - if (dev_comp == NULL) { + if (comp_0 == NULL) { BT_ERR("Invalid device composition"); return; } - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + for (i = 0; i < comp_0->elem_count; i++) { + struct bt_mesh_elem *elem = &comp_0->elem[i]; for (j = 0; j < elem->model_count; j++) { struct bt_mesh_model *model = &elem->models[j]; @@ -88,9 +97,9 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) if (mod->pub->fast_period) { return period >> mod->pub->period_div; - } else { - return period; } + + return period; } static int32_t next_period(struct bt_mesh_model *mod) @@ -169,43 +178,49 @@ static const struct bt_mesh_send_cb pub_sent_cb = { static int publish_retransmit(struct bt_mesh_model *mod) { struct bt_mesh_model_pub *pub = mod->pub; - if (!pub) { + struct bt_mesh_app_key *key = NULL; + struct net_buf_simple *sdu = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + struct bt_mesh_net_tx tx = { + .ctx = &ctx, + .src = bt_mesh_model_elem(mod)->addr, + .xmit = bt_mesh_net_transmit_get(), + }; + int err = 0; + + if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; } - struct bt_mesh_app_key *key = NULL; - struct net_buf_simple *sdu = NULL; - struct bt_mesh_msg_ctx ctx = { - .addr = pub->addr, - .send_ttl = pub->ttl, - .model = mod, - .srv_send = (pub->dev_role == NODE ? true : false), - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_model_elem(mod)->addr, - .xmit = bt_mesh_net_transmit_get(), - .friend_cred = pub->cred, - }; - int err = 0; - - key = bt_mesh_tx_appkey_get(pub->dev_role, pub->key); + key = bt_mesh_app_key_get(pub->key); if (!key) { - BT_ERR("AppKey 0x%03x not exists", pub->key); + BT_ERR("Publish, AppKey 0x%03x not found", pub->key); return -EADDRNOTAVAIL; } - tx.sub = bt_mesh_tx_netkey_get(pub->dev_role, key->net_idx); + tx.sub = bt_mesh_subnet_get(key->net_idx); if (!tx.sub) { - BT_ERR("Subnet 0x%04x not exists", key->net_idx); + BT_ERR("Publish, NetKey 0x%04x not found", key->net_idx); return -EADDRNOTAVAIL; } + ctx.addr = pub->addr; ctx.net_idx = key->net_idx; ctx.app_idx = key->app_idx; + 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 (pub->send_rel) { + /* Tag with send-segmented */ + ctx.send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } - sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_SHORT); +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); +#endif + + sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; @@ -215,7 +230,7 @@ static int publish_retransmit(struct bt_mesh_model *mod) pub->count--; - err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); + err = model_send(mod, &tx, true, sdu, &pub_sent_cb, mod); bt_mesh_free_buf(sdu); return err; @@ -237,8 +252,6 @@ static void mod_publish(struct k_work *work) int32_t period_ms = 0; int err = 0; - BT_DBG("%s", __func__); - period_ms = bt_mesh_model_pub_period_get(pub->mod); BT_INFO("Publish period %u ms", period_ms); @@ -254,7 +267,6 @@ static void mod_publish(struct k_work *work) k_delayed_work_submit(&pub->timer, period_ms); } } - return; } @@ -282,24 +294,24 @@ static void mod_publish(struct k_work *work) struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) { - return &dev_comp->elem[mod->elem_idx]; + return &comp_0->elem[mod->elem_idx]; } struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) { struct bt_mesh_elem *elem = NULL; - if (!dev_comp) { - BT_ERR("dev_comp not initialized"); + if (!comp_0) { + BT_ERR("comp_0 not initialized"); return NULL; } - if (elem_idx >= dev_comp->elem_count) { + if (elem_idx >= comp_0->elem_count) { BT_ERR("Invalid element index %u", elem_idx); return NULL; } - elem = &dev_comp->elem[elem_idx]; + elem = &comp_0->elem[elem_idx]; if (vnd) { if (mod_idx >= elem->vnd_model_count) { @@ -346,7 +358,7 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, } mod->flags = 0; - mod->elem_idx = elem - dev_comp->elem; + mod->elem_idx = elem - comp_0->elem; if (vnd) { mod->model_idx = mod - elem->vnd_models; } else { @@ -371,7 +383,7 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) return -EINVAL; } - dev_comp = comp; + comp_0 = comp; bt_mesh_model_foreach(mod_init, &err); @@ -423,13 +435,13 @@ int bt_mesh_comp_deregister(void) { int err = 0; - if (dev_comp == NULL) { + if (comp_0 == NULL) { return -EINVAL; } bt_mesh_model_foreach(mod_deinit, &err); - dev_comp = NULL; + comp_0 = NULL; return err; } @@ -441,10 +453,10 @@ void bt_mesh_comp_provision(uint16_t addr) dev_primary_addr = addr; - BT_INFO("Primary address 0x%04x, element count %u", addr, dev_comp->elem_count); + BT_INFO("Primary address 0x%04x, element count %u", addr, comp_0->elem_count); - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + for (i = 0; i < comp_0->elem_count; i++) { + struct bt_mesh_elem *elem = &comp_0->elem[i]; elem->addr = addr++; @@ -455,8 +467,6 @@ void bt_mesh_comp_provision(uint16_t addr) void bt_mesh_comp_unprovision(void) { - BT_DBG("%s", __func__); - dev_primary_addr = BLE_MESH_ADDR_UNASSIGNED; } @@ -511,16 +521,16 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) uint16_t index = 0U; if (BLE_MESH_ADDR_IS_UNICAST(addr)) { - index = (addr - dev_comp->elem[0].addr); - if (index < dev_comp->elem_count) { - return &dev_comp->elem[index]; - } else { - return NULL; + index = (addr - comp_0->elem[0].addr); + if (index < comp_0->elem_count) { + return &comp_0->elem[index]; } + + return NULL; } - for (index = 0; index < dev_comp->elem_count; index++) { - struct bt_mesh_elem *elem = &dev_comp->elem[index]; + for (index = 0; index < comp_0->elem_count; index++) { + struct bt_mesh_elem *elem = &comp_0->elem[index]; if (bt_mesh_elem_find_group(elem, addr)) { return elem; @@ -532,7 +542,7 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) uint8_t bt_mesh_elem_count(void) { - return dev_comp->elem_count; + return comp_0->elem_count; } static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) @@ -548,15 +558,20 @@ static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) return false; } -static bool model_has_dst(struct bt_mesh_model *model, uint16_t dst) +static bool model_has_dst(struct bt_mesh_model *model, + struct bt_mesh_subnet *sub, + uint16_t dst) { if (BLE_MESH_ADDR_IS_UNICAST(dst)) { - return (dev_comp->elem[model->elem_idx].addr == dst); - } else if (BLE_MESH_ADDR_IS_GROUP(dst) || BLE_MESH_ADDR_IS_VIRTUAL(dst)) { + return (comp_0->elem[model->elem_idx].addr == dst); + } + + if (BLE_MESH_ADDR_IS_GROUP(dst) || BLE_MESH_ADDR_IS_VIRTUAL(dst)) { return !!bt_mesh_model_find_group(model, dst); } - return (model->elem_idx == 0 && bt_mesh_fixed_group_match(dst)); + return (model->elem_idx == 0 && (bt_mesh_fixed_group_match(dst) || + bt_mesh_fixed_direct_match(sub, dst))); } static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, @@ -581,7 +596,7 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, return NULL; } -static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode) +static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) { switch (buf->data[0] >> 6) { case 0x00: @@ -591,34 +606,51 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode) return -EINVAL; } - *opcode = net_buf_simple_pull_u8(buf); + *opcode = pull_buf ? net_buf_simple_pull_u8(buf) : buf->data[0]; return 0; + case 0x02: if (buf->len < 2) { BT_ERR("Too short payload for 2-octet OpCode"); return -EINVAL; } - *opcode = net_buf_simple_pull_be16(buf); + *opcode = pull_buf ? net_buf_simple_pull_be16(buf) : sys_get_be16(buf->data); return 0; + case 0x03: if (buf->len < 3) { BT_ERR("Too short payload for 3-octet OpCode"); return -EINVAL; } - *opcode = net_buf_simple_pull_u8(buf) << 16; - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - *opcode |= net_buf_simple_pull_le16(buf); + if (pull_buf) { + *opcode = net_buf_simple_pull_u8(buf) << 16; + /* Using LE for the CID since the model layer is defined as + * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * will declare the opcode in this way. + */ + *opcode |= net_buf_simple_pull_le16(buf); + } else { + *opcode = buf->data[0] << 16 | sys_get_le16(&buf->data[1]); + } return 0; } return -EINVAL; } +int bt_mesh_get_opcode(struct net_buf_simple *buf, + uint32_t *opcode, bool pull_buf) +{ + if (buf == NULL || buf->len == 0 || opcode == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + return get_opcode(buf, opcode, pull_buf); +} + bool bt_mesh_fixed_group_match(uint16_t addr) { /* Check for fixed group addresses */ @@ -636,6 +668,22 @@ bool bt_mesh_fixed_group_match(uint16_t addr) } } +bool bt_mesh_fixed_direct_match(struct bt_mesh_subnet *sub, uint16_t addr) +{ + /* A message sent to the all-directed-forwarding-nodes address + * shall be processed by the primary element of all nodes that + * have directed forwarding functionality enabled. + */ +#if CONFIG_BLE_MESH_DF_SRV + if (addr == BLE_MESH_ADDR_DIRECTS && sub && + sub->directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_ENABLED) { + return true; + } +#endif + + return false; +} + void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { struct bt_mesh_model *models = NULL, *model = NULL; @@ -648,15 +696,15 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) rx->ctx.addr, rx->ctx.recv_dst); BT_INFO("recv, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); - if (get_opcode(buf, &opcode) < 0) { + if (get_opcode(buf, &opcode, true) < 0) { BT_WARN("Unable to decode OpCode"); return; } BT_DBG("OpCode 0x%08x", opcode); - for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + for (i = 0; i < comp_0->elem_count; i++) { + struct bt_mesh_elem *elem = &comp_0->elem[i]; struct net_buf_simple_state state = {0}; /* SIG models cannot contain 3-byte (vendor) OpCodes, and @@ -681,7 +729,7 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) continue; } - if (!model_has_dst(model, rx->ctx.recv_dst)) { + if (!model_has_dst(model, rx->sub, rx->ctx.recv_dst)) { continue; } @@ -690,17 +738,28 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) continue; } - /* The following three operations are added by Espressif. - * 1. Update the "recv_op" with the opcode got from the buf; - * 2. Update the model pointer with the found model; - * 3. Update the "srv_send" to be true when received a message. - * This flag will be used when a server model sends a status - * message, and has no impact on the client messages. - * Most of these info will be used by the application layer. + /* The following operation is added by Espressif. + * Update the "recv_op" with the opcode got from the buf; */ rx->ctx.recv_op = opcode; - rx->ctx.model = model; - rx->ctx.srv_send = true; + + /* The message is transmitted by a model in response to a message that + * it has received. + * + * The TTL field shall be set to the value of the Default TTL state. + * + * The response message shall use master security credentials. However, + * the security credentials may be changed by a lower layer unless the + * received message uses the master security credentials. If the received + * message uses master security credentials, then the response message + * shall be tagged with the immutable-credentials tag, and the security + * credentials will not be changed by any lower layer. + */ + rx->ctx.send_ttl = BLE_MESH_TTL_DEFAULT; + if (rx->ctx.recv_cred == BLE_MESH_FLOODING_CRED) { + rx->ctx.send_tag |= BLE_MESH_TAG_IMMUTABLE_CRED; + rx->ctx.send_cred = BLE_MESH_FLOODING_CRED; + } /* The callback will likely parse the buffer, so store * the parsing state in case multiple models receive @@ -737,18 +796,19 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) } } -static bool ready_to_send(uint8_t role, uint16_t dst) +static bool ready_to_send(uint16_t dst) { - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && role == NODE) { + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { return true; - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en() && role == PROVISIONER) { - if (!bt_mesh_provisioner_check_msg_dst(dst)) { + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { + if (bt_mesh_provisioner_check_msg_dst(dst) == false && + bt_mesh_elem_find(dst) == false) { BT_ERR("Failed to find DST 0x%04x", dst); return false; } return true; - } else if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && bt_mesh_is_provisioned() && role == FAST_PROV) { - return true; } return false; @@ -759,23 +819,23 @@ static int model_send(struct bt_mesh_model *model, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { - uint8_t role = 0U; - - role = bt_mesh_get_device_role(model, tx->ctx->srv_send); - if (role == ROLE_NVAL) { - BT_ERR("Failed to get model role"); - return -EINVAL; - } + int err = 0; BT_INFO("send, app_idx 0x%04x src 0x%04x dst 0x%04x", tx->ctx->app_idx, tx->src, tx->ctx->addr); BT_INFO("send, len %u: %s", msg->len, bt_hex(msg->data, msg->len)); - if (!ready_to_send(role, tx->ctx->addr)) { + if (ready_to_send(tx->ctx->addr) == false) { BT_ERR("Not ready to send"); return -EINVAL; } + if (tx->ctx->send_ttl != BLE_MESH_TTL_DEFAULT && + tx->ctx->send_ttl > BLE_MESH_TTL_MAX) { + BT_ERR("Too big send TTL 0x%02x", tx->ctx->send_ttl); + return -EINVAL; + } + if (net_buf_simple_tailroom(msg) < BLE_MESH_MIC_SHORT) { BT_ERR("Not enough tailroom for TransMIC"); return -EINVAL; @@ -791,7 +851,43 @@ static int model_send(struct bt_mesh_model *model, return -EINVAL; } - return bt_mesh_trans_send(tx, msg, cb, cb_data); + if (bt_mesh_valid_security_cred(tx) == false) { + BT_ERR("Can not use security cred 0x%02x", tx->ctx->send_cred); + return -EIO; + } + + bt_mesh_choose_better_security_cred(tx); + + err = bt_mesh_trans_send(tx, msg, cb, cb_data); + +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_is_directed_path_needed(tx); +#endif + + return err; +} + +int bt_mesh_model_send_implicit(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx,bool implicit_bind, + struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct bt_mesh_subnet *sub = NULL; + + sub = bt_mesh_subnet_get(ctx->net_idx); + if (!sub) { + BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + return -EADDRNOTAVAIL; + } + + struct bt_mesh_net_tx tx = { + .sub = sub, + .ctx = ctx, + .src = bt_mesh_model_elem(model)->addr, + .xmit = bt_mesh_net_transmit_get(), + }; + + return model_send(model, &tx, implicit_bind, msg, cb, cb_data); } int bt_mesh_model_send(struct bt_mesh_model *model, @@ -800,28 +896,18 @@ int bt_mesh_model_send(struct bt_mesh_model *model, const struct bt_mesh_send_cb *cb, void *cb_data) { struct bt_mesh_subnet *sub = NULL; - uint8_t role = 0U; - role = bt_mesh_get_device_role(model, ctx->srv_send); - if (role == ROLE_NVAL) { - BT_ERR("Failed to get model role"); - return -EINVAL; - } - - sub = bt_mesh_tx_netkey_get(role, ctx->net_idx); + sub = bt_mesh_subnet_get(ctx->net_idx); if (!sub) { - BT_ERR("Invalid NetKeyIndex 0x%04x", ctx->net_idx); - return -EINVAL; + BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + return -EADDRNOTAVAIL; } - ctx->model = model; - struct bt_mesh_net_tx tx = { - .sub = sub, - .ctx = ctx, - .src = bt_mesh_model_elem(model)->addr, + .sub = sub, + .ctx = ctx, + .src = bt_mesh_model_elem(model)->addr, .xmit = bt_mesh_net_transmit_get(), - .friend_cred = 0, }; return model_send(model, &tx, false, msg, cb, cb_data); @@ -832,19 +918,14 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) struct bt_mesh_model_pub *pub = model->pub; struct bt_mesh_app_key *key = NULL; struct net_buf_simple *sdu = NULL; - struct bt_mesh_msg_ctx ctx = { - .model = model, - }; + struct bt_mesh_msg_ctx ctx = {0}; struct bt_mesh_net_tx tx = { - .sub = NULL, - .ctx = &ctx, - .src = bt_mesh_model_elem(model)->addr, + .ctx = &ctx, + .src = bt_mesh_model_elem(model)->addr, .xmit = bt_mesh_net_transmit_get(), }; int err = 0; - BT_DBG("%s", __func__); - if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; @@ -855,12 +936,6 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) return -EADDRNOTAVAIL; } - key = bt_mesh_tx_appkey_get(pub->dev_role, pub->key); - if (!key) { - BT_ERR("Invalid AppKeyIndex 0x%03x", pub->key); - return -EADDRNOTAVAIL; - } - if (pub->msg->len + BLE_MESH_MIC_SHORT > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SDU_MAX_LEN)) { BT_ERR("Message does not fit maximum SDU size"); return -EMSGSIZE; @@ -871,27 +946,39 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) k_delayed_work_cancel(&pub->timer); } - ctx.addr = pub->addr; - ctx.send_rel = pub->send_rel; - ctx.send_ttl = pub->ttl; - ctx.net_idx = key->net_idx; - ctx.app_idx = key->app_idx; - ctx.srv_send = pub->dev_role == NODE ? true : false; - - tx.friend_cred = pub->cred; - - tx.sub = bt_mesh_tx_netkey_get(pub->dev_role, ctx.net_idx); - if (!tx.sub) { - BT_ERR("Invalid NetKeyIndex 0x%04x", ctx.net_idx); + key = bt_mesh_app_key_get(pub->key); + if (!key) { + BT_ERR("Publish, AppKey 0x%03x not found", pub->key); return -EADDRNOTAVAIL; } + tx.sub = bt_mesh_subnet_get(ctx.net_idx); + if (!tx.sub) { + BT_ERR("Publish, NetKey 0x%04x not found", ctx.net_idx); + return -EADDRNOTAVAIL; + } + + ctx.addr = pub->addr; + ctx.net_idx = key->net_idx; + ctx.app_idx = key->app_idx; + 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 (pub->send_rel) { + /* Tag with send-segmented */ + ctx.send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } + +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); +#endif + pub->count = BLE_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); BT_INFO("Publish Retransmit Count %u Interval %ums", pub->count, BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); - sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_SHORT); + sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; @@ -915,7 +1002,7 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem, for (i = 0; i < elem->vnd_model_count; i++) { if (elem->vnd_models[i].vnd.company == company && - elem->vnd_models[i].vnd.id == id) { + elem->vnd_models[i].vnd.id == id) { return &elem->vnd_models[i]; } } @@ -938,56 +1025,26 @@ struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, uint16_t id) const struct bt_mesh_comp *bt_mesh_comp_get(void) { - return dev_comp; + return comp_0; } -/* APIs used by messages encryption in upper transport layer & network layer */ -struct bt_mesh_subnet *bt_mesh_tx_netkey_get(uint8_t role, uint16_t net_idx) -{ - struct bt_mesh_subnet *sub = NULL; - - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && role == NODE) { - sub = bt_mesh_subnet_get(net_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en() && role == PROVISIONER) { - sub = bt_mesh_provisioner_subnet_get(net_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && bt_mesh_is_provisioned() && role == FAST_PROV) { - sub = bt_mesh_fast_prov_subnet_get(net_idx); - } - - return sub; -} - -const uint8_t *bt_mesh_tx_devkey_get(uint8_t role, uint16_t dst) +const uint8_t *bt_mesh_dev_key_get(uint16_t dst) { const uint8_t *key = NULL; - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && role == NODE) { - key = bt_mesh.dev_key; - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en() && role == PROVISIONER) { + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { + key = bt_mesh.dev_key; + } else { + key = bt_mesh_fast_prov_dev_key_get(dst); + } + } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { key = bt_mesh_provisioner_dev_key_get(dst); - } else if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && bt_mesh_is_provisioned() && role == FAST_PROV) { - key = bt_mesh_fast_prov_dev_key_get(dst); } return key; } -struct bt_mesh_app_key *bt_mesh_tx_appkey_get(uint8_t role, uint16_t app_idx) -{ - struct bt_mesh_app_key *key = NULL; - - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && role == NODE) { - key = bt_mesh_app_key_find(app_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en() && role == PROVISIONER) { - key = bt_mesh_provisioner_app_key_find(app_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && bt_mesh_is_provisioned() && role == FAST_PROV) { - key = bt_mesh_fast_prov_app_key_find(app_idx); - } - - return key; -} - -/* APIs used by messages decryption in network layer & upper transport layer */ size_t bt_mesh_rx_netkey_size(void) { size_t size = 0U; @@ -1048,6 +1105,9 @@ size_t bt_mesh_rx_devkey_size(void) #if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioned()) { size = 1; + if (bt_mesh_dev_key_ca_valid()) { + size += 1; + } } #endif @@ -1059,6 +1119,9 @@ size_t bt_mesh_rx_devkey_size(void) #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = 1; + if (bt_mesh_dev_key_ca_valid()) { + size += 1; + } if (bt_mesh_is_provisioner_en()) { size += 1; } @@ -1073,7 +1136,11 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) #if CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioned()) { - key = bt_mesh.dev_key; + if (index == 0) { + key = bt_mesh.dev_key; + } else if (index == 1) { + key = bt_mesh.dev_key_ca; + } } #endif @@ -1084,8 +1151,18 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) #endif #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER - if (index < 1) { + if (index == 0) { key = bt_mesh.dev_key; + } else if (index == 1 && bt_mesh_dev_key_ca_valid()) { + /* If index == 1, there are two cases. + * 1. bt_mesh_dev_key_ca_valid() is true, it should be return bt_mesh.dev_key_ca. + * 2. bt_mesh_is_provisioner_en() is true, it should be return bt_mesh_provisioner_dev_key_get(src). + * + * If index == 2, that means bt_mesh_dev_key_ca_valid() and bt_mesh_is_provisioner_en() are true. + * So the previous round of function bt_mesh_rx_devkey_get(1, src) will return bt_mesh.dev_key_ca. + * Then this round of function bt_mesh_rx_devkey_get(2, src) will return bt_mesh_provisioner_dev_key_get(src). + */ + key = bt_mesh.dev_key_ca; } else { key = bt_mesh_provisioner_dev_key_get(src); } diff --git a/components/bt/esp_ble_mesh/core/access.h b/components/bt/esp_ble_mesh/core/access.h index a74e056392..672a9a2c7b 100644 --- a/components/bt/esp_ble_mesh/core/access.h +++ b/components/bt/esp_ble_mesh/core/access.h @@ -31,8 +31,13 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); uint16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, uint16_t addr); +int bt_mesh_get_opcode(struct net_buf_simple *buf, + uint32_t *opcode, bool pull_buf); + bool bt_mesh_fixed_group_match(uint16_t addr); +bool bt_mesh_fixed_direct_match(struct bt_mesh_subnet *sub, uint16_t addr); + void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, @@ -55,11 +60,7 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); int bt_mesh_comp_register(const struct bt_mesh_comp *comp); int bt_mesh_comp_deregister(void); -struct bt_mesh_subnet *bt_mesh_tx_netkey_get(uint8_t role, uint16_t net_idx); - -const uint8_t *bt_mesh_tx_devkey_get(uint8_t role, uint16_t dst); - -struct bt_mesh_app_key *bt_mesh_tx_appkey_get(uint8_t role, uint16_t app_idx); +const uint8_t *bt_mesh_dev_key_get(uint16_t dst); size_t bt_mesh_rx_netkey_size(void); diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index 2a84e5a122..b99d22f2a1 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -11,11 +11,11 @@ #include #include -#include "mesh/kernel.h" +#include "adv.h" #include "mesh.h" #include "mesh/hci.h" +#include "mesh/kernel.h" #include "mesh/common.h" -#include "adv.h" #include "beacon.h" #include "prov_node.h" #include "foundation.h" @@ -63,7 +63,7 @@ static struct bt_mesh_queue adv_queue; #define BLE_MESH_ADV_QUEUE_SIZE (CONFIG_BLE_MESH_ADV_BUF_COUNT + 1) #endif -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF NET_BUF_POOL_DEFINE(relay_adv_buf_pool, CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT, BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); @@ -79,7 +79,7 @@ static QueueSetHandle_t mesh_queue_set; #define BLE_MESH_MAX_TIME_INTERVAL 0xFFFFFFFF static bool ignore_relay_packet(uint32_t timestamp); -#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /* length + advertising data + length + scan response data */ @@ -175,9 +175,21 @@ static inline int adv_send(struct net_buf *buf) param.interval_min = ADV_SCAN_UNIT(adv_int); param.interval_max = param.interval_min; - bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); - - err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { + 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(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), + }; + err = bt_le_adv_start(¶m, solic_ad, 3, NULL, 0); + } else +#endif + { + bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); + } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV } else { struct bt_mesh_ble_adv_data data = {0}; @@ -238,7 +250,7 @@ static inline TickType_t K_WAIT(int32_t val) static void adv_thread(void *p) { -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF QueueSetMemberHandle_t handle = NULL; #endif bt_mesh_msg_t msg = {0}; @@ -250,9 +262,9 @@ static void adv_thread(void *p) while (1) { *buf = NULL; -#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER xQueueReceive(adv_queue.handle, &msg, K_NO_WAIT); while (!(*buf)) { int32_t timeout = 0; @@ -266,9 +278,9 @@ static void adv_thread(void *p) #else xQueueReceive(adv_queue.handle, &msg, portMAX_DELAY); #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ -#else /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER handle = xQueueSelectFromSet(mesh_queue_set, K_NO_WAIT); if (handle) { if (uxQueueMessagesWaiting(adv_queue.handle)) { @@ -304,7 +316,7 @@ static void adv_thread(void *p) } } #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ -#endif /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ if (*buf == NULL) { continue; @@ -313,11 +325,11 @@ static void adv_thread(void *p) /* busy == 0 means this was canceled */ if (BLE_MESH_ADV(*buf)->busy) { BLE_MESH_ADV(*buf)->busy = 0U; -#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF if (adv_send(*buf)) { BT_WARN("Failed to send adv packet"); } -#else /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ if (msg.relay && ignore_relay_packet(msg.timestamp)) { /* If the interval between "current time - msg.timestamp" is bigger than * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. @@ -329,7 +341,7 @@ static void adv_thread(void *p) BT_WARN("Failed to send adv packet"); } } -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ } else { bt_mesh_adv_buf_ref_debug(__func__, *buf, 1U, BLE_MESH_BUF_REF_EQUAL); net_buf_unref(*buf); @@ -343,7 +355,7 @@ static void adv_thread(void *p) struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, bt_mesh_adv_alloc_t get_id, enum bt_mesh_adv_type type, - uint8_t xmit, int32_t timeout) + int32_t timeout) { struct bt_mesh_adv *adv = NULL; struct net_buf *buf = NULL; @@ -367,7 +379,6 @@ struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, (void)memset(adv, 0, sizeof(*adv)); adv->type = type; - adv->xmit = xmit; return buf; } @@ -390,11 +401,10 @@ void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) } } -struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout) +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int32_t timeout) { - return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_alloc, type, - xmit, timeout); + return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_alloc, + type, timeout); } void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, @@ -433,14 +443,10 @@ static void bt_mesh_unref_buf(bt_mesh_msg_t *msg) } net_buf_unref(buf); } - - return; } static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { - BT_DBG("%s", __func__); - if (adv_queue.handle == NULL) { BT_ERR("Invalid adv queue"); return; @@ -459,7 +465,8 @@ static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) } } -void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, + const struct bt_mesh_send_cb *cb, void *cb_data) { bt_mesh_msg_t msg = { @@ -472,6 +479,7 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; BLE_MESH_ADV(buf)->busy = 1U; + BLE_MESH_ADV(buf)->xmit = xmit; bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); @@ -486,12 +494,10 @@ void bt_mesh_adv_update(void) .arg = NULL, }; - BT_DBG("%s", __func__); - bt_mesh_task_post(&msg, K_NO_WAIT, false); } -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF static bool ignore_relay_packet(uint32_t timestamp) { uint32_t now = k_uptime_get_32(); @@ -511,11 +517,10 @@ static struct bt_mesh_adv *relay_adv_alloc(int id) return &relay_adv_pool[id]; } -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout) +struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout) { - return bt_mesh_adv_create_from_pool(&relay_adv_buf_pool, relay_adv_alloc, type, - xmit, timeout); + return bt_mesh_adv_create_from_pool(&relay_adv_buf_pool, relay_adv_alloc, + type, timeout); } static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout) @@ -523,8 +528,6 @@ static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout) QueueSetMemberHandle_t handle = NULL; bt_mesh_msg_t old_msg = {0}; - BT_DBG("%s", __func__); - if (relay_queue.handle == NULL) { BT_ERR("Invalid relay queue"); return; @@ -534,8 +537,7 @@ static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout) return; } - /** - * If failed to send packet to the relay queue(queue is full), we will + /* If failed to send packet to the relay queue(queue is full), we will * remove the oldest packet in the queue and put the new one into it. */ handle = xQueueSelectFromSet(mesh_queue_set, K_NO_WAIT); @@ -561,8 +563,10 @@ static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout) } } -void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data, uint16_t src, uint16_t dst) +void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, + uint16_t src, uint16_t dst, + const struct bt_mesh_send_cb *cb, + void *cb_data) { bt_mesh_msg_t msg = { .relay = true, @@ -574,6 +578,7 @@ void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *c BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; BLE_MESH_ADV(buf)->busy = 1U; + BLE_MESH_ADV(buf)->xmit = xmit; msg.arg = (void *)net_buf_ref(buf); msg.src = src; @@ -587,7 +592,7 @@ uint16_t bt_mesh_get_stored_relay_count(void) { return (uint16_t)uxQueueMessagesWaiting(relay_queue.handle); } -#endif /* #if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#endif /* #if CONFIG_BLE_MESH_RELAY_ADV_BUF */ void bt_mesh_adv_init(void) { @@ -611,7 +616,7 @@ void bt_mesh_adv_init(void) __ASSERT(adv_queue.handle, "Failed to create static queue"); #endif /* !CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC */ -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF #if !CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC relay_queue.handle = xQueueCreate(BLE_MESH_RELAY_QUEUE_SIZE, sizeof(bt_mesh_msg_t)); __ASSERT(relay_queue.handle, "Failed to create relay queue"); @@ -636,7 +641,7 @@ void bt_mesh_adv_init(void) __ASSERT(mesh_queue_set, "Failed to create queue set"); xQueueAddToSet(adv_queue.handle, mesh_queue_set); xQueueAddToSet(relay_queue.handle, mesh_queue_set); -#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ @@ -674,7 +679,7 @@ void bt_mesh_adv_deinit(void) adv_task.task = NULL; #endif -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF xQueueRemoveFromSet(adv_queue.handle, mesh_queue_set); xQueueRemoveFromSet(relay_queue.handle, mesh_queue_set); @@ -685,14 +690,14 @@ void bt_mesh_adv_deinit(void) relay_queue.buffer = NULL; heap_caps_free(relay_queue.storage); relay_queue.storage = NULL; -#endif +#endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC */ bt_mesh_unref_buf_from_pool(&relay_adv_buf_pool); memset(relay_adv_pool, 0, sizeof(relay_adv_pool)); vQueueDelete(mesh_queue_set); mesh_queue_set = NULL; -#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ vQueueDelete(adv_queue.handle); adv_queue.handle = NULL; @@ -701,14 +706,14 @@ void bt_mesh_adv_deinit(void) adv_queue.buffer = NULL; heap_caps_free(adv_queue.storage); adv_queue.storage = NULL; -#endif +#endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC */ bt_mesh_unref_buf_from_pool(&adv_buf_pool); memset(adv_pool, 0, sizeof(adv_pool)); #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -718,10 +723,10 @@ static struct bt_mesh_adv *ble_adv_alloc(int id) return &ble_adv_pool[id]; } -static struct net_buf *bt_mesh_ble_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, int32_t timeout) +static struct net_buf *bt_mesh_ble_adv_create(enum bt_mesh_adv_type type, int32_t timeout) { - return bt_mesh_adv_create_from_pool(&ble_adv_buf_pool, ble_adv_alloc, type, - xmit, timeout); + return bt_mesh_adv_create_from_pool(&ble_adv_buf_pool, ble_adv_alloc, + type, timeout); } static void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, @@ -789,11 +794,7 @@ static void ble_adv_send_end(int err, void *cb_data) } if (tx->param.count) { - if (tx->param.period) { - k_delayed_work_submit(&tx->resend, tx->param.period); - } else { - k_work_submit(&tx->resend.work); - } + k_delayed_work_submit(&tx->resend, tx->param.period); } else { ble_adv_tx_reset(tx, true); } @@ -806,7 +807,9 @@ static struct bt_mesh_send_cb ble_adv_send_cb = { static void ble_adv_resend(struct k_work *work) { - struct ble_adv_tx *tx = CONTAINER_OF(work, struct ble_adv_tx, resend.work); + struct ble_adv_tx *tx = CONTAINER_OF(work, + struct ble_adv_tx, + resend.work); bool front = false; if (tx->buf == NULL) { @@ -880,7 +883,7 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, return -EINVAL; } - buf = bt_mesh_ble_adv_create(BLE_MESH_ADV_BLE, 0U, K_NO_WAIT); + buf = bt_mesh_ble_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); if (!buf) { BT_ERR("No empty ble adv buffer"); return -ENOBUFS; diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index 16c3f15918..9367f962fd 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -18,16 +18,16 @@ extern "C" { #endif /* Maximum advertising data payload for a single data type */ -#define BLE_MESH_ADV_DATA_SIZE 29 +#define BLE_MESH_ADV_DATA_SIZE 29 /* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ -#define BLE_MESH_ADV_USER_DATA_SIZE 4 +#define BLE_MESH_ADV_USER_DATA_SIZE 4 -#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) typedef struct bt_mesh_msg { - bool relay; /* Flag indicates if the packet is a relayed one */ - void *arg; /* Pointer to the struct net_buf */ + bool relay; /* Flag indicates if the packet is a relayed one */ + void *arg; /* Pointer to the struct net_buf */ uint16_t src; /* Source address for relay packets */ uint16_t dst; /* Destination address for relay packets */ uint32_t timestamp; /* Timestamp recorded when the relay packet is posted to queue */ @@ -39,6 +39,7 @@ enum bt_mesh_adv_type { BLE_MESH_ADV_BEACON, BLE_MESH_ADV_URI, BLE_MESH_ADV_BLE, + BLE_MESH_ADV_PROXY_SOLIC, }; struct bt_mesh_adv { @@ -52,9 +53,7 @@ struct bt_mesh_adv { typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id); -/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */ -struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout); +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int32_t timeout); typedef enum { BLE_MESH_BUF_REF_EQUAL, @@ -68,18 +67,20 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, bt_mesh_adv_alloc_t get_id, enum bt_mesh_adv_type type, - uint8_t xmit, int32_t timeout); + int32_t timeout); void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool); -void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, + const struct bt_mesh_send_cb *cb, void *cb_data); -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, uint8_t xmit, - int32_t timeout); +struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout); -void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data, uint16_t src, uint16_t dst); +void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, + uint16_t src, uint16_t dst, + const struct bt_mesh_send_cb *cb, + void *cb_data); uint16_t bt_mesh_get_stored_relay_count(void); diff --git a/components/bt/esp_ble_mesh/core/beacon.c b/components/bt/esp_ble_mesh/core/beacon.c index ac0a559308..488a3c5f6d 100644 --- a/components/bt/esp_ble_mesh/core/beacon.c +++ b/components/bt/esp_ble_mesh/core/beacon.c @@ -11,41 +11,45 @@ #include #include "adv.h" +#include "scan.h" #include "mesh.h" -#include "prov_node.h" #include "crypto.h" #include "beacon.h" #include "access.h" #include "foundation.h" #include "proxy_client.h" #include "mesh/main.h" +#include "prov_common.h" +#include "prov_node.h" #include "prov_pvnr.h" #include "pvnr_mgmt.h" +#include "mesh/common.h" + +#include "mesh_v1.1/utils.h" #if defined(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) -#define UNPROVISIONED_INTERVAL K_SECONDS(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) +#define UNPROV_BEACON_INTERVAL K_SECONDS(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) #else -#define UNPROVISIONED_INTERVAL K_SECONDS(5) +#define UNPROV_BEACON_INTERVAL K_SECONDS(5) #endif -#define PROVISIONED_INTERVAL K_SECONDS(10) -#define BEACON_TYPE_UNPROVISIONED 0x00 -#define BEACON_TYPE_SECURE 0x01 +#define SECURE_BEACON_INTERVAL K_SECONDS(10) /* 3 transmissions, 20ms interval */ #define UNPROV_XMIT BLE_MESH_TRANSMIT(2, 20) /* 1 transmission, 20ms interval */ -#define PROV_XMIT BLE_MESH_TRANSMIT(0, 20) +#define SNB_XMIT BLE_MESH_TRANSMIT(0, 20) -#define SNB_NET_IDX_SET(_val) ((void *)((uint32_t)(_val))) -#define SNB_NET_IDX_GET(_ptr) ((uint32_t)(_ptr)) +/* For a device, using the snb_timer when sending Unprovisioned Device Beacon; + * For a node, using the snb_timer when sending Secure Network Beacon. + */ +static struct k_delayed_work snb_timer; -static struct k_delayed_work beacon_timer; - -static struct bt_mesh_subnet *cache_check(uint8_t data[21]) +struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) { size_t subnet_size = 0U; + uint8_t *cache = NULL; int i = 0; subnet_size = bt_mesh_rx_netkey_size(); @@ -57,7 +61,13 @@ static struct bt_mesh_subnet *cache_check(uint8_t data[21]) continue; } - if (!memcmp(sub->beacon_cache, data, 21)) { +#if CONFIG_BLE_MESH_PRIVATE_BEACON + cache = private_beacon ? sub->mpb_cache : sub->snb_cache; +#else + cache = sub->snb_cache; +#endif + + if (!memcmp(cache, data, 21)) { return sub; } } @@ -65,19 +75,26 @@ static struct bt_mesh_subnet *cache_check(uint8_t data[21]) return NULL; } -static void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub) +void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub, bool private_beacon) { - memcpy(sub->beacon_cache, data, 21); +#if CONFIG_BLE_MESH_PRIVATE_BEACON + if (private_beacon) { + memcpy(sub->mpb_cache, data, 21); + } else +#endif + { + memcpy(sub->snb_cache, data, 21); + } } -static void beacon_complete(int err, void *user_data) +static void secure_beacon_complete(int err, void *user_data) { struct bt_mesh_subnet *sub = NULL; uint16_t net_idx = BLE_MESH_KEY_UNUSED; BT_DBG("err %d", err); - net_idx = (uint16_t)SNB_NET_IDX_GET(user_data); + net_idx = (uint16_t)NET_IDX_GET(user_data); /* For node, directly updating the "beacon_sent" timestamp is fine, * since the subnet is pre-allocated. @@ -86,20 +103,14 @@ static void beacon_complete(int err, void *user_data) * a chance that the subnet is removed just before the completion of * sending the Secure Network Beacon. */ - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { - sub = bt_mesh_subnet_get(net_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && - bt_mesh_is_provisioner_en()) { - sub = bt_mesh_provisioner_subnet_get(net_idx); - } - + sub = bt_mesh_subnet_get(net_idx); if (sub) { - sub->beacon_sent = k_uptime_get_32(); + sub->snb_sent = k_uptime_get_32(); } } -void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf) +void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf) { uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; @@ -122,26 +133,21 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, net_buf_simple_add_mem(buf, sub->auth, 8); - BT_INFO("net_idx 0x%03x iv_index 0x%08x flags 0x%02x", + BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x flags 0x%02x", sub->net_idx, bt_mesh.iv_index, flags); - BT_DBG("NetID %s Auth %s", bt_hex(keys->net_id, 8), + BT_DBG("SNB: NetID %s Auth %s", bt_hex(keys->net_id, 8), bt_hex(sub->auth, 8)); } -/* If the interval has passed or is within 5 seconds from now send a beacon */ -#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - K_SECONDS(5)) - static int secure_beacon_send(void) { static const struct bt_mesh_send_cb send_cb = { - .end = beacon_complete, + .end = secure_beacon_complete, }; uint32_t now = k_uptime_get_32(); size_t subnet_size = 0U; int i = 0; - BT_DBG("%s", __func__); - subnet_size = bt_mesh_rx_netkey_size(); for (i = 0; i < subnet_size; i++) { @@ -153,128 +159,137 @@ static int secure_beacon_send(void) continue; } - time_diff = now - sub->beacon_sent; + time_diff = now - sub->snb_sent; if (time_diff < K_SECONDS(600) && - time_diff < BEACON_THRESHOLD(sub)) { + time_diff < BEACON_THRESHOLD(sub->snb_last)) { continue; } - /** - * If a node enables the Proxy Client functionality, and it + /* If a node enables the Proxy Client functionality, and it * succeeds to send Secure Network Beacon with GATT bearer, * here we will continue to send Secure Network Beacon of * other subnets. */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) - if (bt_mesh_proxy_client_beacon_send(sub)) { +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + if (bt_mesh_proxy_client_beacon_send(sub, false)) { continue; } #endif - buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, PROV_XMIT, - K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, K_NO_WAIT); if (!buf) { - BT_ERR("Out of beacon buffer"); + BT_ERR("Out of secure beacon buffer"); return -ENOBUFS; } - bt_mesh_beacon_create(sub, &buf->b); + bt_mesh_secure_beacon_create(sub, &buf->b); /* Care should be taken here. Previously the user_data is the * pointer of a subnet. When the device is a Provisioner, its * subnet is created dynamically. If the corresponding subnet * is removed right after the Secure Network Beacon is sent, - * update its "beacon_sent" timestamp in beacon_complete() will - * cause exception. + * update its "snb_sent" timestamp in secure_beacon_complete() + * will cause exception. * Here we use the "net_idx" of the subnet instead. And in the - * beacon_complete(), we will try to get the subnet before - * updating its "beacon_sent" timestamp. + * secure_beacon_complete(), we will try to get the subnet before + * updating its "snb_sent" timestamp. */ - bt_mesh_adv_send(buf, &send_cb, SNB_NET_IDX_SET(sub->net_idx)); + bt_mesh_adv_send(buf, SNB_XMIT, &send_cb, NET_IDX_SET(sub->net_idx)); net_buf_unref(buf); } return 0; } -#if defined(CONFIG_BLE_MESH_NODE) +#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_ADV) static int unprovisioned_beacon_send(void) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - const struct bt_mesh_prov *prov = NULL; - uint8_t uri_hash[16] = { 0 }; + uint8_t uri_hash[16] = {0}; struct net_buf *buf = NULL; uint16_t oob_info = 0U; - BT_DBG("%s", __func__); + if (bt_mesh_prov_get() == NULL) { + BT_ERR("No provisioning context provided"); + return -EINVAL; + } - buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, UNPROV_XMIT, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, K_NO_WAIT); if (!buf) { - BT_ERR("Out of beacon buffer"); + BT_ERR("Out of unprov beacon buffer"); return -ENOBUFS; } - prov = bt_mesh_prov_get(); - net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); - net_buf_add_mem(buf, prov->uuid, 16); + net_buf_add_mem(buf, bt_mesh_prov_get()->uuid, 16); - if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) { - oob_info = prov->oob_info | BLE_MESH_PROV_OOB_URI; + if (bt_mesh_prov_get()->uri && + bt_mesh_s1(bt_mesh_prov_get()->uri, uri_hash) == 0) { + oob_info = bt_mesh_prov_get()->oob_info | BLE_MESH_PROV_OOB_URI; } else { - oob_info = prov->oob_info; + oob_info = bt_mesh_prov_get()->oob_info; } net_buf_add_be16(buf, oob_info); net_buf_add_mem(buf, uri_hash, 4); - bt_mesh_adv_send(buf, NULL, NULL); + bt_mesh_adv_send(buf, UNPROV_XMIT, NULL, NULL); net_buf_unref(buf); - if (prov->uri) { - size_t len; + if (bt_mesh_prov_get()->uri) { + size_t len = 0; - buf = bt_mesh_adv_create(BLE_MESH_ADV_URI, UNPROV_XMIT, - K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_URI, K_NO_WAIT); if (!buf) { BT_ERR("Unable to allocate URI buffer"); return -ENOBUFS; } - len = strlen(prov->uri); + len = strlen(bt_mesh_prov_get()->uri); + if (net_buf_tailroom(buf) < len) { BT_WARN("Too long URI to fit advertising data"); } else { - net_buf_add_mem(buf, prov->uri, len); - bt_mesh_adv_send(buf, NULL, NULL); + net_buf_add_mem(buf, bt_mesh_prov_get()->uri, len); + bt_mesh_adv_send(buf, UNPROV_XMIT, NULL, NULL); } net_buf_unref(buf); } -#endif /* CONFIG_BLE_MESH_PB_ADV */ return 0; } -#else /* CONFIG_BLE_MESH_NODE */ +#else /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_ADV) */ static int unprovisioned_beacon_send(void) { return 0; } -#endif /* CONFIG_BLE_MESH_NODE */ +#endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_ADV) */ -static void update_beacon_observation(void) +void update_beacon_observation(bool private_beacon) { - static bool first_half; + static bool snb_first_half; size_t subnet_size = 0U; int i = 0; /* Observation period is 20 seconds, whereas the beacon timer - * runs every 10 seconds. We process what's happened during the - * window only after the second half. + * runs every 10 seconds. We process what's happened during + * the window only after the second half. */ - first_half = !first_half; - if (first_half) { - return; +#if CONFIG_BLE_MESH_PRB_SRV + static bool mpb_first_half; + + if (private_beacon) { + mpb_first_half = !mpb_first_half; + if (mpb_first_half) { + return; + } + } else +#endif + { + snb_first_half = !snb_first_half; + if (snb_first_half) { + return; + } } subnet_size = bt_mesh_rx_netkey_size(); @@ -286,8 +301,16 @@ static void update_beacon_observation(void) continue; } - sub->beacons_last = sub->beacons_cur; - sub->beacons_cur = 0U; +#if CONFIG_BLE_MESH_PRB_SRV + if (private_beacon) { + sub->mpb_last = sub->mpb_cur; + sub->mpb_cur = 0U; + } else +#endif + { + sub->snb_last = sub->snb_cur; + sub->snb_cur = 0U; + } } } @@ -299,34 +322,31 @@ static bool ready_to_send(void) return false; } -static void beacon_send(struct k_work *work) +static void secure_beacon_send_timeout(struct k_work *work) { /* Don't send anything if we have an active provisioning link */ if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && - IS_ENABLED(CONFIG_BLE_MESH_PROV) && bt_prov_active()) { - k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL); + IS_ENABLED(CONFIG_BLE_MESH_PROV) && bt_mesh_prov_active()) { + k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); return; } - BT_DBG("%s", __func__); - if (ready_to_send()) { - update_beacon_observation(); + update_beacon_observation(false); + secure_beacon_send(); /* Only resubmit if beaconing is still enabled */ - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED || - bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { - k_delayed_work_submit(&beacon_timer, - PROVISIONED_INTERVAL); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED || + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { + k_delayed_work_submit(&snb_timer, SECURE_BEACON_INTERVAL); } } else { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { unprovisioned_beacon_send(); - k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL); + k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); } } - } static void secure_beacon_recv(struct net_buf_simple *buf) @@ -339,12 +359,12 @@ static void secure_beacon_recv(struct net_buf_simple *buf) bool new_key = false; uint8_t flags = 0U; - if (buf->len < 21) { - BT_ERR("Too short secure beacon (len %u)", buf->len); + if (buf->len != 21) { + BT_ERR("Malformed secure beacon (len %u)", buf->len); return; } - sub = cache_check(buf->data); + sub = cache_check(buf->data, false); if (sub) { /* We've seen this beacon before - just update the stats */ goto update_stats; @@ -361,9 +381,9 @@ static void secure_beacon_recv(struct net_buf_simple *buf) BT_DBG("flags 0x%02x id %s iv_index 0x%08x", flags, bt_hex(net_id, 8), iv_index); - sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key); + sub = bt_mesh_subnet_find_with_snb(net_id, flags, iv_index, auth, &new_key); if (!sub) { - BT_DBG("No subnet that matched beacon"); + BT_DBG("No subnet that matched secure beacon"); return; } @@ -372,16 +392,16 @@ static void secure_beacon_recv(struct net_buf_simple *buf) return; } - cache_add(data, sub); + cache_add(data, sub, false); - /* Spec v1.0.1, Section 3.8.4: - * If a node on a primary subnet receives an update on + /* If we have NetKey0 accept initiation only from it. + * + * Spec v1.1, Section 3.8.4: + * If a device on a primary subnet receives an update on * the primary subnet, it shall propagate the IV update - * to all other subnets. If a node on a primary subnet + * to all other subnets. If a device on a primary subnet * receives an IV update on any other subnet, the update * shall be ignored. - * If a node on a primary subnet receives an key update - * on any other subnet, the update shall not be ignored. */ if (bt_mesh_primary_subnet_exist() && sub->net_idx != BLE_MESH_KEY_PRIMARY && @@ -391,12 +411,12 @@ static void secure_beacon_recv(struct net_buf_simple *buf) goto update_stats; } - BT_INFO("net_idx 0x%03x iv_index 0x%08x current iv_index 0x%08x", + BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x current iv_index 0x%08x", sub->net_idx, iv_index, bt_mesh.iv_index); if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && - (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == - BLE_MESH_IV_UPDATE(flags))) { + (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == + BLE_MESH_IV_UPDATE(flags))) { bt_mesh_beacon_ivu_initiator(false); } @@ -412,7 +432,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) kr_change = bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(flags), new_key); if (kr_change) { - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } if (iv_change) { @@ -424,9 +444,9 @@ static void secure_beacon_recv(struct net_buf_simple *buf) } update_stats: - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED && - sub->beacons_cur < 0xff) { - sub->beacons_cur++; + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED && + sub->snb_cur < 0xff) { + sub->snb_cur++; } } @@ -445,14 +465,28 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) switch (type) { case BEACON_TYPE_UNPROVISIONED: BT_DBG("Unprovisioned device beacon received"); + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && - bt_mesh_is_provisioner_en()) { + IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && + bt_mesh_is_provisioner_en()) { bt_mesh_provisioner_unprov_beacon_recv(buf, rssi); } + + if (IS_ENABLED(CONFIG_BLE_MESH_RPR_SRV) && + bt_mesh_is_provisioned()) { + const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); + } break; case BEACON_TYPE_SECURE: secure_beacon_recv(buf); break; +#if CONFIG_BLE_MESH_PRIVATE_BEACON + case BEACON_TYPE_PRIVATE: + bt_mesh_private_beacon_recv(buf); + break; +#endif default: BT_DBG("Unknown beacon type 0x%02x", type); break; @@ -461,13 +495,31 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) void bt_mesh_beacon_init(void) { - k_delayed_work_init(&beacon_timer, beacon_send); + /* secure beacon init */ + if (k_delayed_work_init(&snb_timer, secure_beacon_send_timeout)) { + BT_ERR("Failed to create a snb_timer"); + return; + } + +#if CONFIG_BLE_MESH_PRB_SRV + /* private beacon init */ + if (bt_mesh_private_beacon_timer_init()) { + BT_ERR("Failed to create a mpb_timer"); + return; + } +#endif } #if CONFIG_BLE_MESH_DEINIT void bt_mesh_beacon_deinit(void) { - k_delayed_work_free(&beacon_timer); + /* secure beacon deinit */ + k_delayed_work_free(&snb_timer); + +#if CONFIG_BLE_MESH_PRB_SRV + /* private beacon deinit */ + bt_mesh_private_beacon_timer_free(); +#endif } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -476,20 +528,32 @@ void bt_mesh_beacon_ivu_initiator(bool enable) bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_INITIATOR, enable); if (enable) { - k_work_submit(&beacon_timer.work); - } else if (bt_mesh_beacon_get() == BLE_MESH_BEACON_DISABLED) { - k_delayed_work_cancel(&beacon_timer); + k_delayed_work_submit(&snb_timer, K_NO_WAIT); +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_timer_submit(K_NO_WAIT); + } +#endif + } else { + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_DISABLED) { + k_delayed_work_cancel(&snb_timer); + } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_DISABLED) { + bt_mesh_private_beacon_timer_cancel(); + } +#endif } } -void bt_mesh_beacon_enable(void) +void bt_mesh_secure_beacon_enable(void) { size_t subnet_size = 0U; int i = 0; - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && - !bt_mesh_is_provisioned()) { - k_work_submit(&beacon_timer.work); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && + bt_mesh_is_node() && !bt_mesh_is_provisioned()) { + k_delayed_work_submit(&snb_timer, K_NO_WAIT); return; } @@ -502,18 +566,18 @@ void bt_mesh_beacon_enable(void) continue; } - sub->beacons_last = 0U; - sub->beacons_cur = 0U; + sub->snb_last = 0U; + sub->snb_cur = 0U; - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } - k_work_submit(&beacon_timer.work); + k_delayed_work_submit(&snb_timer, K_NO_WAIT); } -void bt_mesh_beacon_disable(void) +void bt_mesh_secure_beacon_disable(void) { if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { - k_delayed_work_cancel(&beacon_timer); + k_delayed_work_cancel(&snb_timer); } } diff --git a/components/bt/esp_ble_mesh/core/beacon.h b/components/bt/esp_ble_mesh/core/beacon.h index 5e97b4cfe0..764d86f1cb 100644 --- a/components/bt/esp_ble_mesh/core/beacon.h +++ b/components/bt/esp_ble_mesh/core/beacon.h @@ -15,17 +15,28 @@ extern "C" { #endif -void bt_mesh_beacon_enable(void); -void bt_mesh_beacon_disable(void); +#define BEACON_TYPE_UNPROVISIONED 0x00 +#define BEACON_TYPE_SECURE 0x01 +#define BEACON_TYPE_PRIVATE 0x02 + +#define NET_IDX_SET(_val) ((void *)((uint32_t)(_val))) +#define NET_IDX_GET(_ptr) ((uint32_t)(_ptr)) + +/* If the interval has passed or is within 5 seconds from now send a beacon */ +#define BEACON_THRESHOLD(last) (K_SECONDS(10 * ((last) + 1)) - K_SECONDS(5)) + +void bt_mesh_secure_beacon_enable(void); +void bt_mesh_secure_beacon_disable(void); void bt_mesh_beacon_ivu_initiator(bool enable); void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi); -void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf); +void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf); void bt_mesh_beacon_init(void); + void bt_mesh_beacon_deinit(void); #ifdef __cplusplus 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 c9abf821ad..a9908b7250 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -18,7 +18,9 @@ #include "osi/future.h" #include "device/controller.h" +#if CONFIG_MBEDTLS_HARDWARE_AES #include "mbedtls/aes.h" +#endif #include #include @@ -27,6 +29,9 @@ #include "mesh/adapter.h" #include "mesh/common.h" #include "prov_pvnr.h" +#include "net.h" + +#include "mesh_v1.1/utils.h" struct bt_mesh_dev bt_mesh_dev; @@ -48,14 +53,15 @@ struct bt_mesh_dev bt_mesh_dev; /* P-256 Variables */ static uint8_t bt_mesh_public_key[64]; -static BT_OCTET32 bt_mesh_private_key; +static uint8_t bt_mesh_private_key[32]; /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data); #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) /* Using UUID with a fixed pattern 0x96 for BLE Mesh GATT Proxy Server */ #define BLE_MESH_GATTS_APP_UUID_BYTE 0x96 /* the gatt database list to save the attribute table */ @@ -65,7 +71,7 @@ static sys_slist_t bt_mesh_gatts_db; static struct bt_mesh_conn bt_mesh_gatts_conn[BLE_MESH_MAX_CONN]; static struct bt_mesh_conn_cb *bt_mesh_gatts_conn_cb; static tBTA_GATTS_IF bt_mesh_gatts_if; -static BD_ADDR bt_mesh_gatts_addr; +static uint8_t bt_mesh_gatts_addr[BLE_MESH_ADDR_LEN]; static uint16_t svc_handle, char_handle; static future_t *future_mesh; @@ -74,7 +80,8 @@ static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t hand #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) /* Using UUID with a fixed pattern 0x97 for BLE Mesh GATT Proxy Client */ #define BLE_MESH_GATTC_APP_UUID_BYTE 0x97 static struct gattc_prov_info { @@ -176,14 +183,14 @@ static bool valid_adv_param(const struct bt_mesh_adv_param *param) if (!(param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) { #if BLE_MESH_DEV if (bt_mesh_dev.hci_version < BLE_MESH_HCI_VERSION_5_0 && - param->interval_min < 0x00a0) { + param->interval_min < 0x00a0) { return false; } #endif } if (param->interval_min > param->interval_max || - param->interval_min < 0x0020 || param->interval_max > 0x4000) { + param->interval_min < 0x0020 || param->interval_max > 0x4000) { return false; } @@ -234,12 +241,12 @@ static void start_adv_completed_cb(uint8_t status) static bool valid_scan_param(const struct bt_mesh_scan_param *param) { if (param->type != BLE_MESH_SCAN_PASSIVE && - param->type != BLE_MESH_SCAN_ACTIVE) { + param->type != BLE_MESH_SCAN_ACTIVE) { return false; } if (param->filter_dup != BLE_MESH_SCAN_FILTER_DUP_DISABLE && - param->filter_dup != BLE_MESH_SCAN_FILTER_DUP_ENABLE) { + param->filter_dup != BLE_MESH_SCAN_FILTER_DUP_ENABLE) { return false; } @@ -261,7 +268,7 @@ static bool valid_scan_param(const struct bt_mesh_scan_param *param) static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t filter_dup, uint8_t scan_fil_policy) { - UINT8 addr_type_own = BLE_MESH_ADDR_PUBLIC; /* Currently only support Public Address */ + uint8_t addr_type_own = BLE_MESH_ADDR_PUBLIC; /* Currently only support Public Address */ tGATT_IF client_if = 0xFF; /* Default GATT interface id */ BLE_MESH_BTM_CHECK_STATUS( @@ -297,7 +304,7 @@ static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARC net_buf_simple_init_with_data(&buf, p_data->inq_res.p_eir, p_data->inq_res.adv_data_len); if (bt_mesh_scan_dev_found_cb) { - bt_mesh_scan_dev_found_cb(&addr, p_data->inq_res.rssi, p_data->inq_res.ble_evt_type, &buf); + bt_mesh_scan_dev_found_cb(&addr, p_data->inq_res.rssi, p_data->inq_res.ble_evt_type, &buf, p_data->inq_res.scan_rsp_len); } } else if (event == BTA_DM_INQ_CMPL_EVT) { BT_INFO("Scan completed, number of scan response %d", p_data->inq_cmpl.num_resps); @@ -360,7 +367,13 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, } else { adv_type = BLE_MESH_ADV_NONCONN_IND; } - addr_type_own = BLE_MESH_ADDR_PUBLIC; /* Currently only support Public Address */ + +#if CONFIG_BLE_MESH_PRB_SRV + addr_type_own = bt_mesh_private_beacon_update_addr_type(ad); +#else + addr_type_own = BLE_MESH_ADDR_PUBLIC; +#endif + channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; adv_fil_pol = BLE_MESH_AP_SCAN_CONN_ALL; p_start_adv_cb = start_adv_completed_cb; @@ -502,7 +515,7 @@ int bt_le_update_white_list(struct bt_mesh_white_list *wl) } if (BTM_BleUpdateAdvWhitelist(wl->add_remove, wl->remote_bda, - wl->addr_type, (tBTM_UPDATE_WHITELIST_CBACK *)wl->update_wl_comp_cb) == false) { + wl->addr_type, (tBTM_UPDATE_WHITELIST_CBACK *)wl->update_wl_comp_cb) == false) { return -EIO; } @@ -511,7 +524,7 @@ int bt_le_update_white_list(struct bt_mesh_white_list *wl) #endif #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) { switch (event) { @@ -740,7 +753,7 @@ struct gatts_incl { uint16_t start_handle; uint16_t end_handle; uint16_t uuid16; -} __packed; +} __attribute__((packed)); ssize_t bt_mesh_gatts_attr_read_included(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, @@ -790,7 +803,7 @@ struct gatts_chrc { uint16_t uuid16; uint8_t uuid[16]; }; -} __packed; +} __attribute__((packed)); ssize_t bt_mesh_gatts_attr_read_chrc(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, @@ -845,8 +858,6 @@ static void bta_uuid_to_bt_mesh_uuid(tBT_UUID *bta_uuid, const struct bt_mesh_uu } else { BT_ERR("Invalid mesh uuid type %d", uuid->type); } - - return; } static int gatts_register(struct bt_mesh_gatt_service *svc) @@ -1099,7 +1110,8 @@ int bt_mesh_gatts_set_local_device_name(const char *name) #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) void bt_mesh_gattc_conn_cb_register(struct bt_mesh_prov_conn_cb *cb) { bt_mesh_gattc_conn_cb = cb; @@ -1117,7 +1129,7 @@ uint8_t bt_mesh_gattc_get_free_conn_count(void) for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if (bt_mesh_gattc_info[i].conn.handle == 0xFFFF && - bt_mesh_gattc_info[i].service_uuid == 0x0000) { + bt_mesh_gattc_info[i].service_uuid == 0x0000) { ++count; } } @@ -1155,13 +1167,13 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) int i; if (!addr || !memcmp(addr->val, zero, BLE_MESH_ADDR_LEN) || - (addr->type > BLE_ADDR_RANDOM)) { + (addr->type > BLE_ADDR_RANDOM)) { BT_ERR("Invalid remote address"); return -EINVAL; } if (service_uuid != BLE_MESH_UUID_MESH_PROV_VAL && - service_uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { + service_uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { BT_ERR("Invalid service uuid 0x%04x", service_uuid); return -EINVAL; } @@ -1178,7 +1190,7 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) /* Find empty element in queue to store device info */ for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if ((bt_mesh_gattc_info[i].conn.handle == 0xFFFF) && - (bt_mesh_gattc_info[i].service_uuid == 0x0000)) { + (bt_mesh_gattc_info[i].service_uuid == 0x0000)) { memcpy(bt_mesh_gattc_info[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); bt_mesh_gattc_info[i].addr.type = addr->type; /* Service to be found after exchanging mtu size */ @@ -1281,7 +1293,6 @@ void bt_mesh_gattc_disconnect(struct bt_mesh_conn *conn) } BT_ERR("Conn %p not found", conn); - return; } /** Mesh Provisioning Service: 0x1827 @@ -1306,7 +1317,7 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) BT_DBG("BTA_GATTC_REG_EVT"); if (p_data->reg_oper.app_uuid.len == LEN_UUID_128 && - !memcmp(p_data->reg_oper.app_uuid.uu.uuid128, uuid, 16)) { + !memcmp(p_data->reg_oper.app_uuid.uu.uuid128, uuid, 16)) { bt_mesh_gattc_if = p_data->reg_oper.client_if; BT_DBG("bt_mesh_gattc_if is %d", bt_mesh_gattc_if); } @@ -1388,7 +1399,8 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) BTA_GATTC_GetDBSizeByType(p_data->search_cmpl.conn_id, BTGATT_DB_CHARACTERISTIC, bt_mesh_gattc_info[i].start_handle, bt_mesh_gattc_info[i].end_handle, BTA_GATTC_INVALID_HANDLE, &count); - if (count != 2) { + if (count != 3 && count != 2) { + BT_ERR("Invalid characteristic num(%d) within Mesh Provisioning/Proxy Service", count); bt_mesh_gattc_disconnect(conn); return; } @@ -1562,8 +1574,8 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) } if (memcmp(bt_mesh_gattc_info[i].addr.val, p_data->notify.bda, BLE_MESH_ADDR_LEN) || - bt_mesh_gattc_info[i].data_out_handle != p_data->notify.handle || - p_data->notify.is_notify == false) { + bt_mesh_gattc_info[i].data_out_handle != p_data->notify.handle || + p_data->notify.is_notify == false) { BT_ERR("Notification error"); bt_mesh_gattc_disconnect(conn); return; @@ -1572,7 +1584,8 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROV_VAL) { if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->prov_notify != NULL) { len = bt_mesh_gattc_conn_cb->prov_notify(&bt_mesh_gattc_info[i].conn, - p_data->notify.value, p_data->notify.len); + p_data->notify.value, + p_data->notify.len); if (len < 0) { BT_ERR("prov_notify failed"); bt_mesh_gattc_disconnect(conn); @@ -1582,7 +1595,8 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) } else if (bt_mesh_gattc_info[i].service_uuid == BLE_MESH_UUID_MESH_PROXY_VAL) { if (bt_mesh_gattc_conn_cb != NULL && bt_mesh_gattc_conn_cb->proxy_notify != NULL) { len = bt_mesh_gattc_conn_cb->proxy_notify(&bt_mesh_gattc_info[i].conn, - p_data->notify.value, p_data->notify.len); + p_data->notify.value, + p_data->notify.len); if (len < 0) { BT_ERR("proxy_notify failed"); bt_mesh_gattc_disconnect(conn); @@ -1721,14 +1735,15 @@ void bt_mesh_gatt_init(void) BTA_GATT_SetLocalMTU(GATT_DEF_BLE_MTU_SIZE); #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER tBT_UUID gatts_app_uuid = {LEN_UUID_128, {0}}; memset(&gatts_app_uuid.uu.uuid128, BLE_MESH_GATTS_APP_UUID_BYTE, LEN_UUID_128); BTA_GATTS_AppRegister(&gatts_app_uuid, bt_mesh_bta_gatts_cb); #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) tBT_UUID gattc_app_uuid = {LEN_UUID_128, {0}}; for (int i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { bt_mesh_gattc_info[i].conn.handle = 0xFFFF; @@ -1744,7 +1759,7 @@ void bt_mesh_gatt_init(void) void bt_mesh_gatt_deinit(void) { #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER BTA_GATTS_AppDeregister(bt_mesh_gatts_if); memset(bt_mesh_gatts_addr, 0, BLE_MESH_ADDR_LEN); bt_mesh_gatts_if = 0U; @@ -1753,7 +1768,8 @@ void bt_mesh_gatt_deinit(void) #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) BTA_GATTC_AppDeregister(bt_mesh_gattc_if); bt_mesh_gattc_if = 0U; for (int i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { @@ -1774,8 +1790,6 @@ void bt_mesh_gatt_deinit(void) void bt_mesh_adapt_init(void) { - BT_DBG("%s", __func__); - /* initialization of P-256 parameters */ p_256_init_curve(KEY_LENGTH_DWORDS_P256); @@ -1795,7 +1809,7 @@ void bt_mesh_set_private_key(const uint8_t pri_key[32]) const uint8_t *bt_mesh_pub_key_get(void) { - BT_OCTET32 private_key = {0}; + uint8_t private_key[32] = {0}; Point public_key = {0}; if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { @@ -1842,17 +1856,17 @@ bool bt_mesh_check_public_key(const uint8_t key[64]) return ECC_CheckPointIsInElliCur_P256((Point *)&check); } -int bt_mesh_dh_key_gen(const uint8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, const uint8_t idx) +int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) { - BT_OCTET32 private_key = {0}; + uint8_t private_key[32] = {0}; Point peer_pub_key = {0}; Point new_pub_key = {0}; BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, BT_OCTET32_LEN)); memcpy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); - memcpy(peer_pub_key.x, remote_pk, BT_OCTET32_LEN); - memcpy(peer_pub_key.y, &remote_pk[BT_OCTET32_LEN], BT_OCTET32_LEN); + memcpy(peer_pub_key.x, remote_pub_key, BT_OCTET32_LEN); + memcpy(peer_pub_key.y, &remote_pub_key[BT_OCTET32_LEN], BT_OCTET32_LEN); BT_DBG("remote public key x = %s", bt_hex(peer_pub_key.x, BT_OCTET32_LEN)); BT_DBG("remote public key y = %s", bt_hex(peer_pub_key.y, BT_OCTET32_LEN)); @@ -1862,9 +1876,7 @@ int bt_mesh_dh_key_gen(const uint8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, cons BT_DBG("new public key x = %s", bt_hex(new_pub_key.x, 32)); BT_DBG("new public key y = %s", bt_hex(new_pub_key.y, 32)); - if (cb != NULL) { - cb((const uint8_t *)new_pub_key.x, idx); - } + memcpy(dhkey, new_pub_key.x, 32); return 0; } @@ -1959,10 +1971,10 @@ int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], return 0; } -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) { - BD_ADDR value = {0}; + uint8_t value[BLE_MESH_ADDR_LEN] = {0}; if ((sub_code > BLE_MESH_EXCEP_LIST_SUB_CODE_CLEAN) || (sub_code < BLE_MESH_EXCEP_LIST_SUB_CODE_CLEAN && diff --git a/components/bt/esp_ble_mesh/core/cfg_cli.c b/components/bt/esp_ble_mesh/core/cfg_cli.c index 023fe43ea6..3aedd3644b 100644 --- a/components/bt/esp_ble_mesh/core/cfg_cli.c +++ b/components/bt/esp_ble_mesh/core/cfg_cli.c @@ -24,7 +24,7 @@ static const bt_mesh_client_op_pair_t cfg_op_pair[] = { { OP_BEACON_GET, OP_BEACON_STATUS }, { OP_BEACON_SET, OP_BEACON_STATUS }, - { OP_DEV_COMP_DATA_GET, OP_DEV_COMP_DATA_STATUS }, + { OP_COMP_DATA_GET, OP_COMP_DATA_STATUS }, { OP_DEFAULT_TTL_GET, OP_DEFAULT_TTL_STATUS }, { OP_DEFAULT_TTL_SET, OP_DEFAULT_TTL_STATUS }, { OP_GATT_PROXY_GET, OP_GATT_PROXY_STATUS }, @@ -73,40 +73,17 @@ static const bt_mesh_client_op_pair_t cfg_op_pair[] = { static bt_mesh_mutex_t cfg_client_lock; -static inline void bt_mesh_cfg_client_mutex_new(void) -{ - if (!cfg_client_lock.mutex) { - bt_mesh_mutex_create(&cfg_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_cfg_client_mutex_free(void) -{ - bt_mesh_mutex_free(&cfg_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_cfg_client_lock(void) -{ - bt_mesh_mutex_lock(&cfg_client_lock); -} - -static inline void bt_mesh_cfg_client_unlock(void) -{ - bt_mesh_mutex_unlock(&cfg_client_lock); -} - static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive configuration status message timeout"); - bt_mesh_cfg_client_lock(); + bt_mesh_mutex_lock(&cfg_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -115,15 +92,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_config_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_CONFIG_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_CONFIG_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_cfg_client_unlock(); - - return; + bt_mesh_mutex_unlock(&cfg_client_lock); } static void cfg_client_recv_status(struct bt_mesh_model *model, @@ -143,7 +119,7 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, buf.data = (uint8_t *)status; buf.len = (uint16_t)len; - bt_mesh_cfg_client_lock(); + bt_mesh_mutex_lock(&cfg_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, &buf, true); if (!node) { @@ -151,7 +127,7 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, } else { switch (node->opcode) { case OP_BEACON_GET: - case OP_DEV_COMP_DATA_GET: + case OP_COMP_DATA_GET: case OP_DEFAULT_TTL_GET: case OP_GATT_PROXY_GET: case OP_RELAY_GET: @@ -213,10 +189,10 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, } } - bt_mesh_cfg_client_unlock(); + bt_mesh_mutex_unlock(&cfg_client_lock); switch (ctx->recv_op) { - case OP_DEV_COMP_DATA_STATUS: { + case OP_COMP_DATA_STATUS: { struct bt_mesh_cfg_comp_data_status *val = status; bt_mesh_free_buf(val->comp_data); break; @@ -649,7 +625,7 @@ static void net_trans_status(struct bt_mesh_model *model, } const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { - { OP_DEV_COMP_DATA_STATUS, 15, comp_data_status }, + { OP_COMP_DATA_STATUS, 15, comp_data_status }, { OP_BEACON_STATUS, 1, beacon_status }, { OP_DEFAULT_TTL_STATUS, 1, ttl_status }, { OP_FRIEND_STATUS, 1, friend_status }, @@ -707,7 +683,7 @@ static int send_msg_with_le16(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_comp_data_get(bt_mesh_client_common_param_t *param, uint8_t page) { - return send_msg_with_u8(param, OP_DEV_COMP_DATA_GET, page); + return send_msg_with_u8(param, OP_COMP_DATA_GET, page); } int bt_mesh_cfg_beacon_get(bt_mesh_client_common_param_t *param) @@ -1264,27 +1240,28 @@ static int cfg_cli_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(config_internal_data_t)); - if (!internal) { - BT_ERR("Allocate memory for Configuration Client internal data fail"); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(cfg_op_pair); - client->op_pair = cfg_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } + internal = bt_mesh_calloc(sizeof(config_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(cfg_op_pair); + client->op_pair = cfg_op_pair; + client->internal_data = internal; + /* Configuration Model security is device-key based */ model->keys[0] = BLE_MESH_KEY_DEV; - bt_mesh_cfg_client_mutex_new(); + bt_mesh_mutex_create(&cfg_client_lock); return 0; } @@ -1319,7 +1296,7 @@ static int cfg_cli_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_cfg_client_mutex_free(); + bt_mesh_mutex_free(&cfg_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index 33d0c8f395..5e77a7a589 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -18,6 +18,7 @@ #include "lpn.h" #include "transport.h" #include "crypto.h" +#include "net.h" #include "access.h" #include "beacon.h" #include "foundation.h" @@ -28,94 +29,17 @@ #include "mesh/main.h" #include "mesh/common.h" -#define DEFAULT_TTL 7 +#include "mesh_v1.1/utils.h" -/* Maximum message length is 384 in BLE Mesh. Here for composition data, - * due to 1 octet opcode and 4 octets TransMIC, 379 octets can be used to - * store device composition data. - */ -#define COMP_DATA_MAX_LEN 379 +#define DEFAULT_TTL 7 static struct bt_mesh_cfg_srv *conf; static struct label labels[CONFIG_BLE_MESH_LABEL_COUNT]; -static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, - bool primary) -{ - struct bt_mesh_model *mod = NULL; - int i; - - if (net_buf_simple_tailroom(buf) < - 4 + (elem->model_count * 2U) + (elem->vnd_model_count * 4U)) { - BT_ERR("Too large device composition"); - return -E2BIG; - } - - net_buf_simple_add_le16(buf, elem->loc); - - net_buf_simple_add_u8(buf, elem->model_count); - net_buf_simple_add_u8(buf, elem->vnd_model_count); - - for (i = 0; i < elem->model_count; i++) { - mod = &elem->models[i]; - net_buf_simple_add_le16(buf, mod->id); - } - - for (i = 0; i < elem->vnd_model_count; i++) { - mod = &elem->vnd_models[i]; - net_buf_simple_add_le16(buf, mod->vnd.company); - net_buf_simple_add_le16(buf, mod->vnd.id); - } - - return 0; -} - -static int comp_get_page_0(struct net_buf_simple *buf) -{ - const struct bt_mesh_comp *comp = NULL; - uint16_t feat = 0U; - int i; - - comp = bt_mesh_comp_get(); - - if (IS_ENABLED(CONFIG_BLE_MESH_RELAY)) { - feat |= BLE_MESH_FEAT_RELAY; - } - - if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { - feat |= BLE_MESH_FEAT_PROXY; - } - - if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { - feat |= BLE_MESH_FEAT_FRIEND; - } - - if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { - feat |= BLE_MESH_FEAT_LOW_POWER; - } - - net_buf_simple_add_le16(buf, comp->cid); - net_buf_simple_add_le16(buf, comp->pid); - net_buf_simple_add_le16(buf, comp->vid); - net_buf_simple_add_le16(buf, CONFIG_BLE_MESH_CRPL); - net_buf_simple_add_le16(buf, feat); - - for (i = 0; i < comp->elem_count; i++) { - int err; - - err = comp_add_elem(buf, &comp->elem[i], i == 0); - if (err) { - return err; - } - } - - return 0; -} - -static void dev_comp_data_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) +static void comp_data_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) { struct net_buf_simple *sdu = NULL; uint8_t page = 0U; @@ -124,23 +48,59 @@ static void dev_comp_data_get(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - page = net_buf_simple_pull_u8(buf); - if (page != 0U) { - BT_WARN("Composition page %u not available", page); - page = 0U; - } + /* TODO: + * + * When an element receives a Config Composition Data Get message with + * the Page field of the message containing a value of a Composition + * Data Page that the node contains, it shall respond with a Config + * Composition Data Status message with the Page field set to the page + * number of the Composition Data and the Data field set to the value + * of the largest portion of the Composition Data Page that fits in the + * Data field. If an element is reported in the Config Composition Data + * Status message, the complete list of models supported by the element + * shall be included in the elements description. If the complete list + * of models does not fit in the Data field, the element shall not be + * reported. + * + * When an element receives a Config Composition Data Get message with + * the Page field of the message containing a reserved page number or a + * page number the node does not support, it shall respond with a Config + * Composition Data Status message with the Page field set to the largest + * page number of the Composition Data that the node supports and that is + * less than the Page field value of the received Config Composition Data + * Get message and with the Data field set to the value of the largest + * portion of the Composition Data Page for that page number that fits in + * the Data field. If an element is reported in a Config Composition Data + * Status message, the complete list of models supported by the element + * shall be included in the elements description. If the complete list of + * models does not fit in the Data field, the element shall not be reported. + */ - sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, COMP_DATA_MAX_LEN)); + page = net_buf_simple_pull_u8(buf); + + /* Check if the page exists, and if not, get the largest one + * which is smaller than this page. + */ + page = bt_mesh_comp_page_check(page, false); + + sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_MAX_PDU_LEN_WITH_SMIC)); if (!sdu) { BT_ERR("%s, Out of memory", __func__); return; } - bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS); - + bt_mesh_model_msg_init(sdu, OP_COMP_DATA_STATUS); net_buf_simple_add_u8(sdu, page); - if (comp_get_page_0(sdu) < 0) { - BT_ERR("Unable to get composition page 0"); + + /* Mesh v1.1 updates: + * If an element is reported in the Config Composition Data + * Status message, the complete list of models supported by + * the element shall be included in the elements description. + * If the complete list of models does not fit in the Data + * field, the element shall not be reported. + */ + if (bt_mesh_get_comp_data(sdu, page, 0, true)) { + BT_ERR("Unable to get composition page 0x%02x", page); bt_mesh_free_buf(sdu); return; } @@ -150,15 +110,14 @@ static void dev_comp_data_get(struct bt_mesh_model *model, } bt_mesh_free_buf(sdu); - return; } static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, struct net_buf_simple *buf, bool *vnd) { - if (buf->len < 4) { - uint16_t id = 0U; + uint16_t company = 0U, id = 0U; + if (buf->len < 4) { id = net_buf_simple_pull_le16(buf); BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); @@ -166,35 +125,17 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, *vnd = false; return bt_mesh_model_find(elem, id); - } else { - uint16_t company = 0U, id = 0U; - - company = net_buf_simple_pull_le16(buf); - id = net_buf_simple_pull_le16(buf); - - BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, - elem->addr); - - *vnd = true; - - return bt_mesh_model_find_vnd(elem, company, id); - } -} - -static bool app_key_is_valid(uint16_t app_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != BLE_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return true; - } } - return false; + company = net_buf_simple_pull_le16(buf); + id = net_buf_simple_pull_le16(buf); + + BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, + elem->addr); + + *vnd = true; + + return bt_mesh_model_find_vnd(elem, company, id); } static bool mod_pub_app_key_bound(struct bt_mesh_model *model, @@ -208,7 +149,7 @@ static bool mod_pub_app_key_bound(struct bt_mesh_model *model, } } - BT_ERR("Appkey(0x%02x) not bound to this model.", app_idx); + BT_ERR("AppKey(0x%02x) not bound to this model", app_idx); return false; } @@ -255,7 +196,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, /* For case MESH/NODE/CFG/MP/BI-03-C, need to check if appkey * is bound to model identified by the ModelIdentifier. */ - if (!bt_mesh_app_key_find(app_idx) || + if (!bt_mesh_app_key_get(app_idx) || !mod_pub_app_key_bound(model, app_idx)) { return STATUS_INVALID_APPKEY; } @@ -293,7 +234,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) BT_DBG("model %p key_idx 0x%03x", model, key_idx); - if (!app_key_is_valid(key_idx)) { + if (!bt_mesh_app_key_get(key_idx)) { return STATUS_INVALID_APPKEY; } @@ -325,7 +266,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); - if (!app_key_is_valid(key_idx)) { + if (!bt_mesh_app_key_get(key_idx)) { return STATUS_INVALID_APPKEY; } @@ -379,7 +320,7 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val return STATUS_INVALID_NETKEY; } - key = bt_mesh_app_key_find(app_idx); + key = bt_mesh_app_key_get(app_idx); if (update) { if (!key) { return STATUS_INVALID_APPKEY; @@ -403,24 +344,24 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val if (key->updated) { if (memcmp(keys->val, val, 16)) { return STATUS_CANNOT_UPDATE; - } else { - return STATUS_SUCCESS; } + + return STATUS_SUCCESS; } key->updated = true; } else { if (key) { if (key->net_idx == net_idx && - !memcmp(key->keys[0].val, val, 16)) { + !memcmp(key->keys[0].val, val, 16)) { return STATUS_SUCCESS; } if (key->net_idx == net_idx) { return STATUS_IDX_ALREADY_STORED; - } else { - return STATUS_INVALID_NETKEY; } + + return STATUS_INVALID_NETKEY; } key = bt_mesh_app_key_alloc(app_idx); @@ -569,7 +510,7 @@ static void app_key_del(struct bt_mesh_model *model, goto send_status; } - key = bt_mesh_app_key_find(key_app_idx); + key = bt_mesh_app_key_get(key_app_idx); if (!key) { /* Treat as success since the client might have missed a * previous response and is resending the request. @@ -679,7 +620,7 @@ static void beacon_get(struct bt_mesh_model *model, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); - net_buf_simple_add_u8(&msg, bt_mesh_beacon_get()); + net_buf_simple_add_u8(&msg, bt_mesh_secure_beacon_get()); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Beacon Status"); @@ -708,9 +649,9 @@ static void beacon_set(struct bt_mesh_model *model, } if (cfg->beacon) { - bt_mesh_beacon_enable(); + bt_mesh_secure_beacon_enable(); } else { - bt_mesh_beacon_disable(); + bt_mesh_secure_beacon_disable(); } } } else { @@ -719,7 +660,7 @@ static void beacon_set(struct bt_mesh_model *model, } bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); - net_buf_simple_add_u8(&msg, bt_mesh_beacon_get()); + net_buf_simple_add_u8(&msg, bt_mesh_secure_beacon_get()); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Beacon Status"); @@ -818,7 +759,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, } if (!IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) || - bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { goto send_status; } @@ -835,6 +776,23 @@ static void gatt_proxy_set(struct bt_mesh_model *model, cfg->gatt_proxy = buf->data[0]; +#if CONFIG_BLE_MESH_PRB_SRV + /* If the value of the GATT Proxy state of the node is 0x01 (see Table 4.21), + * then the value of the Private GATT Proxy state shall be Disable (0x00). + */ + if (buf->data[0] == BLE_MESH_GATT_PROXY_ENABLED) { + bt_mesh_disable_private_gatt_proxy(); + } +#endif + +#if CONFIG_BLE_MESH_DF_SRV + /* If the value of the GATT Proxy state of the node is 0x00, + * then the value of the directed proxy state shall be 0x00, + * directed proxy use directed default shall be 0x02. + */ + bt_mesh_disable_directed_proxy_state(ctx->net_idx); +#endif + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_cfg(); } @@ -1464,7 +1422,8 @@ static void mod_sub_add(struct bt_mesh_model *model, goto send_status; } - BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, "SubGroupAddr: 0x%x", sub_addr); for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { @@ -1492,6 +1451,10 @@ send_status: send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_forwarding_node_solicitation(mod, bt_mesh_subnet_get(ctx->net_idx)); +#endif + if (status == STATUS_SUCCESS) { bt_mesh_cfg_server_state_change_t change = {0}; change.cfg_mod_sub_add.elem_addr = elem_addr; @@ -1868,7 +1831,8 @@ static void mod_sub_va_add(struct bt_mesh_model *model, goto send_status; } - BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, "SubVirtualAddr: 0x%x", sub_addr); for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { @@ -2230,11 +2194,24 @@ static void net_key_add(struct bt_mesh_model *model, } /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; bt_mesh_proxy_server_beacon_send(sub); + +#if CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY + /* When the Directed Proxy Server is added to a new subnet, and the + * Proxy_Client_Type parameter for the connection is either Unset or + * Directed_Proxy_Client, then the Directed Proxy Server shall send a + * DIRECTED_PROXY_CAPABILITIES_STATUS message for that subnet to the + * Proxy Client. + */ + if (sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { + bt_mesh_directed_proxy_server_directed_proxy_caps_send(sub, false); + } +#endif + bt_mesh_adv_update(); } else { sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; @@ -2242,6 +2219,12 @@ static void net_key_add(struct bt_mesh_model *model, send_net_key_status(model, ctx, idx, STATUS_SUCCESS); +#if CONFIG_BLE_MESH_DF_SRV + if (bt_mesh_directed_forwarding_sub_init(sub)) { + BT_ERR("Failed to init subnet for directed forward"); + } +#endif + bt_mesh_cfg_server_state_change_t change = {0}; change.cfg_netkey_add.net_idx = sub->net_idx; memcpy(change.cfg_netkey_add.net_key, sub->keys[0].net, 16); @@ -2313,7 +2296,7 @@ static void net_key_update(struct bt_mesh_model *model, bt_mesh_store_subnet(sub); } - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); send_net_key_status(model, ctx, idx, STATUS_SUCCESS); @@ -2326,8 +2309,6 @@ static void net_key_update(struct bt_mesh_model *model, static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) { - BT_DBG("%s", __func__); - cfg->hb_pub.dst = BLE_MESH_ADDR_UNASSIGNED; cfg->hb_pub.count = 0U; cfg->hb_pub.ttl = 0U; @@ -2369,9 +2350,44 @@ static void net_key_del(struct bt_mesh_model *model, goto send_status; } +#if CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY + /* When the Directed Proxy Server is deleted from a subnet, and the + * Proxy_Client_Type parameter for the connection is either Unset or + * Directed_Proxy_Client, then the Directed Proxy Server shall set + * the Use_Directed parameter of the connection for the deleted subnet + * to 0x00, shall set the Proxy_Client_Address_Range parameter of the + * connection for the deleted subnet to the Unassigned value, and shall + * send a DIRECTED_PROXY_CAPABILITIES_STATUS message for the deleted + * subnet to the Proxy Client. + */ + if (sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { + /* Directed Proxy Caps Status must be sent before the subnet is deleted */ + bt_mesh_directed_proxy_server_directed_proxy_caps_send(sub, true); + } + +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_clear_directed_forwarding_table_data(del_idx); +#endif +#endif + bt_mesh_subnet_del(sub, true); status = STATUS_SUCCESS; +#if CONFIG_BLE_MESH_BRC_SRV + /** + * TODO: When a NetKey is deleted from the NetKey List state, + * and subnet bridge functionality is supported, then all the + * Bridging Table state entries with one of the values of the + * NetKeyIndex1 and NetKeyIndex2 fields that matches the NetKey + * Index of the deleted NetKey are removed. + */ + bt_mesh_delete_netkey_in_bridge_table(del_idx); +#endif /* CONFIG_BLE_MESH_BRC_SRV */ + +#if CONFIG_BLE_MESH_RPR_SRV + bt_mesh_rpr_srv_netkey_del(del_idx); +#endif + send_status: send_net_key_status(model, ctx, del_idx, status); @@ -2489,18 +2505,25 @@ static void node_identity_set(struct bt_mesh_model *model, net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); net_buf_simple_add_le16(&msg, idx); net_buf_simple_add_u8(&msg, node_id); - } else { - net_buf_simple_add_u8(&msg, STATUS_SUCCESS); - net_buf_simple_add_le16(&msg, idx); - + } else { if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { - if (node_id) { + if (node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { +#if CONFIG_BLE_MESH_PRB_SRV + /* If the value of the Node Identity state of the node for + * any subnet is 0x01, then the value of the Private Node + * Identity state shall be Disable (0x00). + */ + disable_all_private_node_identity(); +#endif bt_mesh_proxy_server_identity_start(sub); } else { bt_mesh_proxy_server_identity_stop(sub); } bt_mesh_adv_update(); } + + net_buf_simple_add_u8(&msg, STATUS_SUCCESS); + net_buf_simple_add_le16(&msg, idx); net_buf_simple_add_u8(&msg, sub->node_id); } @@ -2570,6 +2593,7 @@ static void mod_app_bind(struct bt_mesh_model *model, status = mod_bind(mod, key_app_idx); + BT_INFO("bind app key %#x on mode %#x", key_app_idx, mod->id); send_status: BT_DBG("status 0x%02x", status); create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, @@ -2805,6 +2829,13 @@ static void friend_set(struct bt_mesh_model *model, if (cfg->frnd == BLE_MESH_FRIEND_DISABLED) { bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); + +#if CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_FRIEND + /* If the value of the friend state of the node is 0x00, + * then the value of the directed friend state shall be 0x00. + */ + bt_mesh_disable_directed_friend_state(ctx->net_idx); +#endif } } @@ -2925,8 +2956,8 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, BT_DBG("%u -> %u", sub->kr_phase, phase); if (phase < BLE_MESH_KR_PHASE_2 || phase > BLE_MESH_KR_PHASE_3 || - (sub->kr_phase == BLE_MESH_KR_NORMAL && - phase == BLE_MESH_KR_PHASE_2)) { + (sub->kr_phase == BLE_MESH_KR_NORMAL && + phase == BLE_MESH_KR_PHASE_2)) { BT_WARN("Prohibited transition %u -> %u", sub->kr_phase, phase); return; } @@ -2941,7 +2972,7 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, bt_mesh_store_subnet(sub); } - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } else if ((sub->kr_phase == BLE_MESH_KR_PHASE_1 || sub->kr_phase == BLE_MESH_KR_PHASE_2) && phase == BLE_MESH_KR_PHASE_3) { @@ -2950,11 +2981,11 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, bt_mesh_net_revoke_keys(sub); if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { - friend_cred_refresh(ctx->net_idx); + IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + friend_cred_refresh(sub->net_idx); } - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS); @@ -2968,35 +2999,39 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, static uint8_t hb_log(uint16_t val) { - if (!val) { + switch (val) { + case 0x0000: return 0x00; - } else if (val == 0xffff) { - return 0xff; - } else { + case 0xFFFF: + return 0xFF; + default: return 32 - __builtin_clz(val); } } static uint8_t hb_pub_count_log(uint16_t val) { - if (!val) { + switch (val) { + case 0x0000: return 0x00; - } else if (val == 0x01) { + case 0x0001: return 0x01; - } else if (val == 0xffff) { - return 0xff; - } else { + case 0xFFFF: + return 0xFF; + default: return 32 - __builtin_clz(val - 1) + 1; } } static uint16_t hb_pwr2(uint8_t val, uint8_t sub) { - if (!val) { + switch (val) { + case 0x00: return 0x0000; - } else if (val == 0xff || val == 0x11) { - return 0xffff; - } else { + case 0x11: + case 0xFF: + return 0xFFFF; + default: return (1 << (val - sub)); } } @@ -3008,7 +3043,7 @@ struct hb_pub_param { uint8_t ttl; uint16_t feat; uint16_t net_idx; -} __packed; +} __attribute__((packed)); static void hb_pub_send_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, @@ -3118,7 +3153,7 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, * has been configured for periodic publishing. */ if (param->period_log && param->count_log) { - k_work_submit(&cfg->hb_pub.timer.work); + k_delayed_work_submit(&cfg->hb_pub.timer, K_NO_WAIT); } else { k_delayed_work_cancel(&cfg->hb_pub.timer); } @@ -3137,7 +3172,7 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, */ if (dst != BLE_MESH_ADDR_UNASSIGNED) { if (param->period_log && param->count_log) { - k_work_submit(&cfg->hb_pub.timer.work); + k_delayed_work_submit(&cfg->hb_pub.timer, K_NO_WAIT); } else { k_delayed_work_cancel(&cfg->hb_pub.timer); } @@ -3209,14 +3244,14 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, sub_src, sub_dst, sub_period); if (sub_src != BLE_MESH_ADDR_UNASSIGNED && - !BLE_MESH_ADDR_IS_UNICAST(sub_src)) { + !BLE_MESH_ADDR_IS_UNICAST(sub_src)) { BT_WARN("Prohibited source address"); return; } if (BLE_MESH_ADDR_IS_VIRTUAL(sub_dst) || BLE_MESH_ADDR_IS_RFU(sub_dst) || - (BLE_MESH_ADDR_IS_UNICAST(sub_dst) && - sub_dst != bt_mesh_primary_addr())) { + (BLE_MESH_ADDR_IS_UNICAST(sub_dst) && + sub_dst != bt_mesh_primary_addr())) { BT_WARN("Prohibited destination address"); return; } @@ -3278,53 +3313,53 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, } const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { - { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get }, - { OP_APP_KEY_ADD, 19, app_key_add }, - { OP_APP_KEY_UPDATE, 19, app_key_update }, - { OP_APP_KEY_DEL, 3, app_key_del }, - { OP_APP_KEY_GET, 2, app_key_get }, - { OP_BEACON_GET, 0, beacon_get }, - { OP_BEACON_SET, 1, beacon_set }, - { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, - { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, - { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, - { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, - { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, - { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, - { OP_RELAY_GET, 0, relay_get }, - { OP_RELAY_SET, 2, relay_set }, - { OP_MOD_PUB_GET, 4, mod_pub_get }, - { OP_MOD_PUB_SET, 11, mod_pub_set }, - { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, - { OP_MOD_SUB_ADD, 6, mod_sub_add }, - { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, - { OP_MOD_SUB_DEL, 6, mod_sub_del }, - { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, - { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, - { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, - { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, - { OP_MOD_SUB_GET, 4, mod_sub_get }, - { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, - { OP_NET_KEY_ADD, 18, net_key_add }, - { OP_NET_KEY_UPDATE, 18, net_key_update }, - { OP_NET_KEY_DEL, 2, net_key_del }, - { OP_NET_KEY_GET, 0, net_key_get }, - { OP_NODE_IDENTITY_GET, 2, node_identity_get }, - { OP_NODE_IDENTITY_SET, 3, node_identity_set }, - { OP_MOD_APP_BIND, 6, mod_app_bind }, - { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, - { OP_SIG_MOD_APP_GET, 4, mod_app_get }, - { OP_VND_MOD_APP_GET, 6, mod_app_get }, - { OP_NODE_RESET, 0, node_reset }, - { OP_FRIEND_GET, 0, friend_get }, - { OP_FRIEND_SET, 1, friend_set }, - { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, - { OP_KRP_GET, 2, krp_get }, - { OP_KRP_SET, 3, krp_set }, - { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, - { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, - { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, - { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, + { OP_COMP_DATA_GET, 1, comp_data_get }, + { OP_APP_KEY_ADD, 19, app_key_add }, + { OP_APP_KEY_UPDATE, 19, app_key_update }, + { OP_APP_KEY_DEL, 3, app_key_del }, + { OP_APP_KEY_GET, 2, app_key_get }, + { OP_BEACON_GET, 0, beacon_get }, + { OP_BEACON_SET, 1, beacon_set }, + { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, + { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, + { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, + { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, + { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, + { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, + { OP_RELAY_GET, 0, relay_get }, + { OP_RELAY_SET, 2, relay_set }, + { OP_MOD_PUB_GET, 4, mod_pub_get }, + { OP_MOD_PUB_SET, 11, mod_pub_set }, + { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, + { OP_MOD_SUB_ADD, 6, mod_sub_add }, + { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, + { OP_MOD_SUB_DEL, 6, mod_sub_del }, + { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, + { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, + { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, + { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, + { OP_MOD_SUB_GET, 4, mod_sub_get }, + { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, + { OP_NET_KEY_ADD, 18, net_key_add }, + { OP_NET_KEY_UPDATE, 18, net_key_update }, + { OP_NET_KEY_DEL, 2, net_key_del }, + { OP_NET_KEY_GET, 0, net_key_get }, + { OP_NODE_IDENTITY_GET, 2, node_identity_get }, + { OP_NODE_IDENTITY_SET, 3, node_identity_set }, + { OP_MOD_APP_BIND, 6, mod_app_bind }, + { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, + { OP_SIG_MOD_APP_GET, 4, mod_app_get }, + { OP_VND_MOD_APP_GET, 6, mod_app_get }, + { OP_NODE_RESET, 0, node_reset }, + { OP_FRIEND_GET, 0, friend_get }, + { OP_FRIEND_SET, 1, friend_set }, + { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, + { OP_KRP_GET, 2, krp_get }, + { OP_KRP_SET, 3, krp_set }, + { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, + { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, + { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, + { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, BLE_MESH_MODEL_OP_END, }; @@ -3376,6 +3411,21 @@ static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) return false; } + if (!IS_ENABLED(CONFIG_BLE_MESH_RELAY)) { + BT_INFO("Relay not supported"); + cfg->relay = BLE_MESH_RELAY_NOT_SUPPORTED; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { + BT_INFO("GATT Proxy not supported"); + cfg->gatt_proxy = BLE_MESH_GATT_PROXY_NOT_SUPPORTED; + } + + if (!IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + BT_INFO("Friend not supported"); + cfg->frnd = BLE_MESH_FRIEND_NOT_SUPPORTED; + } + return true; } @@ -3489,8 +3539,6 @@ void bt_mesh_cfg_reset(bool store) struct bt_mesh_cfg_srv *cfg = conf; int i; - BT_DBG("%s", __func__); - if (!cfg) { return; } @@ -3589,13 +3637,13 @@ uint8_t bt_mesh_relay_retransmit_get(void) return 0; } -uint8_t bt_mesh_beacon_get(void) +uint8_t bt_mesh_secure_beacon_get(void) { if (conf) { return conf->beacon; } - return BLE_MESH_BEACON_DISABLED; + return BLE_MESH_SECURE_BEACON_DISABLED; } uint8_t bt_mesh_gatt_proxy_get(void) diff --git a/components/bt/esp_ble_mesh/core/crypto.c b/components/bt/esp_ble_mesh/core/crypto.c index 3f1d18b703..9b762fb5ed 100644 --- a/components/bt/esp_ble_mesh/core/crypto.c +++ b/components/bt/esp_ble_mesh/core/crypto.c @@ -14,11 +14,16 @@ #include #include #include +#include +#include #include "crypto.h" +#include "mesh/config.h" #include "mesh/common.h" #include "mesh/adapter.h" +#include "mesh_v1.1/utils.h" + #define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) @@ -512,7 +517,7 @@ static int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], return 0; } -#if defined(CONFIG_BLE_MESH_PROXY) +#if CONFIG_BLE_MESH_PROXY static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, uint32_t iv_index) { @@ -538,7 +543,7 @@ static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, /* IV Index */ sys_put_be32(iv_index, &nonce[9]); } -#endif /* PROXY */ +#endif /* CONFIG_BLE_MESH_PROXY */ static void create_net_nonce(uint8_t nonce[13], const uint8_t *pdu, uint32_t iv_index) @@ -593,7 +598,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, } int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, - uint32_t iv_index, bool proxy) + uint32_t iv_index, bool proxy, bool proxy_solic) { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13] = {0}; @@ -603,15 +608,22 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, mic_len); BT_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); -#if defined(CONFIG_BLE_MESH_PROXY) +#if CONFIG_BLE_MESH_PROXY if (proxy) { - create_proxy_nonce(nonce, buf->data, iv_index); +#if CONFIG_BLE_MESH_PROXY_SOLIC + if (proxy_solic) { + bt_mesh_create_proxy_solic_nonce(nonce, buf->data, iv_index); + } else +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ + { + create_proxy_nonce(nonce, buf->data, iv_index); + } } else { create_net_nonce(nonce, buf->data, iv_index); } -#else +#else /* CONFIG_BLE_MESH_PROXY */ create_net_nonce(nonce, buf->data, iv_index); -#endif +#endif /* CONFIG_BLE_MESH_PROXY */ BT_DBG("Nonce %s", bt_hex(nonce, 13)); @@ -625,7 +637,7 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, } int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, - uint32_t iv_index, bool proxy) + uint32_t iv_index, bool proxy, bool proxy_solic) { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13] = {0}; @@ -634,15 +646,22 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), mic_len); -#if defined(CONFIG_BLE_MESH_PROXY) +#if CONFIG_BLE_MESH_PROXY if (proxy) { - create_proxy_nonce(nonce, buf->data, iv_index); +#if CONFIG_BLE_MESH_PROXY_SOLIC + if (proxy_solic) { + bt_mesh_create_proxy_solic_nonce(nonce, buf->data, iv_index); + } else +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ + { + create_proxy_nonce(nonce, buf->data, iv_index); + } } else { create_net_nonce(nonce, buf->data, iv_index); } -#else +#else /* CONFIG_BLE_MESH_PROXY */ create_net_nonce(nonce, buf->data, iv_index); -#endif +#endif /* CONFIG_BLE_MESH_PROXY */ BT_DBG("Nonce %s", bt_hex(nonce, 13)); @@ -849,9 +868,9 @@ int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13], } #endif -int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[8], uint32_t iv_index, - uint8_t auth[8]) +int bt_mesh_secure_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, + const uint8_t net_id[8], uint32_t iv_index, + uint8_t auth[8]) { uint8_t msg[13] = {0}, tmp[16] = {0}; int err = 0; diff --git a/components/bt/esp_ble_mesh/core/crypto.h b/components/bt/esp_ble_mesh/core/crypto.h index 2039a3e312..69627c956b 100644 --- a/components/bt/esp_ble_mesh/core/crypto.h +++ b/components/bt/esp_ble_mesh/core/crypto.h @@ -70,8 +70,8 @@ static inline int bt_mesh_identity_key(const uint8_t net_key[16], return bt_mesh_id128(net_key, "nkik", identity_key); } -static inline int bt_mesh_beacon_key(const uint8_t net_key[16], - uint8_t beacon_key[16]) +static inline int bt_mesh_secure_beacon_key(const uint8_t net_key[16], + uint8_t beacon_key[16]) { return bt_mesh_id128(net_key, "nkbk", beacon_key); } @@ -80,6 +80,10 @@ int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, const uint8_t net_id[8], uint32_t iv_index, uint8_t auth[8]); +int bt_mesh_secure_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, + const uint8_t net_id[8], uint32_t iv_index, + uint8_t auth[8]); + static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) { return bt_mesh_k4(app_key, app_id); @@ -133,10 +137,10 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, const uint8_t privacy_key[16]); int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, - uint32_t iv_index, bool proxy); + uint32_t iv_index, bool proxy, bool proxy_solic); int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, - uint32_t iv_index, bool proxy); + uint32_t iv_index, bool proxy, bool proxy_solic); int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, struct net_buf_simple *buf, const uint8_t *ad, diff --git a/components/bt/esp_ble_mesh/core/fast_prov.c b/components/bt/esp_ble_mesh/core/fast_prov.c index d00cd2aa1f..049a12bb43 100644 --- a/components/bt/esp_ble_mesh/core/fast_prov.c +++ b/components/bt/esp_ble_mesh/core/fast_prov.c @@ -9,6 +9,7 @@ #include "mesh.h" #include "mesh/common.h" +#include "mesh/main.h" #include "access.h" #include "beacon.h" #include "foundation.h" @@ -24,16 +25,27 @@ const uint8_t *bt_mesh_fast_prov_dev_key_get(uint16_t dst) { + const uint8_t *key = NULL; + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { BT_ERR("Invalid unicast address 0x%04x", dst); return NULL; } - if (dst == bt_mesh_primary_addr()) { + if (bt_mesh_is_provisioner_en() == false) { return bt_mesh.dev_key; } - return bt_mesh_provisioner_dev_key_get(dst); + /* For fast provisioning, try to find the DevKey from + * the database firstly. If the dst is not in the DB, + * then we will directly use the DevKey. + */ + key = bt_mesh_provisioner_dev_key_get(dst); + if (key) { + return key; + } + + return bt_mesh.dev_key; } struct bt_mesh_subnet *bt_mesh_fast_prov_subnet_get(uint16_t net_idx) @@ -153,8 +165,8 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) } if (action == ACTION_ENTER) { - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_disable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_disable(); } if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_enable(); @@ -167,8 +179,8 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_disable(); } - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_enable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_enable(); } bt_mesh_atomic_and(bt_mesh.flags, ~(BIT(BLE_MESH_PROVISIONER) | BIT(BLE_MESH_VALID_PROV))); bt_mesh_provisioner_fast_prov_enable(false); diff --git a/components/bt/esp_ble_mesh/core/foundation.h b/components/bt/esp_ble_mesh/core/foundation.h index 1d764aa959..53b70f6980 100644 --- a/components/bt/esp_ble_mesh/core/foundation.h +++ b/components/bt/esp_ble_mesh/core/foundation.h @@ -15,111 +15,241 @@ extern "C" { #endif -#define OP_APP_KEY_ADD BLE_MESH_MODEL_OP_1(0x00) -#define OP_APP_KEY_UPDATE BLE_MESH_MODEL_OP_1(0x01) -#define OP_DEV_COMP_DATA_STATUS BLE_MESH_MODEL_OP_1(0x02) -#define OP_MOD_PUB_SET BLE_MESH_MODEL_OP_1(0x03) -#define OP_HEALTH_CURRENT_STATUS BLE_MESH_MODEL_OP_1(0x04) -#define OP_HEALTH_FAULT_STATUS BLE_MESH_MODEL_OP_1(0x05) -#define OP_HEARTBEAT_PUB_STATUS BLE_MESH_MODEL_OP_1(0x06) -#define OP_APP_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x00) -#define OP_APP_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x01) -#define OP_APP_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x02) -#define OP_APP_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x03) -#define OP_ATTENTION_GET BLE_MESH_MODEL_OP_2(0x80, 0x04) -#define OP_ATTENTION_SET BLE_MESH_MODEL_OP_2(0x80, 0x05) -#define OP_ATTENTION_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x06) -#define OP_ATTENTION_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x07) -#define OP_DEV_COMP_DATA_GET BLE_MESH_MODEL_OP_2(0x80, 0x08) -#define OP_BEACON_GET BLE_MESH_MODEL_OP_2(0x80, 0x09) -#define OP_BEACON_SET BLE_MESH_MODEL_OP_2(0x80, 0x0a) -#define OP_BEACON_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0b) -#define OP_DEFAULT_TTL_GET BLE_MESH_MODEL_OP_2(0x80, 0x0c) -#define OP_DEFAULT_TTL_SET BLE_MESH_MODEL_OP_2(0x80, 0x0d) -#define OP_DEFAULT_TTL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0e) -#define OP_FRIEND_GET BLE_MESH_MODEL_OP_2(0x80, 0x0f) -#define OP_FRIEND_SET BLE_MESH_MODEL_OP_2(0x80, 0x10) -#define OP_FRIEND_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x11) -#define OP_GATT_PROXY_GET BLE_MESH_MODEL_OP_2(0x80, 0x12) -#define OP_GATT_PROXY_SET BLE_MESH_MODEL_OP_2(0x80, 0x13) -#define OP_GATT_PROXY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x14) -#define OP_KRP_GET BLE_MESH_MODEL_OP_2(0x80, 0x15) -#define OP_KRP_SET BLE_MESH_MODEL_OP_2(0x80, 0x16) -#define OP_KRP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x17) -#define OP_MOD_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x18) -#define OP_MOD_PUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x19) -#define OP_MOD_PUB_VA_SET BLE_MESH_MODEL_OP_2(0x80, 0x1a) -#define OP_MOD_SUB_ADD BLE_MESH_MODEL_OP_2(0x80, 0x1b) -#define OP_MOD_SUB_DEL BLE_MESH_MODEL_OP_2(0x80, 0x1c) -#define OP_MOD_SUB_DEL_ALL BLE_MESH_MODEL_OP_2(0x80, 0x1d) -#define OP_MOD_SUB_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x1e) -#define OP_MOD_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x1f) -#define OP_MOD_SUB_VA_ADD BLE_MESH_MODEL_OP_2(0x80, 0x20) -#define OP_MOD_SUB_VA_DEL BLE_MESH_MODEL_OP_2(0x80, 0x21) -#define OP_MOD_SUB_VA_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x22) -#define OP_NET_TRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0x23) -#define OP_NET_TRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0x24) -#define OP_NET_TRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x25) -#define OP_RELAY_GET BLE_MESH_MODEL_OP_2(0x80, 0x26) -#define OP_RELAY_SET BLE_MESH_MODEL_OP_2(0x80, 0x27) -#define OP_RELAY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x28) -#define OP_MOD_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x29) -#define OP_MOD_SUB_LIST BLE_MESH_MODEL_OP_2(0x80, 0x2a) -#define OP_MOD_SUB_GET_VND BLE_MESH_MODEL_OP_2(0x80, 0x2b) -#define OP_MOD_SUB_LIST_VND BLE_MESH_MODEL_OP_2(0x80, 0x2c) -#define OP_LPN_TIMEOUT_GET BLE_MESH_MODEL_OP_2(0x80, 0x2d) -#define OP_LPN_TIMEOUT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x2e) -#define OP_HEALTH_FAULT_CLEAR BLE_MESH_MODEL_OP_2(0x80, 0x2f) -#define OP_HEALTH_FAULT_CLEAR_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x30) -#define OP_HEALTH_FAULT_GET BLE_MESH_MODEL_OP_2(0x80, 0x31) -#define OP_HEALTH_FAULT_TEST BLE_MESH_MODEL_OP_2(0x80, 0x32) -#define OP_HEALTH_FAULT_TEST_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x33) -#define OP_HEALTH_PERIOD_GET BLE_MESH_MODEL_OP_2(0x80, 0x34) -#define OP_HEALTH_PERIOD_SET BLE_MESH_MODEL_OP_2(0x80, 0x35) -#define OP_HEALTH_PERIOD_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x36) -#define OP_HEALTH_PERIOD_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x37) -#define OP_HEARTBEAT_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x38) -#define OP_HEARTBEAT_PUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x39) -#define OP_HEARTBEAT_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x3a) -#define OP_HEARTBEAT_SUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x3b) -#define OP_HEARTBEAT_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3c) -#define OP_MOD_APP_BIND BLE_MESH_MODEL_OP_2(0x80, 0x3d) -#define OP_MOD_APP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3e) -#define OP_MOD_APP_UNBIND BLE_MESH_MODEL_OP_2(0x80, 0x3f) -#define OP_NET_KEY_ADD BLE_MESH_MODEL_OP_2(0x80, 0x40) -#define OP_NET_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x41) -#define OP_NET_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x42) -#define OP_NET_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x43) -#define OP_NET_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x44) -#define OP_NET_KEY_UPDATE BLE_MESH_MODEL_OP_2(0x80, 0x45) -#define OP_NODE_IDENTITY_GET BLE_MESH_MODEL_OP_2(0x80, 0x46) -#define OP_NODE_IDENTITY_SET BLE_MESH_MODEL_OP_2(0x80, 0x47) -#define OP_NODE_IDENTITY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x48) -#define OP_NODE_RESET BLE_MESH_MODEL_OP_2(0x80, 0x49) -#define OP_NODE_RESET_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x4a) -#define OP_SIG_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4b) -#define OP_SIG_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4c) -#define OP_VND_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4d) -#define OP_VND_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4e) +#define OP_APP_KEY_ADD BLE_MESH_MODEL_OP_1(0x00) +#define OP_APP_KEY_UPDATE BLE_MESH_MODEL_OP_1(0x01) +#define OP_COMP_DATA_STATUS BLE_MESH_MODEL_OP_1(0x02) +#define OP_MOD_PUB_SET BLE_MESH_MODEL_OP_1(0x03) +#define OP_HEALTH_CURRENT_STATUS BLE_MESH_MODEL_OP_1(0x04) +#define OP_HEALTH_FAULT_STATUS BLE_MESH_MODEL_OP_1(0x05) +#define OP_HEARTBEAT_PUB_STATUS BLE_MESH_MODEL_OP_1(0x06) +#define OP_APP_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x00) +#define OP_APP_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x01) +#define OP_APP_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x02) +#define OP_APP_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x03) +#define OP_ATTENTION_GET BLE_MESH_MODEL_OP_2(0x80, 0x04) +#define OP_ATTENTION_SET BLE_MESH_MODEL_OP_2(0x80, 0x05) +#define OP_ATTENTION_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x06) +#define OP_ATTENTION_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x07) +#define OP_COMP_DATA_GET BLE_MESH_MODEL_OP_2(0x80, 0x08) +#define OP_BEACON_GET BLE_MESH_MODEL_OP_2(0x80, 0x09) +#define OP_BEACON_SET BLE_MESH_MODEL_OP_2(0x80, 0x0A) +#define OP_BEACON_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0B) +#define OP_DEFAULT_TTL_GET BLE_MESH_MODEL_OP_2(0x80, 0x0C) +#define OP_DEFAULT_TTL_SET BLE_MESH_MODEL_OP_2(0x80, 0x0D) +#define OP_DEFAULT_TTL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x0E) +#define OP_FRIEND_GET BLE_MESH_MODEL_OP_2(0x80, 0x0F) +#define OP_FRIEND_SET BLE_MESH_MODEL_OP_2(0x80, 0x10) +#define OP_FRIEND_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x11) +#define OP_GATT_PROXY_GET BLE_MESH_MODEL_OP_2(0x80, 0x12) +#define OP_GATT_PROXY_SET BLE_MESH_MODEL_OP_2(0x80, 0x13) +#define OP_GATT_PROXY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x14) +#define OP_KRP_GET BLE_MESH_MODEL_OP_2(0x80, 0x15) +#define OP_KRP_SET BLE_MESH_MODEL_OP_2(0x80, 0x16) +#define OP_KRP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x17) +#define OP_MOD_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x18) +#define OP_MOD_PUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x19) +#define OP_MOD_PUB_VA_SET BLE_MESH_MODEL_OP_2(0x80, 0x1A) +#define OP_MOD_SUB_ADD BLE_MESH_MODEL_OP_2(0x80, 0x1B) +#define OP_MOD_SUB_DEL BLE_MESH_MODEL_OP_2(0x80, 0x1C) +#define OP_MOD_SUB_DEL_ALL BLE_MESH_MODEL_OP_2(0x80, 0x1D) +#define OP_MOD_SUB_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x1E) +#define OP_MOD_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x1F) +#define OP_MOD_SUB_VA_ADD BLE_MESH_MODEL_OP_2(0x80, 0x20) +#define OP_MOD_SUB_VA_DEL BLE_MESH_MODEL_OP_2(0x80, 0x21) +#define OP_MOD_SUB_VA_OVERWRITE BLE_MESH_MODEL_OP_2(0x80, 0x22) +#define OP_NET_TRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0x23) +#define OP_NET_TRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0x24) +#define OP_NET_TRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x25) +#define OP_RELAY_GET BLE_MESH_MODEL_OP_2(0x80, 0x26) +#define OP_RELAY_SET BLE_MESH_MODEL_OP_2(0x80, 0x27) +#define OP_RELAY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x28) +#define OP_MOD_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x29) +#define OP_MOD_SUB_LIST BLE_MESH_MODEL_OP_2(0x80, 0x2A) +#define OP_MOD_SUB_GET_VND BLE_MESH_MODEL_OP_2(0x80, 0x2B) +#define OP_MOD_SUB_LIST_VND BLE_MESH_MODEL_OP_2(0x80, 0x2C) +#define OP_LPN_TIMEOUT_GET BLE_MESH_MODEL_OP_2(0x80, 0x2D) +#define OP_LPN_TIMEOUT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x2E) +#define OP_HEALTH_FAULT_CLEAR BLE_MESH_MODEL_OP_2(0x80, 0x2F) +#define OP_HEALTH_FAULT_CLEAR_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x30) +#define OP_HEALTH_FAULT_GET BLE_MESH_MODEL_OP_2(0x80, 0x31) +#define OP_HEALTH_FAULT_TEST BLE_MESH_MODEL_OP_2(0x80, 0x32) +#define OP_HEALTH_FAULT_TEST_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x33) +#define OP_HEALTH_PERIOD_GET BLE_MESH_MODEL_OP_2(0x80, 0x34) +#define OP_HEALTH_PERIOD_SET BLE_MESH_MODEL_OP_2(0x80, 0x35) +#define OP_HEALTH_PERIOD_SET_UNREL BLE_MESH_MODEL_OP_2(0x80, 0x36) +#define OP_HEALTH_PERIOD_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x37) +#define OP_HEARTBEAT_PUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x38) +#define OP_HEARTBEAT_PUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x39) +#define OP_HEARTBEAT_SUB_GET BLE_MESH_MODEL_OP_2(0x80, 0x3A) +#define OP_HEARTBEAT_SUB_SET BLE_MESH_MODEL_OP_2(0x80, 0x3B) +#define OP_HEARTBEAT_SUB_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3C) +#define OP_MOD_APP_BIND BLE_MESH_MODEL_OP_2(0x80, 0x3D) +#define OP_MOD_APP_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x3E) +#define OP_MOD_APP_UNBIND BLE_MESH_MODEL_OP_2(0x80, 0x3F) +#define OP_NET_KEY_ADD BLE_MESH_MODEL_OP_2(0x80, 0x40) +#define OP_NET_KEY_DEL BLE_MESH_MODEL_OP_2(0x80, 0x41) +#define OP_NET_KEY_GET BLE_MESH_MODEL_OP_2(0x80, 0x42) +#define OP_NET_KEY_LIST BLE_MESH_MODEL_OP_2(0x80, 0x43) +#define OP_NET_KEY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x44) +#define OP_NET_KEY_UPDATE BLE_MESH_MODEL_OP_2(0x80, 0x45) +#define OP_NODE_IDENTITY_GET BLE_MESH_MODEL_OP_2(0x80, 0x46) +#define OP_NODE_IDENTITY_SET BLE_MESH_MODEL_OP_2(0x80, 0x47) +#define OP_NODE_IDENTITY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x48) +#define OP_NODE_RESET BLE_MESH_MODEL_OP_2(0x80, 0x49) +#define OP_NODE_RESET_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x4A) +#define OP_SIG_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4B) +#define OP_SIG_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4C) +#define OP_VND_MOD_APP_GET BLE_MESH_MODEL_OP_2(0x80, 0x4D) +#define OP_VND_MOD_APP_LIST BLE_MESH_MODEL_OP_2(0x80, 0x4E) -#define STATUS_SUCCESS 0x00 -#define STATUS_INVALID_ADDRESS 0x01 -#define STATUS_INVALID_MODEL 0x02 -#define STATUS_INVALID_APPKEY 0x03 -#define STATUS_INVALID_NETKEY 0x04 -#define STATUS_INSUFF_RESOURCES 0x05 -#define STATUS_IDX_ALREADY_STORED 0x06 -#define STATUS_NVAL_PUB_PARAM 0x07 -#define STATUS_NOT_SUB_MOD 0x08 -#define STATUS_STORAGE_FAIL 0x09 -#define STATUS_FEAT_NOT_SUPP 0x0a -#define STATUS_CANNOT_UPDATE 0x0b -#define STATUS_CANNOT_REMOVE 0x0c -#define STATUS_CANNOT_BIND 0x0d -#define STATUS_TEMP_STATE_CHG_FAIL 0x0e -#define STATUS_CANNOT_SET 0x0f -#define STATUS_UNSPECIFIED 0x10 -#define STATUS_INVALID_BINDING 0x11 +#define OP_REMOTE_PROV_SCAN_CAPS_GET BLE_MESH_MODEL_OP_2(0x80, 0x4F) +#define OP_REMOTE_PROV_SCAN_CAPS_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x50) +#define OP_REMOTE_PROV_SCAN_GET BLE_MESH_MODEL_OP_2(0x80, 0x51) +#define OP_REMOTE_PROV_SCAN_START BLE_MESH_MODEL_OP_2(0x80, 0x52) +#define OP_REMOTE_PROV_SCAN_STOP BLE_MESH_MODEL_OP_2(0x80, 0x53) +#define OP_REMOTE_PROV_SCAN_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x54) +#define OP_REMOTE_PROV_SCAN_REPORT BLE_MESH_MODEL_OP_2(0x80, 0x55) +#define OP_REMOTE_PROV_EXTENDED_SCAN_START BLE_MESH_MODEL_OP_2(0x80, 0x56) +#define OP_REMOTE_PROV_EXTENDED_SCAN_REPORT BLE_MESH_MODEL_OP_2(0x80, 0x57) +#define OP_REMOTE_PROV_LINK_GET BLE_MESH_MODEL_OP_2(0x80, 0x58) +#define OP_REMOTE_PROV_LINK_OPEN BLE_MESH_MODEL_OP_2(0x80, 0x59) +#define OP_REMOTE_PROV_LINK_CLOSE BLE_MESH_MODEL_OP_2(0x80, 0x5A) +#define OP_REMOTE_PROV_LINK_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x5B) +#define OP_REMOTE_PROV_LINK_REPORT BLE_MESH_MODEL_OP_2(0x80, 0x5C) +#define OP_REMOTE_PROV_PDU_SEND BLE_MESH_MODEL_OP_2(0x80, 0x5D) +#define OP_REMOTE_PROV_PDU_OUTBOUND_REPORT BLE_MESH_MODEL_OP_2(0x80, 0x5E) +#define OP_REMOTE_PROV_PDU_REPORT BLE_MESH_MODEL_OP_2(0x80, 0x5F) + +#define OP_DIRECTED_CONTROL_GET BLE_MESH_MODEL_OP_2(0x80, 0x7B) +#define OP_DIRECTED_CONTROL_SET BLE_MESH_MODEL_OP_2(0x80, 0x7C) +#define OP_DIRECTED_CONTROL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x7D) +#define OP_PATH_METRIC_GET BLE_MESH_MODEL_OP_2(0x80, 0x7E) +#define OP_PATH_METRIC_SET BLE_MESH_MODEL_OP_2(0x80, 0x7F) +#define OP_PATH_METRIC_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x80) +#define OP_DISCOVERY_TABLE_CAPS_GET BLE_MESH_MODEL_OP_2(0x80, 0x81) +#define OP_DISCOVERY_TABLE_CAPS_SET BLE_MESH_MODEL_OP_2(0x80, 0x82) +#define OP_DISCOVERY_TABLE_CAPS_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x83) +#define OP_FORWARDING_TABLE_ADD BLE_MESH_MODEL_OP_2(0x80, 0x84) +#define OP_FORWARDING_TABLE_DEL BLE_MESH_MODEL_OP_2(0x80, 0x85) +#define OP_FORWARDING_TABLE_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x86) +#define OP_FORWARDING_TABLE_DEPS_ADD BLE_MESH_MODEL_OP_2(0x80, 0x87) +#define OP_FORWARDING_TABLE_DEPS_DEL BLE_MESH_MODEL_OP_2(0x80, 0x88) +#define OP_FORWARDING_TABLE_DEPS_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x89) +#define OP_FORWARDING_TABLE_DEPS_GET BLE_MESH_MODEL_OP_2(0x80, 0x8A) +#define OP_FORWARDING_TABLE_DEPS_GET_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x8B) +#define OP_FORWARDING_TABLE_ENTRIES_CNT_GET BLE_MESH_MODEL_OP_2(0x80, 0x8C) +#define OP_FORWARDING_TABLE_ENTRIES_CNT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x8D) +#define OP_FORWARDING_TABLE_ENTRIES_GET BLE_MESH_MODEL_OP_2(0x80, 0x8E) +#define OP_FORWARDING_TABLE_ENTRIES_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x8F) +#define OP_WANTED_LANES_GET BLE_MESH_MODEL_OP_2(0x80, 0x90) +#define OP_WANTED_LANES_SET BLE_MESH_MODEL_OP_2(0x80, 0x91) +#define OP_WANTED_LANES_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x92) +#define OP_TWO_WAY_PATH_GET BLE_MESH_MODEL_OP_2(0x80, 0x93) +#define OP_TWO_WAY_PATH_SET BLE_MESH_MODEL_OP_2(0x80, 0x94) +#define OP_TWO_WAY_PATH_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x95) +#define OP_PATH_ECHO_INTERVAL_GET BLE_MESH_MODEL_OP_2(0x80, 0x96) +#define OP_PATH_ECHO_INTERVAL_SET BLE_MESH_MODEL_OP_2(0x80, 0x97) +#define OP_PATH_ECHO_INTERVAL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x98) +#define OP_DIRECTED_NET_TRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0x99) +#define OP_DIRECTED_NET_TRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0x9A) +#define OP_DIRECTED_NET_TRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x9B) +#define OP_DIRECTED_RELAY_RETRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0x9C) +#define OP_DIRECTED_RELAY_RETRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0x9D) +#define OP_DIRECTED_RELAY_RETRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x9E) +#define OP_RSSI_THRESHOLD_GET BLE_MESH_MODEL_OP_2(0x80, 0x9F) +#define OP_RSSI_THRESHOLD_SET BLE_MESH_MODEL_OP_2(0x80, 0xA0) +#define OP_RSSI_THRESHOLD_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xA1) +#define OP_DIRECTED_PATHS_GET BLE_MESH_MODEL_OP_2(0x80, 0xA2) +#define OP_DIRECTED_PATHS_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xA3) +#define OP_DIRECTED_PUB_POLICY_GET BLE_MESH_MODEL_OP_2(0x80, 0xA4) +#define OP_DIRECTED_PUB_POLICY_SET BLE_MESH_MODEL_OP_2(0x80, 0xA5) +#define OP_DIRECTED_PUB_POLICY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xA6) +#define OP_PATH_DISCOVERY_TIMING_CTL_GET BLE_MESH_MODEL_OP_2(0x80, 0xA7) +#define OP_PATH_DISCOVERY_TIMING_CTL_SET BLE_MESH_MODEL_OP_2(0x80, 0xA8) +#define OP_PATH_DISCOVERY_TIMING_CTL_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xA9) +#define OP_DIRECTED_CTL_NET_TRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0xAB) +#define OP_DIRECTED_CTL_NET_TRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0xAC) +#define OP_DIRECTED_CTL_NET_TRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xAD) +#define OP_DIRECTED_CTL_RELAY_RETRANSMIT_GET BLE_MESH_MODEL_OP_2(0x80, 0xAE) +#define OP_DIRECTED_CTL_RELAY_RETRANSMIT_SET BLE_MESH_MODEL_OP_2(0x80, 0xAF) +#define OP_DIRECTED_CTL_RELAY_RETRANSMIT_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xB0) + +#define OP_SUBNET_BRIDGE_GET BLE_MESH_MODEL_OP_2(0x80, 0xB1) +#define OP_SUBNET_BRIDGE_SET BLE_MESH_MODEL_OP_2(0x80, 0xB2) +#define OP_SUBNET_BRIDGE_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xB3) +#define OP_BRIDGING_TABLE_ADD BLE_MESH_MODEL_OP_2(0x80, 0xB4) +#define OP_BRIDGING_TABLE_REMOVE BLE_MESH_MODEL_OP_2(0x80, 0xB5) +#define OP_BRIDGING_TABLE_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xB6) +#define OP_BRIDGED_SUBNETS_GET BLE_MESH_MODEL_OP_2(0x80, 0xB7) +#define OP_BRIDGED_SUBNETS_LIST BLE_MESH_MODEL_OP_2(0x80, 0xB8) +#define OP_BRIDGING_TABLE_GET BLE_MESH_MODEL_OP_2(0x80, 0xB9) +#define OP_BRIDGING_TABLE_LIST BLE_MESH_MODEL_OP_2(0x80, 0xBA) +#define OP_BRIDGING_TABLE_SIZE_GET BLE_MESH_MODEL_OP_2(0x80, 0xBB) +#define OP_BRIDGING_TABLE_SIZE_STATUS BLE_MESH_MODEL_OP_2(0x80, 0xBC) + +#define OP_PRIVATE_BEACON_GET BLE_MESH_MODEL_OP_2(0x80, 0x60) +#define OP_PRIVATE_BEACON_SET BLE_MESH_MODEL_OP_2(0x80, 0x61) +#define OP_PRIVATE_BEACON_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x62) +#define OP_PRIVATE_GATT_PROXY_GET BLE_MESH_MODEL_OP_2(0x80, 0x63) +#define OP_PRIVATE_GATT_PROXY_SET BLE_MESH_MODEL_OP_2(0x80, 0x64) +#define OP_PRIVATE_GATT_PROXY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x65) +#define OP_PRIVATE_NODE_IDENTITY_GET BLE_MESH_MODEL_OP_2(0x80, 0x66) +#define OP_PRIVATE_NODE_IDENTITY_SET BLE_MESH_MODEL_OP_2(0x80, 0x67) +#define OP_PRIVATE_NODE_IDENTITY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x68) + +#define OP_ON_DEMAND_PRIVATE_PROXY_GET BLE_MESH_MODEL_OP_2(0x80, 0x69) +#define OP_ON_DEMAND_PRIVATE_PROXY_SET BLE_MESH_MODEL_OP_2(0x80, 0x6A) +#define OP_ON_DEMAND_PRIVATE_PROXY_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x6B) + +#define OP_SAR_TRANSMITTER_GET BLE_MESH_MODEL_OP_2(0x80, 0x6C) +#define OP_SAR_TRANSMITTER_SET BLE_MESH_MODEL_OP_2(0x80, 0x6D) +#define OP_SAR_TRANSMITTER_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x6E) +#define OP_SAR_RECEIVER_GET BLE_MESH_MODEL_OP_2(0x80, 0x6F) +#define OP_SAR_RECEIVER_SET BLE_MESH_MODEL_OP_2(0x80, 0x70) +#define OP_SAR_RECEIVER_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x71) + +#define OP_OPCODES_AGG_SEQUENCE BLE_MESH_MODEL_OP_2(0x80, 0x72) +#define OP_OPCODES_AGG_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x73) + +#define OP_LARGE_COMP_DATA_GET BLE_MESH_MODEL_OP_2(0x80, 0x74) +#define OP_LARGE_COMP_DATA_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x75) +#define OP_MODELS_METADATA_GET BLE_MESH_MODEL_OP_2(0x80, 0x76) +#define OP_MODELS_METADATA_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x77) + +#define OP_SOLIC_PDU_RPL_ITEMS_CLEAR BLE_MESH_MODEL_OP_2(0x80, 0x78) +#define OP_SOLIC_PDU_RPL_ITEMS_CLEAR_UNACK BLE_MESH_MODEL_OP_2(0x80, 0x79) +#define OP_SOLIC_PDU_RPL_ITEMS_STATUS BLE_MESH_MODEL_OP_2(0x80, 0x7A) + +#define STATUS_SUCCESS 0x00 +#define STATUS_INVALID_ADDRESS 0x01 +#define STATUS_INVALID_MODEL 0x02 +#define STATUS_INVALID_APPKEY 0x03 +#define STATUS_INVALID_NETKEY 0x04 +#define STATUS_INSUFF_RESOURCES 0x05 +#define STATUS_IDX_ALREADY_STORED 0x06 +#define STATUS_NVAL_PUB_PARAM 0x07 +#define STATUS_NOT_SUB_MOD 0x08 +#define STATUS_STORAGE_FAIL 0x09 +#define STATUS_FEAT_NOT_SUPP 0x0A +#define STATUS_CANNOT_UPDATE 0x0B +#define STATUS_CANNOT_REMOVE 0x0C +#define STATUS_CANNOT_BIND 0x0D +#define STATUS_TEMP_STATE_CHG_FAIL 0x0E +#define STATUS_CANNOT_SET 0x0F +#define STATUS_UNSPECIFIED 0x10 +#define STATUS_INVALID_BINDING 0x11 +#define STATUS_INVALID_PATH_ENTRY 0x12 +#define STATUS_CANNOT_GET 0x13 +#define STATUS_OBSOLETE_INFO 0x14 +#define STATUS_INVALID_BEARER 0x15 + +/* 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 enum { BLE_MESH_VA_CHANGED, /* Label information changed */ @@ -152,7 +282,7 @@ uint8_t bt_mesh_net_transmit_get(void); uint8_t bt_mesh_relay_get(void); uint8_t bt_mesh_friend_get(void); uint8_t bt_mesh_relay_retransmit_get(void); -uint8_t bt_mesh_beacon_get(void); +uint8_t bt_mesh_secure_beacon_get(void); uint8_t bt_mesh_gatt_proxy_get(void); uint8_t bt_mesh_default_ttl_get(void); diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index 0637b17d1f..fca3cf1358 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -18,20 +18,28 @@ #include "friend.h" #include "foundation.h" #include "mesh/main.h" +#include "mesh/common.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + #ifdef CONFIG_BLE_MESH_FRIEND /* We reserve one extra buffer for each friendship, since we need to be able * to resend the last sent PDU, which sits separately outside of the queue. */ #define FRIEND_BUF_COUNT ((CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE + 1) * \ - CONFIG_BLE_MESH_FRIEND_LPN_COUNT) + CONFIG_BLE_MESH_FRIEND_LPN_COUNT) -#define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), struct friend_adv, adv) +#define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), struct friend_adv, adv) /* PDUs from Friend to the LPN should only be transmitted once with the * smallest possible interval (20ms). + * + * Spec v1.1, Section 3.4.6: + * When transmitting a Network PDU that is tagged as friendship, the + * Advertising Bearer Network Interface shall transmit the Network PDU + * over the advertising bearer only once. */ #define FRIEND_XMIT BLE_MESH_TRANSMIT(0, 20) @@ -70,15 +78,7 @@ static bool friend_init = false; static struct bt_mesh_subnet *friend_subnet_get(uint16_t net_idx) { - struct bt_mesh_subnet *sub = NULL; - - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { - sub = bt_mesh_subnet_get(net_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { - sub = bt_mesh_provisioner_subnet_get(net_idx); - } - - return sub; + return bt_mesh_subnet_get(net_idx); } static struct bt_mesh_adv *adv_alloc(int id) @@ -166,6 +166,15 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) if (friend_cb) { friend_cb(false, frnd->lpn, reason); } + +#if CONFIG_BLE_MESH_DF_SRV + struct bt_mesh_subnet *sub = friend_subnet_get(frnd->net_idx); + if (sub && sub->directed_friend == BLE_MESH_DIRECTED_FRIEND_ENABLED) { + if (bt_mesh_directed_update_dependent_node(sub, 0, frnd->lpn, frnd->num_elem)) { + BT_ERR("Friend failed to update dependent node"); + } + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ } friend_cred_del(frnd->net_idx, frnd->lpn); @@ -296,7 +305,10 @@ int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) return 0; } - tx.ctx->send_ttl = BLE_MESH_TTL_MAX; + tx.ctx->send_ttl = BLE_MESH_TTL_MAX; + tx.ctx->send_cred = BLE_MESH_FLOODING_CRED; + /* Tag with immutable-credentials */ + tx.ctx->send_tag = BLE_MESH_TAG_IMMUTABLE_CRED; cfm.lpn_addr = msg->lpn_addr; cfm.lpn_counter = msg->lpn_counter; @@ -309,6 +321,19 @@ int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) return 0; } +static bool friend_sub_exist(struct bt_mesh_friend *frnd, uint16_t addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { + if (frnd->sub_list[i] == addr) { + return true; + } + } + + return false; +} + static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) { int i; @@ -342,8 +367,7 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf = NULL; buf = bt_mesh_adv_create_from_pool(&friend_buf_pool, adv_alloc, - BLE_MESH_ADV_DATA, - FRIEND_XMIT, K_NO_WAIT); + BLE_MESH_ADV_DATA, K_NO_WAIT); if (!buf) { return NULL; } @@ -380,7 +404,6 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta *meta) { uint16_t app_idx = FRIEND_ADV(buf)->app_idx; - uint8_t role = 0U; int err = 0; meta->subnet = friend_subnet_get(frnd->net_idx); @@ -389,13 +412,10 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, return -EINVAL; } - role = (IS_ENABLED(CONFIG_BLE_MESH_NODE) && - bt_mesh_is_provisioned()) ? NODE : PROVISIONER; - meta->is_dev_key = (app_idx == BLE_MESH_KEY_DEV); bt_mesh_net_header_parse(&buf->b, &meta->net); - err = bt_mesh_app_key_get(meta->subnet, app_idx, &meta->key, - &meta->aid, role, meta->net.ctx.addr); + err = bt_mesh_upper_key_get(meta->subnet, app_idx, &meta->key, + &meta->aid, meta->net.ctx.addr); if (err) { BT_ERR("Failed to get AppKey"); return err; @@ -532,7 +552,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, buf->data[0] = (nid | (iv_index & 1) << 7); - if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false)) { + if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false, false)) { BT_ERR("Encrypting failed"); return -EINVAL; } @@ -657,12 +677,29 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, xact = net_buf_simple_pull_u8(buf); while (buf->len >= 2U) { - friend_sub_add(frnd, net_buf_simple_pull_be16(buf)); + uint16_t addr = net_buf_simple_pull_be16(buf); + + if (!BLE_MESH_ADDR_IS_GROUP(addr) && + !BLE_MESH_ADDR_IS_VIRTUAL(addr) && + !BLE_MESH_ADDR_IS_FIXED_GROUP(addr)) { + BT_WARN("Invalid friend sub addr 0x%04x to add", addr); + continue; + } + + if (friend_sub_exist(frnd, addr)) { + continue; + } + + friend_sub_add(frnd, addr); } enqueue_sub_cfm(frnd, xact); +#if CONFIG_BLE_MESH_DF_SRV + return bt_mesh_directed_friend_solicitation(frnd, rx->sub); +#else return 0; +#endif } int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, @@ -692,7 +729,16 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, xact = net_buf_simple_pull_u8(buf); while (buf->len >= 2U) { - friend_sub_rem(frnd, net_buf_simple_pull_be16(buf)); + uint16_t addr = net_buf_simple_pull_be16(buf); + + if (!BLE_MESH_ADDR_IS_GROUP(addr) && + !BLE_MESH_ADDR_IS_VIRTUAL(addr) && + !BLE_MESH_ADDR_IS_FIXED_GROUP(addr)) { + BT_WARN("Invalid friend sub addr 0x%04x to remove", addr); + continue; + } + + friend_sub_rem(frnd, addr); } enqueue_sub_cfm(frnd, xact); @@ -808,10 +854,13 @@ static const struct bt_mesh_send_cb clear_sent_cb = { static void send_friend_clear(struct bt_mesh_friend *frnd) { struct bt_mesh_msg_ctx ctx = { - .net_idx = frnd->net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = frnd->clear.frnd, - .send_ttl = BLE_MESH_TTL_MAX, + .net_idx = frnd->net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = frnd->clear.frnd, + .send_ttl = BLE_MESH_TTL_MAX, + .send_cred = BLE_MESH_FLOODING_CRED, + /* Tag with immutable-credentials */ + .send_tag = BLE_MESH_TAG_IMMUTABLE_CRED, }; struct bt_mesh_net_tx tx = { .sub = friend_subnet_get(frnd->net_idx), @@ -824,8 +873,6 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter), }; - BT_DBG("%s", __func__); - if (!tx.sub) { BT_ERR("Invalid subnet for Friend Clear"); return; @@ -870,8 +917,6 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint16_t lpn_addr = 0U, lpn_counter = 0U; - BT_DBG("%s", __func__); - if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Clear Confirm (len %d)", buf->len); return -EINVAL; @@ -909,17 +954,15 @@ static void enqueue_offer(struct bt_mesh_friend *frnd, int8_t rssi) NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*off)); struct net_buf *buf = NULL; - BT_DBG("%s", __func__); - net_buf_simple_reserve(&sdu, 1); off = net_buf_simple_add(&sdu, sizeof(*off)); - off->recv_win = CONFIG_BLE_MESH_FRIEND_RECV_WIN, - off->queue_size = CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, - off->sub_list_size = ARRAY_SIZE(frnd->sub_list), - off->rssi = rssi, - off->frnd_counter = sys_cpu_to_be16(frnd->counter); + off->recv_win = CONFIG_BLE_MESH_FRIEND_RECV_WIN; + off->queue_size = CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE; + off->sub_list_size = ARRAY_SIZE(frnd->sub_list); + off->rssi = rssi; + off->frnd_counter = sys_cpu_to_be16(frnd->counter); buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_OFFER, &sdu); if (!buf) { @@ -956,8 +999,8 @@ static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t cri int32_t delay = 0; BT_INFO("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d", - fact[RECV_WIN_FACT(crit)], RECV_WIN, - fact[RSSI_FACT(crit)], rssi); + fact[RECV_WIN_FACT(crit)], RECV_WIN, + fact[RSSI_FACT(crit)], rssi); /* Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI */ delay = (int32_t)fact[RECV_WIN_FACT(crit)] * RECV_WIN; @@ -1059,7 +1102,7 @@ init_friend: * begin sending Friend Clear messages to that unicast address. */ if (BLE_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) && - !bt_mesh_elem_find(frnd->clear.frnd)) { + !bt_mesh_elem_find(frnd->clear.frnd)) { clear_procedure_start(frnd); } @@ -1245,7 +1288,7 @@ static void friend_timeout(struct k_work *work) send_last: frnd->pending_req = 0U; frnd->pending_buf = 1U; - bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); + bt_mesh_adv_send(frnd->last, FRIEND_XMIT, &buf_sent_cb, frnd); } void bt_mesh_friend_set_cb(void (*cb)(bool establish, uint16_t lpn_addr, uint8_t reason)) @@ -1513,6 +1556,29 @@ bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr) return false; } +bool bt_mesh_friend_unicast_match(uint16_t net_idx, uint16_t addr, uint8_t *selem) +{ + int i; + + if (!BLE_MESH_ADDR_IS_UNICAST(addr) || selem == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return false; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (frnd->established && net_idx == frnd->net_idx && + BLE_MESH_ADDR_IS_UNICAST(frnd->lpn) && + (addr >= frnd->lpn && addr < (frnd->lpn + frnd->num_elem))) { + *selem = frnd->num_elem - 1; + return true; + } + } + + return false; +} + static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, const uint64_t *seq_auth, uint8_t seg_count) { @@ -1623,8 +1689,8 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, int i; if (!rx->friend_match || - (rx->ctx.recv_ttl <= 1U && rx->net_if != BLE_MESH_NET_IF_LOCAL) || - bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { + (rx->ctx.recv_ttl <= 1U && rx->net_if != BLE_MESH_NET_IF_LOCAL) || + bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return; } @@ -1659,7 +1725,7 @@ bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, int i; if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) || - bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { + bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return matched; } @@ -1692,8 +1758,6 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; int j; diff --git a/components/bt/esp_ble_mesh/core/friend.h b/components/bt/esp_ble_mesh/core/friend.h index 2855081bf5..2e583f357d 100644 --- a/components/bt/esp_ble_mesh/core/friend.h +++ b/components/bt/esp_ble_mesh/core/friend.h @@ -22,6 +22,7 @@ enum bt_mesh_friend_pdu_type { }; bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr); +bool bt_mesh_friend_unicast_match(uint16_t net_idx, uint16_t addr, uint8_t *selem); struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, bool valid, bool established); diff --git a/components/bt/esp_ble_mesh/core/health_cli.c b/components/bt/esp_ble_mesh/core/health_cli.c index 6ddedef55f..1e03d93513 100644 --- a/components/bt/esp_ble_mesh/core/health_cli.c +++ b/components/bt/esp_ble_mesh/core/health_cli.c @@ -31,40 +31,17 @@ static const bt_mesh_client_op_pair_t health_op_pair[] = { static bt_mesh_mutex_t health_client_lock; -static inline void bt_mesh_health_client_mutex_new(void) -{ - if (!health_client_lock.mutex) { - bt_mesh_mutex_create(&health_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_health_client_mutex_free(void) -{ - bt_mesh_mutex_free(&health_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_health_client_lock(void) -{ - bt_mesh_mutex_lock(&health_client_lock); -} - -static inline void bt_mesh_health_client_unlock(void) -{ - bt_mesh_mutex_unlock(&health_client_lock); -} - static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive health status message timeout"); - bt_mesh_health_client_lock(); + bt_mesh_mutex_lock(&health_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -73,15 +50,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_health_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_HEALTH_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_HEALTH_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_health_client_unlock(); - - return; + bt_mesh_mutex_unlock(&health_client_lock); } static void health_client_recv_status(struct bt_mesh_model *model, @@ -101,7 +77,7 @@ static void health_client_recv_status(struct bt_mesh_model *model, buf.data = (uint8_t *)status; buf.len = (uint16_t)len; - bt_mesh_health_client_lock(); + bt_mesh_mutex_lock(&health_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, &buf, true); if (!node) { @@ -131,7 +107,7 @@ static void health_client_recv_status(struct bt_mesh_model *model, } } - bt_mesh_health_client_unlock(); + bt_mesh_mutex_unlock(&health_client_lock); switch (ctx->recv_op) { case OP_HEALTH_FAULT_STATUS: { @@ -324,24 +300,25 @@ static int health_cli_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(health_internal_data_t)); - if (!internal) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(health_op_pair); - client->op_pair = health_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_health_client_mutex_new(); + internal = bt_mesh_calloc(sizeof(health_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(health_op_pair); + client->op_pair = health_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&health_client_lock); return 0; } @@ -373,7 +350,7 @@ static int health_cli_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_health_client_mutex_free(); + bt_mesh_mutex_free(&health_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/core/health_srv.c b/components/bt/esp_ble_mesh/core/health_srv.c index 70a3e3fbfc..a27e4547b2 100644 --- a/components/bt/esp_ble_mesh/core/health_srv.c +++ b/components/bt/esp_ble_mesh/core/health_srv.c @@ -182,8 +182,6 @@ static void health_fault_test(struct bt_mesh_model *model, uint16_t company_id = 0U; uint8_t test_id = 0U; - BT_DBG("%s", __func__); - if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -241,8 +239,6 @@ static void attention_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("%s", __func__); - send_attention_status(model, ctx); } @@ -263,8 +259,6 @@ static void attention_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("%s", __func__); - health_set_attention(model, ctx, buf); if (ctx->recv_op == OP_ATTENTION_SET) { @@ -289,8 +283,6 @@ static void health_period_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("%s", __func__); - send_health_period_status(model, ctx); } @@ -315,8 +307,6 @@ static void health_period_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("%s", __func__); - health_set_period(model, ctx, buf); if (ctx->recv_op == OP_HEALTH_PERIOD_SET) { @@ -367,8 +357,6 @@ static int health_pub_update(struct bt_mesh_model *model) struct bt_mesh_model_pub *pub = model->pub; size_t count = 0U; - BT_DBG("%s", __func__); - if (!pub || !pub->msg) { BT_ERR("Invalid health publication context"); return -EINVAL; @@ -416,8 +404,6 @@ static void attention_off(struct k_work *work) struct bt_mesh_health_srv *srv = CONTAINER_OF(work, struct bt_mesh_health_srv, attn_timer.work); - BT_DBG("%s", __func__); - if (!srv) { BT_ERR("No Health Server context provided"); return; 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 3e826cea26..1b78cbd416 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-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,16 +26,20 @@ extern "C" { #endif -#define BLE_MESH_CID_NVAL 0xFFFF +#define BLE_MESH_CID_NVAL 0xFFFF -#define BLE_MESH_ADDR_UNASSIGNED 0x0000 -#define BLE_MESH_ADDR_ALL_NODES 0xffff -#define BLE_MESH_ADDR_PROXIES 0xfffc -#define BLE_MESH_ADDR_FRIENDS 0xfffd -#define BLE_MESH_ADDR_RELAYS 0xfffe +#define BLE_MESH_ADDR_UNASSIGNED 0x0000 -#define BLE_MESH_KEY_UNUSED 0xffff -#define BLE_MESH_KEY_DEV 0xfffe +#define BLE_MESH_ADDR_IPT_ROUTERS 0xFFF9 +#define BLE_MESH_ADDR_IPT_NODES 0xFFFA +#define BLE_MESH_ADDR_DIRECTS 0xFFFB +#define BLE_MESH_ADDR_PROXIES 0xFFFC +#define BLE_MESH_ADDR_FRIENDS 0xFFFD +#define BLE_MESH_ADDR_RELAYS 0xFFFE +#define BLE_MESH_ADDR_ALL_NODES 0xFFFF + +#define BLE_MESH_KEY_UNUSED 0xFFFF +#define BLE_MESH_KEY_DEV 0xFFFE /** Helper to define a mesh element within an array. * @@ -75,6 +79,24 @@ struct bt_mesh_elem { #define BLE_MESH_MODEL_ID_CFG_CLI 0x0001 #define BLE_MESH_MODEL_ID_HEALTH_SRV 0x0002 #define BLE_MESH_MODEL_ID_HEALTH_CLI 0x0003 +#define BLE_MESH_MODEL_ID_RPR_SRV 0x0004 +#define BLE_MESH_MODEL_ID_RPR_CLI 0x0005 +#define BLE_MESH_MODEL_ID_DF_SRV 0x0006 +#define BLE_MESH_MODEL_ID_DF_CLI 0x0007 +#define BLE_MESH_MODEL_ID_BRC_SRV 0x0008 +#define BLE_MESH_MODEL_ID_BRC_CLI 0x0009 +#define BLE_MESH_MODEL_ID_PRB_SRV 0x000A +#define BLE_MESH_MODEL_ID_PRB_CLI 0x000B +#define BLE_MESH_MODEL_ID_ODP_SRV 0x000C +#define BLE_MESH_MODEL_ID_ODP_CLI 0x000D +#define BLE_MESH_MODEL_ID_SAR_SRV 0x000E +#define BLE_MESH_MODEL_ID_SAR_CLI 0x000F +#define BLE_MESH_MODEL_ID_AGG_SRV 0x0010 +#define BLE_MESH_MODEL_ID_AGG_CLI 0x0011 +#define BLE_MESH_MODEL_ID_LCD_SRV 0x0012 +#define BLE_MESH_MODEL_ID_LCD_CLI 0x0013 +#define BLE_MESH_MODEL_ID_SRPL_SRV 0x0014 +#define BLE_MESH_MODEL_ID_SRPL_CLI 0x0015 /* Models from the Mesh Model Specification */ #define BLE_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000 @@ -129,6 +151,8 @@ struct bt_mesh_elem { #define BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 +#define BLE_MESH_MODEL_ID_MBT_SRV 0x1400 +#define BLE_MESH_MODEL_ID_MBT_CLI 0x1401 /** Message sending context. */ struct bt_mesh_msg_ctx { @@ -144,28 +168,42 @@ struct bt_mesh_msg_ctx { /** Destination address of a received message. Not used for sending. */ uint16_t recv_dst; - /** RSSI of received packet. Not used for sending. */ - int8_t recv_rssi; + /** RSSI of a received message. Not used for sending. */ + int8_t recv_rssi; + + /** Opcode of a received message. Not used for sending. */ + uint32_t recv_op; /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl: 7; + uint8_t recv_ttl; - /** Force sending reliably by using segment acknowledgement */ - uint8_t send_rel: 1; + /** Security credentials of a received message. Not used for sending. */ + uint8_t recv_cred; + + /** Tag of a received message. Not used for sending. */ + uint8_t recv_tag; + + /** Force sending reliably by using segment acknowledgement. */ + uint8_t send_rel:1 __attribute__((deprecated)); + + /** Size of TransMIC when sending a Segmented Access message. */ + uint8_t send_szmic:1; /** TTL, or BLE_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; - /** Change by Espressif, opcode of a received message. - * Not used for sending message. */ - uint32_t recv_op; + /** Security credentials used for sending the message */ + uint8_t send_cred; + + /** Tag used for sending the message. */ + uint8_t send_tag; /** Change by Espressif, model corresponds to the message */ - struct bt_mesh_model *model; + struct bt_mesh_model *model __attribute__((deprecated)); /** Change by Espressif, if the message is sent by a server * model. Not used for receiving message. */ - bool srv_send; + bool srv_send __attribute__((deprecated)); }; struct bt_mesh_model_op { @@ -194,16 +232,29 @@ struct bt_mesh_model_op { /** Length of a short Mesh MIC. */ #define BLE_MESH_MIC_SHORT 4 + /** Length of a long Mesh MIC. */ #define BLE_MESH_MIC_LONG 8 +/* Using 4-octets TransMIC for a segmented message */ +#define BLE_MESH_SEG_SZMIC_SHORT 0 + +/* Using 8-octets TransMIC for a segmented message */ +#define BLE_MESH_SEG_SZMIC_LONG 1 + +/** Maximum length of payload with short MIC */ +#define BLE_MESH_MAX_PDU_LEN_WITH_SMIC 380 + +/** Maximum length of payload with long MIC */ +#define BLE_MESH_MAX_PDU_LEN_WITH_LMIC 376 + /** @def BLE_MESH_MODEL_OP_LEN * * @brief Helper to determine the length of an opcode. * * @param _op Opcode. */ -#define BLE_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) +#define BLE_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) /** @def BLE_MESH_MODEL_BUF_LEN * @@ -364,7 +415,8 @@ struct bt_mesh_model_pub { uint16_t addr; /**< Publish Address. */ uint16_t key:12, /**< Publish AppKey Index. */ cred:1, /**< Friendship Credentials Flag. */ - send_rel:1; /**< Force reliable sending (segment acks) */ + send_rel:1, /**< Force reliable sending (segment acks) */ + send_szmic:1; /**< Size of TransMIC when sending Segmented Access message */ uint8_t ttl; /**< Publish Time to Live. */ uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ @@ -375,6 +427,10 @@ struct bt_mesh_model_pub { uint32_t period_start; /**< Start of the current period. */ +#if CONFIG_BLE_MESH_DF_SRV + uint8_t directed_pub_policy; /**< Directed publish policy */ +#endif + /** @brief Publication buffer, containing the publication message. * * This will get correctly created when the publication context @@ -405,7 +461,7 @@ struct bt_mesh_model_pub { struct k_delayed_work timer; /* Change by Espressif, role of the device going to publish messages */ - uint8_t dev_role; + uint8_t dev_role __attribute__((deprecated)); }; /** @def BLE_MESH_MODEL_PUB_DEFINE 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 47d4b550d0..431fc72cfe 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -113,20 +113,41 @@ extern "C" { #define BLE_MESH_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ #define BLE_MESH_DATA_NAME_SHORTENED 0x08 /* Shortened name */ #define BLE_MESH_DATA_NAME_COMPLETE 0x09 /* Complete name */ -#define BLE_MESH_DATA_TX_POWER 0x0a /* Tx Power */ +#define BLE_MESH_DATA_TX_POWER 0x0A /* Tx Power */ +#define BLE_MESH_DATA_CLASS_OF_DEVICE 0x0D /* Class of Device */ +#define BLE_MESH_DATA_SIMP_PAIR_HASH_C 0x0E /* Simple Pairing Hash C */ +#define BLE_MESH_DATA_SIMP_PAIR_RAND_R 0x0F /* Simple Pairing Randomizer R */ +#define BLE_MESH_DATA_SEC_MANAGER_TK_VAL 0x10 /* Security Manager TK Value */ +#define BLE_MESH_DATA_SEC_MANAGER_OOB_FLAG 0x11 /* Security Manager Out of Band Flags */ +#define BLE_MESH_DATA_SLAVE_CONN_INT_RANGE 0x12 /* Slave Connection Interval Range */ #define BLE_MESH_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */ #define BLE_MESH_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */ #define BLE_MESH_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */ +#define BLE_MESH_DATA_PUBLIC_TARGET_ADDR 0x17 /* Public Target Address */ +#define BLE_MESH_DATA_RANDOM_TARGET_ADDR 0x18 /* Random Target Address */ #define BLE_MESH_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */ -#define BLE_MESH_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ +#define BLE_MESH_DATA_ADV_INTERVAL 0x1A /* Advertising Interval */ +#define BLE_MESH_DATA_LE_DEVICE_ADDR 0x1B /* LE Bluetooth Device Address */ +#define BLE_MESH_DATA_LE_ROLE 0x1C /* LE Role */ +#define BLE_MESH_DATA_SIMP_PAIR_HASH_C_256 0x1D /* Simple Pairing Hash C-256 */ +#define BLE_MESH_DATA_SIMP_PAIR_RAND_R_256 0x1E /* Simple Pairing Randomizer R-256 */ +#define BLE_MESH_DATA_SOLICIT32 0x1F /* Solicit UUIDs, 32-bit */ #define BLE_MESH_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ #define BLE_MESH_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ +#define BLE_MESH_DATA_LE_SEC_CONN_CFM_VAL 0x22 /* LE Secure Connections Confirmation Value */ +#define BLE_MESH_DATA_LE_SEC_CONN_RAND_VAL 0x23 /* LE Secure Connections Random Value */ #define BLE_MESH_DATA_URI 0x24 /* URI */ +#define BLE_MESH_DATA_INDOOR_POSITION 0x25 /* Indoor Positioning */ +#define BLE_MESH_DATA_TRANS_DISC_DATA 0x26 /* Transport Discovery Data */ +#define BLE_MESH_DATA_LE_SUPPORT_FEAT 0x27 /* LE Supported Features */ +#define BLE_MESH_DATA_CHAN_MAP_UPDATE_IND 0x28 /* Channel Map Update Indication */ #define BLE_MESH_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ -#define BLE_MESH_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ -#define BLE_MESH_DATA_MESH_BEACON 0x2b /* Mesh Beacon */ - -#define BLE_MESH_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */ +#define BLE_MESH_DATA_MESH_MESSAGE 0x2A /* Mesh Networking PDU */ +#define BLE_MESH_DATA_MESH_BEACON 0x2B /* Mesh Beacon */ +#define BLE_MESH_DATA_BIGINFO 0x2C /* BIGInf */ +#define BLE_MESH_DATA_BROADCAST_COD 0x2D /* Broadcast_Cod */ +#define BLE_MESH_DATA_3D_INFO_DATA 0x3D /* 3D Information Data */ +#define BLE_MESH_DATA_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */ #define BLE_MESH_AD_LIMITED 0x01 /* Limited Discoverable */ #define BLE_MESH_AD_GENERAL 0x02 /* General Discoverable */ @@ -442,9 +463,11 @@ struct bt_mesh_conn { * @param rssi Strength of advertiser signal. * @param adv_type Type of advertising response from advertiser. * @param data Buffer containing advertiser data. + * @param scan_rsp_len Scan Response data length. */ typedef void bt_mesh_scan_cb_t(const bt_mesh_addr_t *addr, int8_t rssi, - uint8_t adv_type, struct net_buf_simple *buf); + uint8_t adv_type, struct net_buf_simple *buf, + uint8_t scan_rsp_len); /* @typedef bt_mesh_dh_key_cb_t * @brief Callback type for DH Key calculation. @@ -452,11 +475,11 @@ typedef void bt_mesh_scan_cb_t(const bt_mesh_addr_t *addr, int8_t rssi, * Used to notify of the calculated DH Key. * * @param key Public key. - * @param idx Provisioning link index, only used by Provisioner. + * @param user_data User data. * * @return The DH Key, or NULL in case of failure. */ -typedef void (*bt_mesh_dh_key_cb_t)(const uint8_t key[32], const uint8_t idx); +typedef void (*bt_mesh_dh_key_cb_t)(const uint8_t key[32], void *user_data); /** @typedef bt_mesh_gatt_attr_func_t * @brief Attribute iterator callback. @@ -767,7 +790,7 @@ const uint8_t *bt_mesh_pub_key_get(void); bool bt_mesh_check_public_key(const uint8_t key[64]); -int bt_mesh_dh_key_gen(const uint8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, const uint8_t idx); +int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]); int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], uint8_t enc_data[16]); diff --git a/components/bt/esp_ble_mesh/core/include/mesh/hci.h b/components/bt/esp_ble_mesh/core/include/mesh/hci.h index c48ffe4db5..9be507d95e 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/hci.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/hci.h @@ -107,19 +107,19 @@ struct bt_mesh_hci_cp_set_adv_param { bt_mesh_addr_t direct_addr; uint8_t channel_map; uint8_t filter_policy; -} __packed; +} __attribute__((packed)); #define BLE_MESH_HCI_OP_SET_ADV_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0008) struct bt_mesh_hci_cp_set_adv_data { uint8_t len; uint8_t data[31]; -} __packed; +} __attribute__((packed)); #define BLE_MESH_HCI_OP_SET_SCAN_RSP_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0009) struct bt_mesh_hci_cp_set_scan_rsp_data { uint8_t len; uint8_t data[31]; -} __packed; +} __attribute__((packed)); /* Added by Espressif */ extern struct bt_mesh_dev bt_mesh_dev; diff --git a/components/bt/esp_ble_mesh/core/include/mesh/main.h b/components/bt/esp_ble_mesh/core/include/mesh/main.h index bc04033732..35e554458a 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/main.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/main.h @@ -54,7 +54,9 @@ typedef enum { BLE_MESH_PROV_OOB_NFC = BIT(4), BLE_MESH_PROV_OOB_NUMBER = BIT(5), BLE_MESH_PROV_OOB_STRING = BIT(6), - /* 7 - 10 are reserved */ + BLE_MESH_PROV_CERT_BASED = BIT(7), + BLE_MESH_PROV_RECORDS = BIT(8), + /* 9 - 10 are reserved */ BLE_MESH_PROV_OOB_ON_BOX = BIT(11), BLE_MESH_PROV_OOB_IN_BOX = BIT(12), BLE_MESH_PROV_OOB_ON_PAPER = BIT(13), @@ -62,7 +64,12 @@ typedef enum { BLE_MESH_PROV_OOB_ON_DEV = BIT(15), } bt_mesh_prov_oob_info_t; +#if CONFIG_BLE_MESH_PROV_EPA +#define BLE_MESH_PROV_STATIC_OOB_MAX_LEN 32 +#else /* CONFIG_BLE_MESH_PROV_EPA */ #define BLE_MESH_PROV_STATIC_OOB_MAX_LEN 16 +#endif /* CONFIG_BLE_MESH_PROV_EPA */ + #define BLE_MESH_PROV_OUTPUT_OOB_MAX_LEN 8 #define BLE_MESH_PROV_INPUT_OOB_MAX_LEN 8 @@ -92,6 +99,9 @@ struct bt_mesh_prov { */ void (*oob_pub_key_cb)(void); + /** OOB type */ + uint8_t oob_type; + /** Static OOB value */ const uint8_t *static_val; /** Static OOB value length */ @@ -161,8 +171,9 @@ struct bt_mesh_prov { * link has been closed on the given provisioning bearer. * * @param bearer Provisioning bearer. + * @param reason Provisioning link close reason(disconnect reason) */ - void (*link_close)(bt_mesh_prov_bearer_t bearer); + void (*link_close)(bt_mesh_prov_bearer_t bearer, uint8_t reason); /** @brief Provisioning is complete. * @@ -181,7 +192,7 @@ struct bt_mesh_prov { /** @brief Node has been reset. * * This callback notifies the application that the local node - * has been reset and needs to be reprovisioned. The node will + * has been reset and needs to be re-provisioned. The node will * not automatically advertise as unprovisioned, rather the * bt_mesh_prov_enable() API needs to be called to enable * unprovisioned advertising on one or more provisioning bearers. @@ -305,6 +316,41 @@ struct bt_mesh_prov { void (*prov_complete)(uint16_t node_idx, const uint8_t device_uuid[16], uint16_t unicast_addr, uint8_t element_num, uint16_t netkey_idx); + + /** @brief Provisioner start certificate based provisioning. + * + * This callback notifies the application that certificate based provisioning + * has started. Provisioner need to send prov_records_get, prov_record_request + * or prov_invite message. + * + * @param link_idx: The provisioning link index + */ + void (*cert_based_prov_start)(uint16_t link_idx); + + /** @brief Provisioner receive provisioning records list from device. + * + * This callback notifies the application that provisioner has received + * provisioning records list, and will send the list to application. + * + * @param link_idx: The provisioning link index + * @param data: The provisioning records list. + */ + void (*records_list_get)(uint16_t link_idx, struct net_buf_simple *data); + + /** @brief Provisioner receive complete provisioning record from device. + * + * This callback notifies the application that provisioner has received + * complete provisioning record, and will send the record to application. + * + * @param status: Status + * @param link_idx: The provisioning link index. + * @param record_id: The provisioning record index. + * @param frag_offset: The starting of the fragment. + * @param total_len: The length of the record. + * @param record: The data of the record. + */ + void (*prov_record_recv_comp)(uint8_t status, uint16_t link_idx, uint16_t record_id, + uint16_t frag_offset, uint16_t total_len, uint8_t *record); #endif /* CONFIG_BLE_MESH_PROVISIONER */ }; @@ -415,36 +461,82 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers); */ /* Primary Network Key index */ -#define BLE_MESH_NET_PRIMARY 0x000 +#define BLE_MESH_NET_PRIMARY 0x000 -#define BLE_MESH_RELAY_DISABLED 0x00 -#define BLE_MESH_RELAY_ENABLED 0x01 -#define BLE_MESH_RELAY_NOT_SUPPORTED 0x02 +#define BLE_MESH_RELAY_DISABLED 0x00 +#define BLE_MESH_RELAY_ENABLED 0x01 +#define BLE_MESH_RELAY_NOT_SUPPORTED 0x02 -#define BLE_MESH_BEACON_DISABLED 0x00 -#define BLE_MESH_BEACON_ENABLED 0x01 +#define BLE_MESH_SECURE_BEACON_DISABLED 0x00 +#define BLE_MESH_SECURE_BEACON_ENABLED 0x01 -#define BLE_MESH_GATT_PROXY_DISABLED 0x00 -#define BLE_MESH_GATT_PROXY_ENABLED 0x01 -#define BLE_MESH_GATT_PROXY_NOT_SUPPORTED 0x02 +#define BLE_MESH_GATT_PROXY_DISABLED 0x00 +#define BLE_MESH_GATT_PROXY_ENABLED 0x01 +#define BLE_MESH_GATT_PROXY_NOT_SUPPORTED 0x02 -#define BLE_MESH_FRIEND_DISABLED 0x00 -#define BLE_MESH_FRIEND_ENABLED 0x01 -#define BLE_MESH_FRIEND_NOT_SUPPORTED 0x02 +#define BLE_MESH_FRIEND_DISABLED 0x00 +#define BLE_MESH_FRIEND_ENABLED 0x01 +#define BLE_MESH_FRIEND_NOT_SUPPORTED 0x02 -#define BLE_MESH_NODE_IDENTITY_STOPPED 0x00 -#define BLE_MESH_NODE_IDENTITY_RUNNING 0x01 -#define BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02 +#define BLE_MESH_NODE_IDENTITY_STOPPED 0x00 +#define BLE_MESH_NODE_IDENTITY_RUNNING 0x01 +#define BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_PRIVATE_BEACON_DISABLED 0x00 +#define BLE_MESH_PRIVATE_BEACON_ENABLED 0x01 + +#define BLE_MESH_RANDOM_UPDATE_EVERY_PRIVATE_BEACON 0x00 + +#define BLE_MESH_PRIVATE_GATT_PROXY_DISABLED 0x00 +#define BLE_MESH_PRIVATE_GATT_PROXY_ENABLED 0x01 +#define BLE_MESH_PRIVATE_GATT_PROXY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED 0x00 +#define BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING 0x01 +#define BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_SUBNET_BRIDGE_DISABLED 0x00 +#define BLE_MESH_SUBNET_BRIDGE_ENABLED 0x01 + +#define BLE_MESH_PRIVATE_NET_ID_CANNOT_EN_ON_DEMAND 0x00 + +#define BLE_MESH_DIRECTED_FORWARDING_DISABLED 0x00 +#define BLE_MESH_DIRECTED_FORWARDING_ENABLED 0x01 + +#define BLE_MESH_DIRECTED_RELAY_DISABLED 0x00 +#define BLE_MESH_DIRECTED_RELAY_ENABLED 0x01 + +#define BLE_MESH_DIRECTED_PROXY_DISABLED 0x00 +#define BLE_MESH_DIRECTED_PROXY_ENABLED 0x01 +#define BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_DIRECTED_PROXY_USE_DEF_DISABLED 0x00 +#define BLE_MESH_DIRECTED_PROXY_USE_DEF_ENABLED 0x01 +#define BLE_MESH_DIRECTED_PROXY_USE_DEF_NOT_SUPPORTED 0x02 + +#define BLE_MESH_DIRECTED_FRIEND_DISABLED 0x00 +#define BLE_MESH_DIRECTED_FRIEND_ENABLED 0x01 +#define BLE_MESH_DIRECTED_FRIEND_NOT_SUPPORTED 0x02 + +#define BLE_MESH_DIRECTED_PUB_POLICY_FLOODING 0x00 +#define BLE_MESH_DIRECTED_PUB_POLICY_FORWARD 0x01 + +#define BLE_MESH_PROXY_USE_DIRECTED_DISABLED 0x00 +#define BLE_MESH_PROXY_USE_DIRECTED_ENABLED 0x01 + +#define BLE_MESH_FLOODING_CRED 0x00 +#define BLE_MESH_FRIENDSHIP_CRED 0x01 +#define BLE_MESH_DIRECTED_CRED 0x02 /* Features */ -#define BLE_MESH_FEAT_RELAY BIT(0) -#define BLE_MESH_FEAT_PROXY BIT(1) -#define BLE_MESH_FEAT_FRIEND BIT(2) -#define BLE_MESH_FEAT_LOW_POWER BIT(3) -#define BLE_MESH_FEAT_SUPPORTED (BLE_MESH_FEAT_RELAY | \ - BLE_MESH_FEAT_PROXY | \ - BLE_MESH_FEAT_FRIEND | \ - BLE_MESH_FEAT_LOW_POWER) +#define BLE_MESH_FEAT_RELAY BIT(0) +#define BLE_MESH_FEAT_PROXY BIT(1) +#define BLE_MESH_FEAT_FRIEND BIT(2) +#define BLE_MESH_FEAT_LOW_POWER BIT(3) +#define BLE_MESH_FEAT_SUPPORTED (BLE_MESH_FEAT_RELAY | \ + BLE_MESH_FEAT_PROXY | \ + BLE_MESH_FEAT_FRIEND | \ + BLE_MESH_FEAT_LOW_POWER) /** @brief Check if the mesh stack is initialized. * @@ -482,7 +574,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param); /** @brief Reset the state of the local Mesh node. * * Resets the state of the node, which means that it needs to be - * reprovisioned to become an active node in a Mesh network again. + * re-provisioned to become an active node in a Mesh network again. * * After calling this API, the node will not automatically advertise as * unprovisioned, rather the bt_mesh_prov_enable() API needs to be called 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 986d7f1dde..bd63b84d86 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/uuid.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/uuid.h @@ -466,6 +466,10 @@ 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 e3367e93eb..b8bcfffa55 100644 --- a/components/bt/esp_ble_mesh/core/local.c +++ b/components/bt/esp_ble_mesh/core/local.c @@ -35,9 +35,9 @@ static struct bt_mesh_model *find_model(uint16_t elem_addr, uint16_t cid, uint16 if (cid == BLE_MESH_CID_NVAL) { return bt_mesh_model_find(elem, mod_id); - } else { - return bt_mesh_model_find_vnd(elem, cid, mod_id); } + + return bt_mesh_model_find_vnd(elem, cid, mod_id); } int bt_mesh_model_subscribe_group_addr(uint16_t elem_addr, uint16_t cid, @@ -120,6 +120,36 @@ int bt_mesh_model_unsubscribe_group_addr(uint16_t elem_addr, uint16_t cid, return 0; } +#if CONFIG_BLE_MESH_DF_SRV +int bt_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay) +{ + struct bt_mesh_subnet *sub = NULL; + + if (net_idx > 0xFFF) { + BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + return -EINVAL; + } + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + BT_ERR("NetKey 0x%04x not exists", net_idx); + return -EINVAL; + } + + if (directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_DISABLED && + directed_forwarding_relay == BLE_MESH_DIRECTED_RELAY_ENABLED) { + BT_ERR("Invalid Config directed forwarding: %d, directed forwarding relay: %d", directed_forwarding, directed_forwarding_relay); + return -EINVAL; + } + + sub->directed_forwarding = directed_forwarding; + sub->directed_relay = directed_forwarding_relay; + + return 0; +} + +#endif #if CONFIG_BLE_MESH_NODE const uint8_t *bt_mesh_node_get_local_net_key(uint16_t net_idx) @@ -149,7 +179,7 @@ const uint8_t *bt_mesh_node_get_local_app_key(uint16_t app_idx) return NULL; } - key = bt_mesh_app_key_find(app_idx); + key = bt_mesh_app_key_get(app_idx); if (!key) { BT_ERR("AppKey 0x%04x not exists", app_idx); return NULL; @@ -225,7 +255,7 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) } /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); return 0; } @@ -250,7 +280,7 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, return -EIO; } - key = bt_mesh_app_key_find(app_idx); + key = bt_mesh_app_key_get(app_idx); if (key) { BT_WARN("AppKey 0x%04x already exists", app_idx); return -EEXIST; @@ -312,7 +342,7 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, return -ENODEV; } - if (bt_mesh_app_key_find(app_idx) == NULL) { + if (bt_mesh_app_key_get(app_idx) == NULL) { BT_ERR("Bind, AppKey 0x%03x not exists", app_idx); return -ENODEV; } diff --git a/components/bt/esp_ble_mesh/core/local.h b/components/bt/esp_ble_mesh/core/local.h index 85b37e64bd..3172d58e17 100644 --- a/components/bt/esp_ble_mesh/core/local.h +++ b/components/bt/esp_ble_mesh/core/local.h @@ -34,6 +34,11 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, uint16_t cid, uint16_t app_idx); +#if CONFIG_BLE_MESH_DF_SRV +int bt_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwarding, + bool directed_forwarding_relay); +#endif + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/core/lpn.c b/components/bt/esp_ble_mesh/core/lpn.c index 4de5bebe6b..52b01a9c57 100644 --- a/components/bt/esp_ble_mesh/core/lpn.c +++ b/components/bt/esp_ble_mesh/core/lpn.c @@ -17,13 +17,16 @@ #include "access.h" #include "beacon.h" #include "lpn.h" +#include "rpl.h" #include "foundation.h" #include "mesh/main.h" #include "mesh/cfg_srv.h" +#include "mesh_v1.1/utils.h" + #ifdef CONFIG_BLE_MESH_LOW_POWER -#if defined(CONFIG_BLE_MESH_LPN_AUTO) +#if CONFIG_BLE_MESH_LPN_AUTO #define LPN_AUTO_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_LPN_AUTO_TIMEOUT) #else #define LPN_AUTO_TIMEOUT 0 @@ -180,15 +183,18 @@ static const struct bt_mesh_send_cb clear_sent_cb = { static int send_friend_clear(void) { struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = bt_mesh.lpn.frnd, - .send_ttl = 0, + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = bt_mesh.lpn.frnd, + .send_ttl = 0, + .send_cred = BLE_MESH_FLOODING_CRED, + /* Tag with immutable-credentials */ + .send_tag = BLE_MESH_TAG_IMMUTABLE_CRED, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], - .ctx = &ctx, - .src = bt_mesh_primary_addr(), + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), .xmit = bt_mesh_net_transmit_get(), }; struct bt_mesh_ctl_friend_clear req = { @@ -196,8 +202,6 @@ static int send_friend_clear(void) .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter), }; - BT_DBG("%s", __func__); - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, sizeof(req), &clear_sent_cb, NULL); } @@ -210,13 +214,14 @@ static void clear_friendship(bool force, bool disable) BT_DBG("force %u disable %u", force, disable); if (!force && lpn->established && !lpn->clear_success && - lpn->req_attempts < CLEAR_ATTEMPTS) { + lpn->req_attempts < CLEAR_ATTEMPTS) { send_friend_clear(); lpn->disable = disable; return; } - bt_mesh_rx_reset(true); + bt_mesh_rx_reset(); + bt_mesh_rpl_reset(true); k_delayed_work_cancel(&lpn->timer); @@ -303,15 +308,18 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = BLE_MESH_ADDR_FRIENDS, - .send_ttl = 0, + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = BLE_MESH_ADDR_FRIENDS, + .send_ttl = 0, + .send_cred = BLE_MESH_FLOODING_CRED, + /* Tag with immutable-credentials and as a friendship PDU */ + .send_tag = BLE_MESH_TAG_IMMUTABLE_CRED | BLE_MESH_TAG_FRIENDSHIP, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], - .ctx = &ctx, - .src = bt_mesh_primary_addr(), + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, }; struct bt_mesh_ctl_friend_req req = { @@ -323,8 +331,6 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) .lpn_counter = sys_cpu_to_be16(lpn->counter), }; - BT_DBG("%s", __func__); - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req, sizeof(req), &friend_req_sent_cb, NULL); } @@ -348,7 +354,7 @@ static void req_sent(uint16_t duration, int err, void *user_data) if (lpn->established || IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { lpn_set_state(BLE_MESH_LPN_RECV_DELAY); - /* We start scanning a bit early to elimitate risk of missing + /* We start scanning a bit early to eliminate risk of missing * response data due to HCI and other latencies. */ k_delayed_work_submit(&lpn->timer, @@ -374,17 +380,19 @@ static const struct bt_mesh_send_cb req_sent_cb = { static int send_friend_poll(void) { struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = bt_mesh.lpn.frnd, - .send_ttl = 0, + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = bt_mesh.lpn.frnd, + .send_ttl = 0, + .send_cred = BLE_MESH_FRIENDSHIP_CRED, + /* Tag with immutable-credentials and as a friendship PDU */ + .send_tag = BLE_MESH_TAG_IMMUTABLE_CRED | BLE_MESH_TAG_FRIENDSHIP, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], - .ctx = &ctx, - .src = bt_mesh_primary_addr(), + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, - .friend_cred = true, }; struct bt_mesh_lpn *lpn = &bt_mesh.lpn; uint8_t fsn = lpn->fsn; @@ -632,7 +640,7 @@ static void lpn_group_del(uint16_t group) for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (lpn->groups[i] == group) { if (bt_mesh_atomic_test_bit(lpn->added, i) || - bt_mesh_atomic_test_bit(lpn->pending, i)) { + bt_mesh_atomic_test_bit(lpn->pending, i)) { bt_mesh_atomic_set_bit(lpn->to_remove, i); lpn->groups_changed = 1U; } else { @@ -660,17 +668,19 @@ static bool sub_update(uint8_t op) struct bt_mesh_lpn *lpn = &bt_mesh.lpn; int added_count = group_popcount(lpn->added); struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = lpn->frnd, - .send_ttl = 0, + .net_idx = bt_mesh.sub[0].net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = lpn->frnd, + .send_ttl = 0, + .send_cred = BLE_MESH_FRIENDSHIP_CRED, + /* Tag with immutable-credentials and as a friendship PDU */ + .send_tag = BLE_MESH_TAG_IMMUTABLE_CRED | BLE_MESH_TAG_FRIENDSHIP, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], - .ctx = &ctx, - .src = bt_mesh_primary_addr(), + .sub = &bt_mesh.sub[0], + .ctx = &ctx, + .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, - .friend_cred = true, }; struct bt_mesh_ctl_friend_sub req = {0}; size_t i = 0U, g = 0U; @@ -920,7 +930,7 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (bt_mesh_atomic_test_and_clear_bit(lpn->pending, i) && - bt_mesh_atomic_test_and_clear_bit(lpn->to_remove, i)) { + bt_mesh_atomic_test_and_clear_bit(lpn->to_remove, i)) { lpn->groups[i] = BLE_MESH_ADDR_UNASSIGNED; } } @@ -975,8 +985,8 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && - (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == - BLE_MESH_IV_UPDATE(msg->flags))) { + (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == + BLE_MESH_IV_UPDATE(msg->flags))) { bt_mesh_beacon_ivu_initiator(false); } @@ -988,7 +998,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, * credentials so we need to ensure the right ones (Friend * Credentials) were used for this message. */ - if (!rx->friend_cred) { + if (rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED) { BT_WARN("Friend Update with wrong credentials"); return -EINVAL; } @@ -1008,6 +1018,17 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, /* Set initial poll timeout */ lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), POLL_TIMEOUT_INIT); + + /* 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. + */ + /* TODO: + * Store - clear - restore directed forwarding state value of the subnet. + */ } friend_response_received(lpn); @@ -1019,7 +1040,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), rx->new_key)) { - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } bt_mesh_net_iv_update(iv_index, BLE_MESH_IV_UPDATE(msg->flags)); @@ -1065,8 +1086,6 @@ int bt_mesh_lpn_init(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("%s", __func__); - k_delayed_work_init(&lpn->timer, lpn_timeout); if (lpn->state == BLE_MESH_LPN_ENABLED) { diff --git a/components/bt/esp_ble_mesh/core/lpn.h b/components/bt/esp_ble_mesh/core/lpn.h index dbff49d624..7c1edd02d3 100644 --- a/components/bt/esp_ble_mesh/core/lpn.h +++ b/components/bt/esp_ble_mesh/core/lpn.h @@ -26,7 +26,7 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, static inline bool bt_mesh_lpn_established(void) { -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER return bt_mesh.lpn.established; #else return false; @@ -35,7 +35,7 @@ static inline bool bt_mesh_lpn_established(void) static inline bool bt_mesh_lpn_match(uint16_t addr) { -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER if (bt_mesh_lpn_established()) { return (addr == bt_mesh.lpn.frnd); } @@ -45,7 +45,7 @@ static inline bool bt_mesh_lpn_match(uint16_t addr) static inline bool bt_mesh_lpn_waiting_update(void) { -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER return (bt_mesh.lpn.state == BLE_MESH_LPN_WAIT_UPDATE); #else return false; @@ -54,7 +54,7 @@ static inline bool bt_mesh_lpn_waiting_update(void) static inline bool bt_mesh_lpn_timer(void) { -#if defined(CONFIG_BLE_MESH_LPN_AUTO) +#if CONFIG_BLE_MESH_LPN_AUTO return (bt_mesh.lpn.state == BLE_MESH_LPN_TIMER); #else return false; diff --git a/components/bt/esp_ble_mesh/core/main.c b/components/bt/esp_ble_mesh/core/main.c index 7b5a3c715a..deea8d74ee 100644 --- a/components/bt/esp_ble_mesh/core/main.c +++ b/components/bt/esp_ble_mesh/core/main.c @@ -12,9 +12,9 @@ #include "adv.h" #include "scan.h" -#include "prov_node.h" #include "beacon.h" #include "lpn.h" +#include "rpl.h" #include "friend.h" #include "transport.h" #include "access.h" @@ -25,9 +25,13 @@ #include "mesh/common.h" #include "proxy_client.h" #include "proxy_server.h" +#include "prov_common.h" +#include "prov_node.h" #include "prov_pvnr.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + static bool mesh_init = false; bool bt_mesh_is_initialized(void) @@ -45,9 +49,11 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, BT_INFO("Primary Element: 0x%04x", addr); BT_INFO("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", net_idx, flags, iv_index); - BT_INFO("dev_key %s", bt_hex(dev_key, 16)); + BT_INFO("DevKey %s", bt_hex(dev_key, 16)); + BT_INFO("NetKey %s", bt_hex(net_key, 16)); if (bt_mesh_atomic_test_and_set_bit(bt_mesh.flags, BLE_MESH_VALID)) { + BT_ERR("Already enter network!"); return -EALREADY; } @@ -63,6 +69,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); if (err) { + BT_ERR("Create network for node failed"); bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_VALID); if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && pb_gatt_enabled) { @@ -111,8 +118,9 @@ void bt_mesh_node_reset(void) bt_mesh_cfg_reset(true); - bt_mesh_rx_reset(true); + bt_mesh_rx_reset(); bt_mesh_tx_reset(); + bt_mesh_rpl_reset(true); if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { if (IS_ENABLED(CONFIG_BLE_MESH_LPN_SUB_ALL_NODES_ADDR)) { @@ -135,14 +143,22 @@ void bt_mesh_node_reset(void) (void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); bt_mesh_scan_disable(); - bt_mesh_beacon_disable(); + bt_mesh_secure_beacon_disable(); + +#if CONFIG_BLE_MESH_PRB_SRV + bt_mesh_private_beacon_disable(); +#endif bt_mesh_comp_unprovision(); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_clear_net(); bt_mesh_clear_seq(); + bt_mesh_clear_dkca(); bt_mesh_clear_role(); + if (IS_ENABLED(CONFIG_BLE_MESH_DF_SRV)) { + bt_mesh_clear_all_directed_forwarding_table_data(); + } } memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); @@ -175,20 +191,20 @@ bool bt_mesh_is_provisioner_en(void) { if (bt_mesh_is_provisioner()) { return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID_PROV); - } else { - return false; } + + return false; } static bool prov_bearers_valid(bt_mesh_prov_bearer_t bearers) { if ((!(bearers & (BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT))) || (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - !(bearers & BLE_MESH_PROV_ADV)) || + !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + !(bearers & BLE_MESH_PROV_ADV)) || (!IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - !(bearers & BLE_MESH_PROV_GATT))) { + IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && + !(bearers & BLE_MESH_PROV_GATT))) { BT_ERR("Invalid bearers 0x%02x", bearers); return false; } @@ -232,7 +248,7 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) } if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - (bearers & BLE_MESH_PROV_ADV)) { + (bearers & BLE_MESH_PROV_ADV)) { /* Make sure we're scanning for provisioning invitations */ err = bt_mesh_scan_enable(); if (err) { @@ -240,11 +256,11 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) } /* Enable unprovisioned beacon sending */ - bt_mesh_beacon_enable(); + bt_mesh_secure_beacon_enable(); } if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (bearers & BLE_MESH_PROV_GATT)) { + (bearers & BLE_MESH_PROV_GATT)) { bt_mesh_proxy_server_prov_enable(); bt_mesh_adv_update(); } @@ -270,13 +286,13 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) } if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - (bearers & BLE_MESH_PROV_ADV)) { - bt_mesh_beacon_disable(); + (bearers & BLE_MESH_PROV_ADV)) { + bt_mesh_secure_beacon_disable(); bt_mesh_scan_disable(); } if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (bearers & BLE_MESH_PROV_GATT)) { + (bearers & BLE_MESH_PROV_GATT)) { bt_mesh_proxy_server_prov_disable(true); } @@ -313,10 +329,16 @@ int bt_mesh_suspend(void) bt_mesh_hb_pub_disable(); - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_disable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_disable(); } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_disable(); + } +#endif + bt_mesh_model_foreach(model_suspend, NULL); return 0; @@ -353,10 +375,16 @@ int bt_mesh_resume(void) return err; } - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_enable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_enable(); } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_enable(); + } +#endif + bt_mesh_model_foreach(model_resume, NULL); return err; @@ -372,6 +400,13 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, return -EALREADY; } + extern int bt_mesh_v11_ext_init(void); + err = bt_mesh_v11_ext_init(); + if (err) { + BT_ERR("Bluetooth Mesh v1.1 init failed"); + return err; + } + bt_mesh_mutex_init(); bt_mesh_timer_init(); @@ -401,15 +436,28 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, bt_mesh_proxy_client_init(); } +#if CONFIG_BLE_MESH_PROXY_SOLIC + err = bt_mesh_proxy_solic_init(); + if (err) { + return err; + } +#endif + if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { + err = bt_mesh_prov_set(prov); + if (err) { + return err; + } + if (IS_ENABLED(CONFIG_BLE_MESH_NODE)) { - err = bt_mesh_prov_init(prov); + err = bt_mesh_prov_init(); if (err) { return err; } } + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER)) { - err = bt_mesh_provisioner_prov_init(prov); + err = bt_mesh_provisioner_prov_init(); if (err) { return err; } @@ -417,6 +465,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, } bt_mesh_net_init(); + bt_mesh_trans_init(); /* Changed by Espressif, add a random delay (0 ~ 3s) */ @@ -458,7 +507,11 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) } bt_mesh_scan_disable(); - bt_mesh_beacon_disable(); + bt_mesh_secure_beacon_disable(); + +#if CONFIG_BLE_MESH_PRB_SRV + bt_mesh_private_beacon_disable(); +#endif if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && @@ -507,21 +560,28 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) return err; } } + + bt_mesh_prov_set(NULL); } bt_mesh_trans_deinit(param->erase); + bt_mesh_net_deinit(); bt_mesh_beacon_deinit(); +#if CONFIG_BLE_MESH_PROXY_SOLIC + bt_mesh_proxy_solic_deinit(); +#endif + if ((IS_ENABLED(CONFIG_BLE_MESH_NODE) && - IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || + IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { bt_mesh_proxy_server_deinit(); } if ((IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && - IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || + IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)) { bt_mesh_proxy_client_deinit(); } @@ -560,7 +620,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) } #endif /* CONFIG_BLE_MESH_DEINIT */ -#if defined(CONFIG_BLE_MESH_PROVISIONER) +#if CONFIG_BLE_MESH_PROVISIONER int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) { int err = 0; @@ -616,22 +676,24 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) bt_mesh_comp_provision(bt_mesh_provisioner_get_primary_elem_addr()); -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - (bearers & BLE_MESH_PROV_ADV)) { + (bearers & BLE_MESH_PROV_ADV)) { bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, + NULL); } if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (bearers & BLE_MESH_PROV_GATT)) { + (bearers & BLE_MESH_PROV_GATT)) { bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, + NULL); } #endif if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (bearers & BLE_MESH_PROV_GATT)) { + (bearers & BLE_MESH_PROV_GATT)) { bt_mesh_proxy_client_prov_enable(); } @@ -639,10 +701,16 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) bt_mesh_friend_init(); } - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_enable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_enable(); } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_enable(); + } +#endif + err = bt_mesh_scan_enable(); if (err) { return err; @@ -673,12 +741,14 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) bt_mesh_provisioner_set_prov_bearer(bearers, true); if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (enable & BLE_MESH_PROV_GATT) && - (bearers & BLE_MESH_PROV_GATT)) { + (enable & BLE_MESH_PROV_GATT) && + (bearers & BLE_MESH_PROV_GATT)) { bt_mesh_proxy_client_prov_disable(); -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, + NULL); #endif } @@ -686,11 +756,12 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) /* Provisioner is disabled completely, disable scan here */ bt_mesh_scan_disable(); -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - (enable & BLE_MESH_PROV_ADV)) { + (enable & BLE_MESH_PROV_ADV)) { bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, + NULL); } #endif @@ -702,10 +773,16 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) * its previous information can be recovered from flash properly. */ - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_disable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_disable(); } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_disable(); + } +#endif + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); } diff --git a/components/bt/esp_ble_mesh/core/mesh.h b/components/bt/esp_ble_mesh/core/mesh.h index cb6efd0dc0..c939224069 100644 --- a/components/bt/esp_ble_mesh/core/mesh.h +++ b/components/bt/esp_ble_mesh/core/mesh.h @@ -16,13 +16,19 @@ extern "C" { #endif -#define BLE_MESH_KEY_PRIMARY 0x0000 -#define BLE_MESH_KEY_ANY 0xffff +#define BLE_MESH_KEY_PRIMARY 0x0000 +#define BLE_MESH_KEY_ANY 0xFFFF -#define BLE_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) -#define BLE_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) < 0xff00) -#define BLE_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000) -#define BLE_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb) +#define BLE_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) +#define BLE_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xC000) +#define BLE_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xC000 && (addr) < 0xFF00) +/* Currently not including all-ipt-nodes & all-ipt-border-routers in RFU & fixed group */ +#define BLE_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xFF00 && (addr) <= 0xFFFA) +#define BLE_MESH_ADDR_IS_FIXED_GROUP(addr) ((addr) >= 0xFFFB && ((addr) < 0xFFFF || (addr) == 0xFFFF)) + +#define BLE_MESH_SUPPORTING_TYPE_FRIEND 1 +#define BLE_MESH_SUPPORTING_TYPE_PROXY 2 +#define BLE_MESH_SUPPORTING_TYPE_SBR 3 struct bt_mesh_net; diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 89274121ad..fef500e663 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,17 +16,23 @@ #include "scan.h" #include "mesh.h" #include "lpn.h" +#include "rpl.h" #include "friend.h" #include "transport.h" #include "access.h" #include "foundation.h" #include "beacon.h" #include "settings.h" +#include "fast_prov.h" #include "prov_node.h" +#include "test.h" +#include "fast_prov.h" #include "proxy_client.h" #include "proxy_server.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + /* Minimum valid Mesh Network PDU length. The Network headers * themselves take up 9 bytes. After that there is a minumum of 1 byte * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 @@ -38,18 +44,10 @@ /* Seq limit after IV Update is triggered */ #define IV_UPDATE_SEQ_LIMIT 8000000 -#define IVI(pdu) ((pdu)[0] >> 7) -#define NID(pdu) ((pdu)[0] & 0x7f) -#define CTL(pdu) ((pdu)[1] >> 7) -#define TTL(pdu) ((pdu)[1] & 0x7f) -#define SEQ(pdu) (sys_get_be24(&(pdu)[2])) -#define SRC(pdu) (sys_get_be16(&(pdu)[5])) -#define DST(pdu) (sys_get_be16(&(pdu)[7])) - /* Determine how many friendship credentials we need */ -#if defined(CONFIG_BLE_MESH_FRIEND) +#if CONFIG_BLE_MESH_FRIEND #define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT -#elif defined(CONFIG_BLE_MESH_LOW_POWER) +#elif CONFIG_BLE_MESH_LOW_POWER #define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT #else #define FRIEND_CRED_COUNT 0 @@ -83,7 +81,7 @@ struct bt_mesh_net bt_mesh = { static uint32_t dup_cache[4]; static int dup_cache_next; -#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#if CONFIG_BLE_MESH_RELAY_ADV_BUF #define BLE_MESH_MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) #endif @@ -113,8 +111,8 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx, int i; for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { - if (msg_cache[i].src == SRC(pdu->data) && - msg_cache[i].seq == (SEQ(pdu->data) & BIT_MASK(17))) { + if (msg_cache[i].src == BLE_MESH_NET_HDR_SRC(pdu->data) && + msg_cache[i].seq == (BLE_MESH_NET_HDR_SEQ(pdu->data) & BIT_MASK(17))) { return true; } } @@ -146,16 +144,35 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num) struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) { - int i; + if (bt_mesh_is_provisioned()) { +#if CONFIG_BLE_MESH_NODE + if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { + if (net_idx == BLE_MESH_KEY_ANY) { + return &bt_mesh.sub[0]; + } - if (net_idx == BLE_MESH_KEY_ANY) { - return &bt_mesh.sub[0]; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx == net_idx) { - return &bt_mesh.sub[i]; + for (int i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx == net_idx) { + return &bt_mesh.sub[i]; + } + } + } else { + return bt_mesh_fast_prov_subnet_get(net_idx); } +#endif + } else if (bt_mesh_is_provisioner_en()) { +#if CONFIG_BLE_MESH_PROVISIONER + if (net_idx == BLE_MESH_KEY_ANY) { + return bt_mesh.p_sub[0]; + } + + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + if (bt_mesh.p_sub[i] && + bt_mesh.p_sub[i]->net_idx == net_idx) { + return bt_mesh.p_sub[i]; + } + } +#endif } return NULL; @@ -189,7 +206,7 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, BT_DBG("NetID %s", bt_hex(keys->net_id, 8)); -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER err = bt_mesh_identity_key(key, keys->identity); if (err) { BT_ERR("Unable to generate IdentityKey"); @@ -199,7 +216,7 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, BT_DBG("IdentityKey %s", bt_hex(keys->identity, 16)); #endif /* GATT_PROXY */ - err = bt_mesh_beacon_key(key, keys->beacon); + err = bt_mesh_secure_beacon_key(key, keys->beacon); if (err) { BT_ERR("Unable to generate beacon key"); return err; @@ -207,18 +224,39 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, BT_DBG("BeaconKey %s", bt_hex(keys->beacon, 16)); +#if CONFIG_BLE_MESH_PRIVATE_BEACON + err = bt_mesh_private_beacon_key(key, keys->private_beacon); + if (err) { + BT_ERR("Unable to generate private beacon key"); + return err; + } + + BT_DBG("PrivateBeaconKey %s", bt_hex(keys->private_beacon, 16)); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ + +#if CONFIG_BLE_MESH_DF_SRV + p[0] = 0x02; + + err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->direct_enc, keys->direct_privacy); + if (err) { + BT_ERR("Unable to generate directed NID, EncKey & PrivacyKey"); + return err; + } + + keys->direct_nid = nid; +#endif /* CONFIG_BLE_MESH_DF_SRV */ + return 0; } -#if (defined(CONFIG_BLE_MESH_LOW_POWER) || \ - defined(CONFIG_BLE_MESH_FRIEND)) +#if (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key[16]) { uint16_t lpn_addr = 0U, frnd_addr = 0U; uint8_t p[9] = {0}; int err = 0; -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER if (cred->addr == bt_mesh.lpn.frnd) { lpn_addr = bt_mesh_primary_addr(); frnd_addr = cred->addr; @@ -263,7 +301,7 @@ void friend_cred_refresh(uint16_t net_idx) struct friend_cred *cred = &friend_cred[i]; if (cred->addr != BLE_MESH_ADDR_UNASSIGNED && - cred->net_idx == net_idx) { + cred->net_idx == net_idx) { memcpy(&cred->cred[0], &cred->cred[1], sizeof(cred->cred[0])); } @@ -280,7 +318,7 @@ int friend_cred_update(struct bt_mesh_subnet *sub) struct friend_cred *cred = &friend_cred[i]; if (cred->addr == BLE_MESH_ADDR_UNASSIGNED || - cred->net_idx != sub->net_idx) { + cred->net_idx != sub->net_idx) { continue; } @@ -303,8 +341,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) { if ((friend_cred[i].addr == BLE_MESH_ADDR_UNASSIGNED) || - (friend_cred[i].addr == addr && - friend_cred[i].net_idx == sub->net_idx)) { + (friend_cred[i].addr == addr && + friend_cred[i].net_idx == sub->net_idx)) { cred = &friend_cred[i]; break; } @@ -420,7 +458,7 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) return flags; } -int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub) +int bt_mesh_net_secure_beacon_update(struct bt_mesh_subnet *sub) { uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; @@ -435,8 +473,8 @@ int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub) BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); - return bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, - bt_mesh.iv_index, sub->auth); + return bt_mesh_secure_beacon_auth(keys->beacon, flags, keys->net_id, + bt_mesh.iv_index, sub->auth); } int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], @@ -475,6 +513,9 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; } else { sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; +#if CONFIG_BLE_MESH_PRB_SRV + sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED; +#endif } bt_mesh.iv_index = iv_index; @@ -488,7 +529,11 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], bt_mesh.ivu_duration = BLE_MESH_IVU_MIN_HOURS; /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); + +#if CONFIG_BLE_MESH_DF_SRV + return bt_mesh_directed_forwarding_sub_init(sub); +#endif return 0; } @@ -565,7 +610,7 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) bt_mesh_net_revoke_keys(sub); if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { + IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { friend_cred_refresh(sub->net_idx); } @@ -576,31 +621,7 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) return false; } -void bt_mesh_rpl_reset(void) -{ - int i; - - /* Discard "old old" IV Index entries from RPL and flag - * any other ones (which are valid) as old. - */ - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - - if (rpl->src) { - if (rpl->old_iv) { - (void)memset(rpl, 0, sizeof(*rpl)); - } else { - rpl->old_iv = true; - } - - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } - } - } -} - -#if defined(CONFIG_BLE_MESH_IV_UPDATE_TEST) +#if CONFIG_BLE_MESH_IV_UPDATE_TEST void bt_mesh_iv_update_test(bool enable) { bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_TEST, enable); @@ -635,7 +656,11 @@ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) } if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { + (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED +#if CONFIG_BLE_MESH_PRB_SRV + || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED +#endif + )) { bt_mesh_proxy_server_beacon_send(sub); } } @@ -666,13 +691,23 @@ 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) { + 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 + * procedure see Section 3.10.6 + */ if ((iv_index > bt_mesh.iv_index + 1) #if CONFIG_BLE_MESH_IVU_RECOVERY_IVI || (iv_index == bt_mesh.iv_index + 1 && !iv_update) @@ -685,6 +720,13 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) goto do_update; } + /* If a node in Normal Operation receives a Secure Network beacon + * or a Mesh Private beacon with an IV index equal to the last known + * IV index+1 and the IV Update Flag set to 0, the node may update + * its IV without going to the IV Update in Progress state, or it may + * initiate an IV Index Recovery procedure(Section 3.10.6), or it may + * ignore the Secure Network beacon or the Mesh Private beacon. + */ #if !CONFIG_BLE_MESH_IVU_RECOVERY_IVI if (iv_index == bt_mesh.iv_index + 1 && !iv_update) { BT_WARN("Ignoring new index in normal mode"); @@ -700,7 +742,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) } if (!(IS_ENABLED(CONFIG_BLE_MESH_IV_UPDATE_TEST) && - bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_TEST))) { + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_TEST))) { if (bt_mesh.ivu_duration < BLE_MESH_IVU_MIN_HOURS) { BT_WARN("IV Update before minimum duration"); return false; @@ -721,9 +763,9 @@ do_update: if (iv_update) { bt_mesh.iv_index = iv_index; BT_INFO("IV Update state entered. New index 0x%08x", - bt_mesh.iv_index); + bt_mesh.iv_index); - bt_mesh_rpl_reset(); + bt_mesh_rpl_update(); } else { BT_INFO("Normal mode entered"); bt_mesh.seq = 0U; @@ -736,7 +778,7 @@ do_update: for (i = 0; i < subnet_size; i++) { struct bt_mesh_subnet *sub = bt_mesh_rx_netkey_get(i); if (sub && sub->net_idx != BLE_MESH_KEY_UNUSED) { - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); } } @@ -749,14 +791,8 @@ do_update: bool bt_mesh_primary_subnet_exist(void) { - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { - if (bt_mesh_subnet_get(BLE_MESH_KEY_PRIMARY)) { - return true; - } - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { - if (bt_mesh_provisioner_subnet_get(BLE_MESH_KEY_PRIMARY)) { - return true; - } + if (bt_mesh_subnet_get(BLE_MESH_KEY_PRIMARY)) { + return true; } return false; @@ -771,8 +807,8 @@ uint32_t bt_mesh_next_seq(void) } if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) && - bt_mesh.seq > IV_UPDATE_SEQ_LIMIT && - bt_mesh_primary_subnet_exist()) { + bt_mesh.seq > IV_UPDATE_SEQ_LIMIT && + bt_mesh_primary_subnet_exist()) { bt_mesh_beacon_ivu_initiator(true); bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); bt_mesh_net_sec_update(NULL); @@ -782,8 +818,8 @@ uint32_t bt_mesh_next_seq(void) } int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, - bool new_key, const struct bt_mesh_send_cb *cb, - void *cb_data) + bool new_key, uint8_t *tx_cred, uint8_t tx_tag, + const struct bt_mesh_send_cb *cb, void *cb_data) { const uint8_t *enc = NULL, *priv = NULL; uint32_t seq = 0U; @@ -793,8 +829,48 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key, buf->len); - enc = sub->keys[new_key].enc; - priv = sub->keys[new_key].privacy; + /* Previously when resending the segments, only managed flooding + * security credentials will be used. + * Now for the segments retransmission, try to get the security + * credentials based on the parameters "tx_cred" and "tag". + * + * Note: + * Use "tag" here in case the friendship is terminated, which will + * cause the friendship security credentials are deleted. + * + * TODO: + * Potential issue here, if the subnet is deleted, exception (on + * Provisioner) will happen. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + *tx_cred == BLE_MESH_FRIENDSHIP_CRED) { + err = friend_cred_get(sub, BLE_MESH_ADDR_UNASSIGNED, NULL, &enc, &priv); + if (err) { + /* If tagged with immutable-credentials, then no + * falling back should happen. + */ + if (bt_mesh_tag_immutable_cred(tx_tag)) { + BT_ERR("Resend, no friendship credentials found"); + return err; + } + + BT_WARN("Falling back to managed flooding credentials"); + + *tx_cred = BLE_MESH_FLOODING_CRED; + enc = sub->keys[new_key].enc; + priv = sub->keys[new_key].privacy; + } + } +#if CONFIG_BLE_MESH_DF_SRV + else if (*tx_cred == BLE_MESH_DIRECTED_CRED) { + enc = sub->keys[new_key].direct_enc; + priv = sub->keys[new_key].direct_privacy; + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ + else { + enc = sub->keys[new_key].enc; + priv = sub->keys[new_key].privacy; + } err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); if (err) { @@ -802,7 +878,7 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, return err; } - err = bt_mesh_net_decrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false); + err = bt_mesh_net_decrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { BT_ERR("Decrypt failed (err %d)", err); return err; @@ -813,9 +889,9 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, sys_put_be24(seq, &buf->data[2]); /* Get destination, in case it's a proxy client */ - dst = DST(buf->data); + dst = BLE_MESH_NET_HDR_DST(buf->data); - err = bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false); + err = bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { BT_ERR("Encrypt failed (err %d)", err); return err; @@ -840,11 +916,11 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, return 0; } - bt_mesh_adv_send(buf, cb, cb_data); + bt_mesh_adv_send(buf, BLE_MESH_ADV(buf)->xmit, cb, cb_data); return 0; } -static void bt_mesh_net_local(struct k_work *work) +static void bt_mesh_net_local(void) { struct net_buf *buf = NULL; @@ -866,7 +942,9 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, if (ctl && net_buf_simple_tailroom(buf) < BLE_MESH_MIC_LONG) { BT_ERR("Insufficient MIC space for CTL PDU"); return -EINVAL; - } else if (net_buf_simple_tailroom(buf) < BLE_MESH_MIC_SHORT) { + } + + if (net_buf_simple_tailroom(buf) < BLE_MESH_MIC_SHORT) { BT_ERR("Insufficient MIC space for PDU"); return -EINVAL; } @@ -885,19 +963,39 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, net_buf_simple_push_u8(buf, tx->ctx->send_ttl); } - if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && tx->friend_cred) { - if (friend_cred_get(tx->sub, BLE_MESH_ADDR_UNASSIGNED, - &nid, &enc, &priv)) { - BT_WARN("Falling back to master credentials"); + BT_INFO("Use security credentials 0x%02x, proxy %d", tx->ctx->send_cred, proxy); - tx->friend_cred = 0U; + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && + tx->ctx->send_cred == BLE_MESH_FRIENDSHIP_CRED) { + err = friend_cred_get(tx->sub, BLE_MESH_ADDR_UNASSIGNED, + &nid, &enc, &priv); + if (err) { + /* If tagged with immutable-credentials, then no + * falling back should happen. + */ + if (bt_mesh_tag_immutable_cred(tx->ctx->send_tag)) { + BT_ERR("No friendship credentials found"); + return err; + } + + BT_WARN("Falling back to managed flooding credentials"); + + tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; nid = tx->sub->keys[tx->sub->kr_flag].nid; enc = tx->sub->keys[tx->sub->kr_flag].enc; priv = tx->sub->keys[tx->sub->kr_flag].privacy; } - } else { - tx->friend_cred = 0U; + } +#if CONFIG_BLE_MESH_DF_SRV + else if (tx->ctx->send_cred == BLE_MESH_DIRECTED_CRED) { + nid = tx->sub->keys[tx->sub->kr_flag].direct_nid; + enc = tx->sub->keys[tx->sub->kr_flag].direct_enc; + priv = tx->sub->keys[tx->sub->kr_flag].direct_privacy; + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ + else { + tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; nid = tx->sub->keys[tx->sub->kr_flag].nid; enc = tx->sub->keys[tx->sub->kr_flag].enc; priv = tx->sub->keys[tx->sub->kr_flag].privacy; @@ -905,7 +1003,7 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, net_buf_simple_push_u8(buf, (nid | (BLE_MESH_NET_IVI_TX & 1) << 7)); - err = bt_mesh_net_encrypt(enc, buf, BLE_MESH_NET_IVI_TX, proxy); + err = bt_mesh_net_encrypt(enc, buf, BLE_MESH_NET_IVI_TX, proxy, false); if (err) { return err; } @@ -916,6 +1014,7 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { + uint8_t bearer = BLE_MESH_ALL_BEARERS; int err = 0; BT_DBG("src 0x%04x dst 0x%04x len %u headroom %u tailroom %u", @@ -928,31 +1027,81 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, tx->ctx->send_ttl = bt_mesh_default_ttl_get(); } + /* 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 + * as relay. + */ + if (tx->ctx->send_ttl == 1U && + !bt_mesh_tag_relay(tx->ctx->send_tag)) { + BT_WARN("Ignore PDU with TTL=1 but not tagged as relay"); + err = -EIO; + goto done; + } + + /* Spec: + * If the message security material is not set by the network + * layer or any higher layer, the message shall be secured + * using the managed flooding security credentials. + * + * Note: + * Currently no need to add any code for this here, because if + * the security material is not set, the "tx->ctx->send_cred" + * will be initialized to 0x00, which will be used as managed + * flooding security credentials. + */ + +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_update_net_send_cred(tx, &bearer); +#endif /* CONFIG_BLE_MESH_DF_SRV */ + err = bt_mesh_net_encode(tx, &buf->b, false); if (err) { goto done; } +#if CONFIG_BLE_MESH_SELF_TEST + if (net_pdu_test_cb) { + net_pdu_test_cb(buf->data, buf->len); + goto done; + } +#endif /* CONFIG_BLE_MESH_SELF_TEST */ + /* Deliver to GATT Proxy Clients if necessary. Mesh spec 3.4.5.2: * "The output filter of the interface connected to advertising or - * GATT bearers shall drop all messages with TTL value set to 1." + * GATT bearers shall drop all messages with the TTL value set to + * 1 unless they contain a network PDU that is tagged as relay." + * + * "The output filter of the interface connected to the GATT bearer + * shall drop all messages secured using the friendship security + * credentials." */ + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - tx->ctx->send_ttl != 1U) { + (bearer & BLE_MESH_GATT_BEARER) && + (tx->ctx->send_ttl != 1U || + bt_mesh_tag_relay(tx->ctx->send_tag)) && + tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_server_relay(&buf->b, tx->ctx->addr) && - BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* Notify completion if this only went * through the Mesh Proxy. */ - send_cb_finalize(cb, cb_data); + if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { + send_cb_finalize(cb, cb_data); + + err = 0; + goto done; + } - err = 0; - goto done; } } if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) && - tx->ctx->send_ttl != 1U) { + (bearer & BLE_MESH_GATT_BEARER) && + (tx->ctx->send_ttl != 1U || + bt_mesh_tag_relay(tx->ctx->send_tag)) && + tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_client_relay(&buf->b, tx->ctx->addr)) { /* If Proxy Client succeeds to send messages with GATT bearer, * we can directly finish here. And if not, which means no @@ -967,26 +1116,53 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, } /* Deliver to local network interface if necessary */ - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && - (bt_mesh_fixed_group_match(tx->ctx->addr) || - bt_mesh_elem_find(tx->ctx->addr))) { + if (((IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) || + (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en())) && + (bt_mesh_fixed_group_match(tx->ctx->addr) || bt_mesh_elem_find(tx->ctx->addr))) { if (cb && cb->start) { cb->start(0, 0, cb_data); } + net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + if (cb && cb->end) { cb->end(0, cb_data); } - k_work_submit(&bt_mesh.local_work); - } else if (tx->ctx->send_ttl != 1U) { + + bt_mesh_net_local(); + + err = 0; + goto done; + } + + if ((bearer & BLE_MESH_ADV_BEARER) && + (tx->ctx->send_ttl != 1U || bt_mesh_tag_relay(tx->ctx->send_tag))) { /* Deliver to the advertising network interface. Mesh spec * 3.4.5.2: "The output filter of the interface connected to * advertising or GATT bearers shall drop all messages with * TTL value set to 1." + * Spec v1.1 adds additional condition: + * "unless they contain a network PDU that is tagged as relay" + * + * "tx->xmit" has already been initialized in the access.c + * (i.e. bt_mesh_model_send() & bt_mesh_model_publish()). + * Here xmit may needs to be updated according Mesh spec 3.4.6. */ - bt_mesh_adv_send(buf, cb, cb_data); + bt_mesh_net_adv_xmit_update(tx); + + BT_INFO("Network PDU, count %d, interval %d", + BLE_MESH_TRANSMIT_COUNT(tx->xmit), BLE_MESH_TRANSMIT_INT(tx->xmit)); + bt_mesh_adv_send(buf, tx->xmit, cb, cb_data); + + err = 0; + goto done; } + BT_WARN("Not sent, src 0x%04x, dst 0x%04x, ttl %d, cred 0x%02x, tag 0x%02x", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, tx->ctx->send_cred, + tx->ctx->send_tag); + err = -EIO; + done: net_buf_unref(buf); return err; @@ -1002,8 +1178,8 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, return false; } - bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, iv_index, - net_auth); + bt_mesh_secure_beacon_auth(keys->beacon, flags, keys->net_id, iv_index, + net_auth); if (memcmp(auth, net_auth, 8)) { BT_WARN("Authentication Value %s != %s", @@ -1014,9 +1190,9 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, return true; } -struct bt_mesh_subnet *bt_mesh_subnet_find(const uint8_t net_id[8], uint8_t flags, - uint32_t iv_index, const uint8_t auth[8], - bool *new_key) +struct bt_mesh_subnet *bt_mesh_subnet_find_with_snb(const uint8_t net_id[8], uint8_t flags, + uint32_t iv_index, const uint8_t auth[8], + bool *new_key) { size_t subnet_size = 0U; int i; @@ -1048,15 +1224,15 @@ struct bt_mesh_subnet *bt_mesh_subnet_find(const uint8_t net_id[8], uint8_t flag return NULL; } -static int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, - const uint8_t *priv, const uint8_t *data, - size_t data_len, struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf) +int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, + const uint8_t *priv, const uint8_t *data, + size_t data_len, struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) { - BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); - BT_DBG("IVI %u net->iv_index 0x%08x", IVI(data), bt_mesh.iv_index); + BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + BT_DBG("IVI %u net->iv_index 0x%08x", BLE_MESH_NET_HDR_IVI(data), bt_mesh.iv_index); - rx->old_iv = (IVI(data) != (bt_mesh.iv_index & 0x01)); + rx->old_iv = (BLE_MESH_NET_HDR_IVI(data) != (bt_mesh.iv_index & 0x01)); net_buf_simple_reset(buf); memcpy(net_buf_simple_add(buf, data_len), data, data_len); @@ -1065,7 +1241,7 @@ static int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, return -ENOENT; } - rx->ctx.addr = SRC(buf->data); + 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); return -EINVAL; @@ -1079,23 +1255,22 @@ static int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, BT_DBG("src 0x%04x", rx->ctx.addr); if (IS_ENABLED(CONFIG_BLE_MESH_PROXY) && - rx->net_if == BLE_MESH_NET_IF_PROXY_CFG) { + rx->net_if == BLE_MESH_NET_IF_PROXY_CFG) { return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), - true); + true, false); } - return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), false); + return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), false, false); } -#if (defined(CONFIG_BLE_MESH_LOW_POWER) || \ - defined(CONFIG_BLE_MESH_FRIEND)) +#if (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, size_t data_len, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { int i; - BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); + BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -1104,9 +1279,9 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, continue; } - if (NID(data) == cred->cred[0].nid && - !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, - data, data_len, rx, buf)) { + if (BLE_MESH_NET_HDR_NID(data) == cred->cred[0].nid && + !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, + data, data_len, rx, buf)) { return 0; } @@ -1114,9 +1289,9 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, continue; } - if (NID(data) == cred->cred[1].nid && - !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, - data, data_len, rx, buf)) { + if (BLE_MESH_NET_HDR_NID(data) == cred->cred[1].nid && + !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, + data, data_len, rx, buf)) { rx->new_key = 1U; return 0; } @@ -1124,7 +1299,33 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, return -ENOENT; } -#endif +#endif /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ + +static int flooding_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, + size_t data_len, struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + + if (BLE_MESH_NET_HDR_NID(data) == sub->keys[0].nid && + !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, + data, data_len, rx, buf)) { + return 0; + } + + if (sub->kr_phase == BLE_MESH_KR_NORMAL) { + return -ENOENT; + } + + if (BLE_MESH_NET_HDR_NID(data) == sub->keys[1].nid && + !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, + data, data_len, rx, buf)) { + rx->new_key = 1U; + return 0; + } + + return -ENOENT; +} static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, struct bt_mesh_net_rx *rx, @@ -1134,8 +1335,6 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, size_t array_size = 0U; int i; - BT_DBG("%s", __func__); - array_size = bt_mesh_rx_netkey_size(); for (i = 0; i < array_size; i++) { @@ -1149,31 +1348,30 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, continue; } -#if (defined(CONFIG_BLE_MESH_LOW_POWER) || defined(CONFIG_BLE_MESH_FRIEND)) +#if CONFIG_BLE_MESH_BRC_SRV + sub->sbr_net_idx = BLE_MESH_KEY_UNUSED; +#endif + +#if (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) if (!friend_decrypt(sub, data, data_len, rx, buf)) { - rx->friend_cred = 1; + rx->ctx.recv_cred = BLE_MESH_FRIENDSHIP_CRED; rx->ctx.net_idx = sub->net_idx; rx->sub = sub; return true; } #endif - if (NID(data) == sub->keys[0].nid && - !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, - data, data_len, rx, buf)) { +#if CONFIG_BLE_MESH_DF_SRV + if (!bt_mesh_directed_decrypt(sub, data, data_len, rx, buf)) { + rx->ctx.recv_cred = BLE_MESH_DIRECTED_CRED; rx->ctx.net_idx = sub->net_idx; rx->sub = sub; return true; } +#endif /* CONFIG_BLE_MESH_DF_SRV */ - if (sub->kr_phase == BLE_MESH_KR_NORMAL) { - continue; - } - - if (NID(data) == sub->keys[1].nid && - !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, - data, data_len, rx, buf)) { - rx->new_key = 1U; + if (!flooding_decrypt(sub, data, data_len, rx, buf)) { + rx->ctx.recv_cred = BLE_MESH_FLOODING_CRED; rx->ctx.net_idx = sub->net_idx; rx->sub = sub; return true; @@ -1207,7 +1405,12 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, { const uint8_t *enc = NULL, *priv = NULL; struct net_buf *buf = NULL; - uint8_t nid = 0U, transmit = 0U; + uint8_t bearer = 0; + uint8_t xmit = 0U; + uint8_t cred = 0; + uint8_t nid = 0U; + bool netkey_changed = false; + uint8_t tag = 0; if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { /* Locally originated PDUs with TTL=1 will only be delivered @@ -1216,52 +1419,100 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, * advertising or GATT bearers shall drop all messages with * TTL value set to 1." */ + /* For local network interface, no outbound bearer will be found. + * So currently if a PDU is received from local network interface + * with TTL=1, it will be ignored here. + */ if (rx->ctx.recv_ttl == 1U) { return; } } else { - if (rx->ctx.recv_ttl <= 1U) { + /* Only PDU with TTL=0 will be ignored here. PDU with TTL=1 will + * be checked later to see if it could be tagged with RELAY. + */ + if (rx->ctx.recv_ttl < 1U) { return; } } +#if 0 + /* This could be moved, since in mesh v1.1, two more conditions could + * cause a message to be relayed, i.e. directed forwarding and subnet + * bridge. + * The two conditions will be checked with retransmission requirements. + */ if (rx->net_if == BLE_MESH_NET_IF_ADV && - !rx->friend_cred && - bt_mesh_relay_get() != BLE_MESH_RELAY_ENABLED && - bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_ENABLED) { + bt_mesh_relay_get() != BLE_MESH_RELAY_ENABLED && + bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_ENABLED && + rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED) { + return; + } +#endif + + /* Mesh spec 3.4.6.3: + * "The Network PDU shall be evaluated against retransmission conditions + * for incoming Network PDUs as defined in Table 3.10. For a Network PDU, + * there may be more than one matching row in Table 3.10. If there is no + * row that matches the retransmission conditions, then the Network PDU + * shall not be retransmitted." + */ + bearer = bt_mesh_net_retrans_match(rx, &cred, &tag); + if (bearer == BLE_MESH_NONE_BEARER) { + BT_WARN("No outbound bearer found, inbound bearer %d", rx->net_if); return; } - BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, - rx->ctx.recv_dst); + if (cred != BLE_MESH_FLOODING_CRED +#if CONFIG_BLE_MESH_DF_SRV + && cred != BLE_MESH_DIRECTED_CRED +#endif + ) { + BT_WARN("No outbound security cred found, inbound cred %d", rx->ctx.recv_cred); + 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"); + return; + } + + BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, rx->ctx.recv_dst); /* The Relay Retransmit state is only applied to adv-adv relaying. * Anything else (like GATT to adv, or locally originated packets) * use the Network Transmit state. */ - if (rx->net_if == BLE_MESH_NET_IF_ADV && !rx->friend_cred) { - transmit = bt_mesh_relay_retransmit_get(); + if (rx->net_if == BLE_MESH_NET_IF_ADV && + rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED) { + xmit = bt_mesh_relay_retransmit_get(); } else { - transmit = bt_mesh_net_transmit_get(); + xmit = bt_mesh_net_transmit_get(); } - /** +#if 0 + /* TODO: Needs further thinking. */ + xmit = bt_mesh_net_adv_xmit_update(cred, tag, rx->ctl); + if (xmit == 0) { + return; + } +#endif + + /* TODO: * When the node tries to relay a Segment ACK message, in this case * the corresponding segment packets (if exist) can be removed from * the relay queue. */ -#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) - buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, transmit, K_NO_WAIT); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); #else - /** - * Check if the number of relay packets in queue is too large, if so + /* Check if the number of relay packets in queue is too large, if so * use minimum relay retransmit value for later relay packets. */ if (bt_mesh_get_stored_relay_count() >= BLE_MESH_MAX_STORED_RELAY_COUNT) { - transmit = BLE_MESH_TRANSMIT(0, 20); + xmit = BLE_MESH_TRANSMIT(0, 20); } - buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_DATA, transmit, K_NO_WAIT); + buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); #endif if (!buf) { @@ -1278,14 +1529,31 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, net_buf_add_mem(buf, sbuf->data, sbuf->len); - enc = rx->sub->keys[rx->sub->kr_flag].enc; - priv = rx->sub->keys[rx->sub->kr_flag].privacy; - nid = rx->sub->keys[rx->sub->kr_flag].nid; + if (cred == BLE_MESH_FLOODING_CRED) { + enc = rx->sub->keys[rx->sub->kr_flag].enc; + priv = rx->sub->keys[rx->sub->kr_flag].privacy; + nid = rx->sub->keys[rx->sub->kr_flag].nid; +#if CONFIG_BLE_MESH_DF_SRV + } else { + enc = rx->sub->keys[rx->sub->kr_flag].direct_enc; + priv = rx->sub->keys[rx->sub->kr_flag].direct_privacy; + nid = rx->sub->keys[rx->sub->kr_flag].direct_nid; +#endif /* CONFIG_BLE_MESH_DF_SRV */ + } - BT_DBG("Relaying packet. TTL is now %u", TTL(buf->data)); +#if CONFIG_BLE_MESH_BRC_SRV + /* Check if subnet bridge is supported & decide which NetKey is used */ + if (bt_mesh_subnet_bridge_state_get() == BLE_MESH_SUBNET_BRIDGE_ENABLED) { + netkey_changed = bt_mesh_bridge_change_net_key(rx, &enc, &priv, &nid, cred); + } +#endif - /* Update NID if RX or RX was with friend credentials */ - if (rx->friend_cred) { + 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. + * 2. Update NID if the net_key has changed. + */ + if (rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED || netkey_changed) { buf->data[0] &= 0x80; /* Clear everything except IVI */ buf->data[0] |= nid; } @@ -1294,7 +1562,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, * the normal TX IVI (which may be different) since the transport * layer nonce includes the IVI. */ - if (bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_RX(rx), false)) { + if (bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_RX(rx), false, false)) { BT_ERR("Re-encrypting failed"); goto done; } @@ -1306,22 +1574,46 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, /* Sending to the GATT bearer should only happen if GATT Proxy * is enabled or the message originates from the local node. + * + * The output filter of the interface connected to the GATT bearer + * shall drop all messages secured using the friendship security + * credentials. */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED || - rx->friend_cred || - rx->net_if == BLE_MESH_NET_IF_LOCAL)) { + (bearer & BLE_MESH_GATT_BEARER) && + ((bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED && + cred != BLE_MESH_FRIENDSHIP_CRED) || + bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED || + rx->net_if == BLE_MESH_NET_IF_LOCAL || + rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED)) { if (bt_mesh_proxy_server_relay(&buf->b, rx->ctx.recv_dst) && - BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - goto done; + BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { + if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { + goto done; + } } } - if (relay_to_adv(rx->net_if) || rx->friend_cred) { -#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) - bt_mesh_adv_send(buf, NULL, NULL); + 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 - bt_mesh_relay_adv_send(buf, NULL, NULL, rx->ctx.addr, rx->ctx.recv_dst); + bt_mesh_relay_adv_send(buf, xmit, rx->ctx.addr, rx->ctx.recv_dst, NULL, NULL); #endif } @@ -1332,12 +1624,12 @@ done: void bt_mesh_net_header_parse(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { - rx->old_iv = (IVI(buf->data) != (bt_mesh.iv_index & 0x01)); - rx->ctl = CTL(buf->data); - rx->ctx.recv_ttl = TTL(buf->data); - rx->seq = SEQ(buf->data); - rx->ctx.addr = SRC(buf->data); - rx->ctx.recv_dst = DST(buf->data); + rx->old_iv = (BLE_MESH_NET_HDR_IVI(buf->data) != (bt_mesh.iv_index & 0x01)); + rx->ctl = BLE_MESH_NET_HDR_CTL(buf->data); + rx->ctx.recv_ttl = BLE_MESH_NET_HDR_TTL(buf->data); + rx->seq = BLE_MESH_NET_HDR_SEQ(buf->data); + rx->ctx.addr = BLE_MESH_NET_HDR_SRC(buf->data); + rx->ctx.recv_dst = BLE_MESH_NET_HDR_DST(buf->data); } int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, @@ -1362,10 +1654,21 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, return -ENOENT; } + /* Spec v1.1, Section 3.4.5.1: + * The input filter of the interface connected to the GATT + * bearer shall drop all messages that have been secured + * using the friendship security credentials. + */ + if (net_if == BLE_MESH_NET_IF_PROXY && + rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED) { + BT_WARN("Dropping packet from GATT bearer using friendship creds"); + return -EBADMSG; + } + /* Initialize AppIdx to a sane value */ rx->ctx.app_idx = BLE_MESH_KEY_UNUSED; - rx->ctx.recv_ttl = TTL(buf->data); + rx->ctx.recv_ttl = BLE_MESH_NET_HDR_TTL(buf->data); /* Default to responding with TTL 0 for non-routed messages */ if (rx->ctx.recv_ttl == 0U) { @@ -1374,14 +1677,14 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, rx->ctx.send_ttl = BLE_MESH_TTL_DEFAULT; } - rx->ctl = CTL(buf->data); - rx->seq = SEQ(buf->data); - rx->ctx.recv_dst = DST(buf->data); + rx->ctl = BLE_MESH_NET_HDR_CTL(buf->data); + rx->seq = BLE_MESH_NET_HDR_SEQ(buf->data); + rx->ctx.recv_dst = BLE_MESH_NET_HDR_DST(buf->data); BT_DBG("Decryption successful. Payload len %u", buf->len); if (net_if != BLE_MESH_NET_IF_PROXY_CFG && - rx->ctx.recv_dst == BLE_MESH_ADDR_UNASSIGNED) { + rx->ctx.recv_dst == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("Destination address is unassigned; dropping packet"); return -EBADMSG; } @@ -1412,7 +1715,9 @@ static bool ready_to_recv(void) { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { return true; - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { + } + + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { if (bt_mesh_provisioner_get_node_count()) { return true; } @@ -1439,12 +1744,16 @@ static bool ignore_net_msg(uint16_t src, uint16_t dst) * address of Provisioner, but Provisioner fails to find the * node in its provisioning database, then this message will * be ignored. + * Note: extra check src here to support Provisioner sending + * messages to itself. */ - if (!bt_mesh_provisioner_get_node_with_addr(src)) { + if (!bt_mesh_provisioner_get_node_with_addr(src) && + !bt_mesh_elem_find(src)) { BT_INFO("Not found node address 0x%04x", src); return true; } } + return false; } @@ -1472,16 +1781,23 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, /* Save the state so the buffer can later be relayed */ net_buf_simple_save(&buf, &state); - BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_NET, + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ + BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_NET, "\nNetRecv: ctl: %d, src: %d, dst: %d, ttl: %d, data: 0x%s", - CTL(buf.data), SRC(buf.data), DST(buf.data), TTL(buf.data), + rx.ctl, rx.ctx.addr, rx.ctx.recv_dst, rx.ctx.recv_ttl, bt_hex(buf.data + BLE_MESH_NET_HDR_LEN, buf.len - BLE_MESH_NET_HDR_LEN)); + /* If trying to handle a message with DST set to all-directed-forwarding-nodes, + * we need to make sure the directed forwarding functionality is enabled in the + * corresponding subnet. + */ rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || + bt_mesh_fixed_direct_match(rx.sub, rx.ctx.recv_dst) || bt_mesh_elem_find(rx.ctx.recv_dst)); if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - net_if == BLE_MESH_NET_IF_PROXY) { + bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_DISABLED && + net_if == BLE_MESH_NET_IF_PROXY) { bt_mesh_proxy_server_addr_add(data, rx.ctx.addr); if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_DISABLED && @@ -1489,6 +1805,22 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, BT_INFO("Proxy is disabled; ignoring message"); return; } + + /* If the Directed Proxy Server receives a valid Network PDU from the Directed + * Proxy Client, and the value of the Use_Directed parameter of the connection + * for the subnet identified by the Network PDU is Enabled, and the source + * address of the Network PDU is outside the unicast address range defined by + * the Proxy_Client_Address_Range parameter, then the Directed Proxy Server shall + * tag the Network PDU with the immutable-credentials tag. + */ +#if CONFIG_BLE_MESH_DF_SRV + if (rx.sub->directed_proxy == BLE_MESH_DIRECTED_PROXY_ENABLED && + rx.sub->use_directed == BLE_MESH_PROXY_USE_DIRECTED_ENABLED && + !bt_mesh_addr_in_uar(&rx.sub->proxy_client_uar, rx.ctx.addr) && + !bt_mesh_proxy_server_find_client_by_addr(rx.ctx.addr)) { + rx.ctx.recv_tag |= BLE_MESH_TAG_IMMUTABLE_CRED; + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ } /* The transport layer has indicated that it has rejected the message, @@ -1509,7 +1841,7 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, * was neither a local element nor an LPN we're Friends for. */ if (!BLE_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) || - (!rx.local_match && !rx.friend_match)) { + (!rx.local_match && !rx.friend_match)) { net_buf_simple_restore(&buf, &state); bt_mesh_net_relay(&buf, &rx); } @@ -1520,9 +1852,9 @@ static void ivu_refresh(struct k_work *work) bt_mesh.ivu_duration += BLE_MESH_IVU_HOURS; BT_INFO("%s for %u hour%s", - bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) ? - "IVU in Progress" : "IVU Normal mode", - bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1U ? "" : "s"); + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) ? + "IVU in Progress" : "IVU Normal mode", + bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1U ? "" : "s"); if (bt_mesh.ivu_duration < BLE_MESH_IVU_MIN_HOURS) { if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { @@ -1543,22 +1875,31 @@ static void ivu_refresh(struct k_work *work) void bt_mesh_net_start(void) { - if (bt_mesh_beacon_get() == BLE_MESH_BEACON_ENABLED) { - bt_mesh_beacon_enable(); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { + bt_mesh_secure_beacon_enable(); } else { - bt_mesh_beacon_disable(); + bt_mesh_secure_beacon_disable(); } +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { + bt_mesh_private_beacon_enable(); + } else { + bt_mesh_private_beacon_disable(); + } +#endif + if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { + bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { bt_mesh_proxy_server_gatt_enable(); bt_mesh_adv_update(); } -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Add Mesh beacon type (Secure Network Beacon) to the exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, + NULL); #endif if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { @@ -1589,8 +1930,6 @@ void bt_mesh_net_start(void) void bt_mesh_net_init(void) { k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); - - k_work_init(&bt_mesh.local_work, bt_mesh_net_local); } void bt_mesh_net_reset(void) @@ -1618,8 +1957,6 @@ void bt_mesh_net_deinit(void) k_delayed_work_free(&bt_mesh.ivu_timer); - k_work_init(&bt_mesh.local_work, NULL); - /* Local queue uses a while loop, currently no need * to handle this. */ diff --git a/components/bt/esp_ble_mesh/core/net.h b/components/bt/esp_ble_mesh/core/net.h index b0e3488524..b9dfb42dda 100644 --- a/components/bt/esp_ble_mesh/core/net.h +++ b/components/bt/esp_ble_mesh/core/net.h @@ -11,18 +11,19 @@ #define _NET_H_ #include "mesh/access.h" +#include "mesh/mutex.h" #ifdef __cplusplus extern "C" { #endif -#define BLE_MESH_NET_FLAG_KR BIT(0) -#define BLE_MESH_NET_FLAG_IVU BIT(1) +#define BLE_MESH_NET_FLAG_KR BIT(0) +#define BLE_MESH_NET_FLAG_IVU BIT(1) -#define BLE_MESH_KR_NORMAL 0x00 -#define BLE_MESH_KR_PHASE_1 0x01 -#define BLE_MESH_KR_PHASE_2 0x02 -#define BLE_MESH_KR_PHASE_3 0x03 +#define BLE_MESH_KR_NORMAL 0x00 +#define BLE_MESH_KR_PHASE_1 0x01 +#define BLE_MESH_KR_PHASE_2 0x02 +#define BLE_MESH_KR_PHASE_3 0x03 #define BLE_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01) #define BLE_MESH_KEY_REFRESH(flags) (flags & 0x01) @@ -43,45 +44,131 @@ struct bt_mesh_app_key { }; struct bt_mesh_subnet { - uint32_t beacon_sent; /* Timestamp of last sent beacon */ - uint8_t beacons_last; /* Number of beacons during last observation window. */ - uint8_t beacons_cur; /* Number of beacons observed during currently ongoing window. */ + uint32_t snb_sent; /* Timestamp of last sent secure network beacon */ + uint8_t snb_last; /* Number of secure network beacons during last observation window */ + uint8_t snb_cur; /* Number of secure network beacons observed during currently ongoing window.*/ + uint8_t snb_cache[21]; /* Cached last receive authenticated secure beacon */ - uint8_t beacon_cache[21]; /* Cached last authenticated beacon */ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + uint32_t mpb_sent; /* Timestamp of last sent private beacon */ + uint8_t mpb_last; /* Number of private beacons during last observation window */ + uint8_t mpb_cur; /* Number of private beacons observed during currently ongoing window. */ + uint8_t mpb_cache[21]; /* Cached last receive private beacon (Random + Authentication Tag) */ - uint16_t net_idx; /* NetKeyIndex */ + 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 */ - bool kr_flag; /* Key Refresh Flag */ - uint8_t kr_phase; /* Key Refresh Phase */ + uint8_t private_node_id; /* Private Node Identity State */ +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ - uint8_t node_id; /* Node Identity State */ - uint32_t node_id_start; /* Node Identity started timestamp */ + uint16_t net_idx; /* NetKeyIndex */ - uint8_t auth[8]; /* Beacon Authentication Value */ +#if CONFIG_BLE_MESH_BRC_SRV + uint16_t sbr_net_idx; /* NetKeyIndex of bridged subnet */ +#endif + + bool kr_flag; /* Key Refresh Flag */ + uint8_t kr_phase; /* Key Refresh Phase */ + + uint8_t node_id; /* Node Identity State */ + uint32_t node_id_start; /* Node Identity started timestamp */ + + uint8_t auth[8]; /* Beacon Authentication Value */ struct bt_mesh_subnet_keys { - uint8_t net[16]; /* NetKey */ - uint8_t nid; /* NID */ - uint8_t enc[16]; /* EncKey */ - uint8_t net_id[8]; /* Network ID */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) - uint8_t identity[16]; /* IdentityKey */ -#endif - uint8_t privacy[16]; /* PrivacyKey */ - uint8_t beacon[16]; /* BeaconKey */ + uint8_t net[16]; /* NetKey */ + uint8_t nid; /* NID */ + uint8_t enc[16]; /* EncKey */ + uint8_t net_id[8]; /* Network ID */ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + uint8_t identity[16]; /* IdentityKey */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + uint8_t privacy[16]; /* PrivacyKey */ + uint8_t beacon[16]; /* BeaconKey */ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + uint8_t private_beacon[16]; /* Private BeaconKey */ +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +#if CONFIG_BLE_MESH_DF_SRV + uint8_t direct_nid; /* Directed NID */ + uint8_t direct_enc[16]; /* Directed EncKey */ + uint8_t direct_privacy[16]; /* Directed PrivacyKey */ +#endif /* CONFIG_BLE_MESH_DF_SRV */ } keys[2]; + + /* Indicate if proxy privacy is enabled (i.e. sending Mesh Private Beacons + * or Secure Network Beacons) to proxy client. + * + * Note: in Mesh Spec, it describes as "the Proxy Privacy parameter for the + * connection". Here we put the parameter in the subnet, since when sending + * mesh beacon, and for the existing subnets, proxy server should send mesh + * beacon for each of the subnets. + */ + uint8_t proxy_privacy; + +#if CONFIG_BLE_MESH_DF_SRV + uint8_t directed_forwarding; + uint8_t directed_relay; /* Binding with Directed Forwarding state */ + uint8_t directed_proxy; /* Binding with Directed Forwarding state & GATT Proxy state */ + uint8_t directed_proxy_use_default; /* Binding with Directed Proxy state */ + uint8_t directed_friend; + + uint8_t use_directed; + struct { + uint16_t len_present:1, + range_start:15; + uint8_t range_length; + } proxy_client_uar; + + uint8_t path_metric_type:3, + path_lifetime_type:2, + two_way_path:1; + + uint8_t forward_number; + + /* The Discovery Table initially is empty. A Path Origin updates + * its Discovery Table when a Directed Forwarding Initialization + * procedure is executed. A Path Target or a Directed Relay node + * updates its Discovery Table when a PATH_REQUEST message is + * received and processed. + */ + struct bt_mesh_discovery_table { + uint8_t max_disc_entries; + uint8_t max_concurr_init; /* default is 0x02 */ + uint8_t concurr_init; + + bt_mesh_mutex_t mutex; + sys_slist_t entries; + } discovery_table; + + struct bt_mesh_forward_table { + uint8_t max_ford_entries; + uint8_t max_deps_nodes; + uint16_t update_id; + + bt_mesh_mutex_t mutex; + sys_slist_t entries; + } forward_table; + + uint8_t wanted_lanes; + + uint8_t unicast_echo_interval; + + uint8_t multicast_echo_interval; +#endif /* CONFIG_BLE_MESH_DF_SRV */ }; struct bt_mesh_rpl { uint16_t src; bool old_iv; -#if defined(CONFIG_BLE_MESH_SETTINGS) +#if CONFIG_BLE_MESH_SETTINGS bool store; #endif uint32_t seq; }; -#if defined(CONFIG_BLE_MESH_FRIEND) +#if CONFIG_BLE_MESH_FRIEND #define FRIEND_SEG_RX CONFIG_BLE_MESH_FRIEND_SEG_RX #define FRIEND_SUB_LIST_SIZE CONFIG_BLE_MESH_FRIEND_SUB_LIST_SIZE #else @@ -133,7 +220,7 @@ struct bt_mesh_friend { } clear; }; -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER #define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS #else #define LPN_GROUPS 0 @@ -141,7 +228,7 @@ struct bt_mesh_friend { /* Low Power Node state */ struct bt_mesh_lpn { - enum __packed { + enum __attribute__((packed)) { BLE_MESH_LPN_DISABLED, /* LPN feature is disabled */ BLE_MESH_LPN_CLEAR, /* Clear in progress */ BLE_MESH_LPN_TIMER, /* Waiting for auto timer expiry */ @@ -236,15 +323,14 @@ struct bt_mesh_net { BLE_MESH_ATOMIC_DEFINE(flags, BLE_MESH_FLAG_COUNT); /* Local network interface */ - struct k_work local_work; sys_slist_t local_queue; -#if defined(CONFIG_BLE_MESH_FRIEND) +#if CONFIG_BLE_MESH_FRIEND /* Friend state, unique for each LPN that we're Friends for */ struct bt_mesh_friend frnd[CONFIG_BLE_MESH_FRIEND_LPN_COUNT]; #endif -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER struct bt_mesh_lpn lpn; /* Low Power Node state */ #endif @@ -254,7 +340,8 @@ struct bt_mesh_net { /* Timer to track duration in current IV Update state */ struct k_delayed_work ivu_timer; - uint8_t dev_key[16]; + uint8_t dev_key[16]; /* Device Key */ + uint8_t dev_key_ca[16]; /* Device Key Candidate */ struct bt_mesh_app_key app_keys[CONFIG_BLE_MESH_APP_KEY_COUNT]; @@ -262,7 +349,7 @@ struct bt_mesh_net { struct bt_mesh_rpl rpl[CONFIG_BLE_MESH_CRPL]; -#if defined(CONFIG_BLE_MESH_PROVISIONER) +#if CONFIG_BLE_MESH_PROVISIONER /* Application keys stored by provisioner */ struct bt_mesh_app_key *p_app_keys[CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT]; /* Next app_idx can be assigned */ @@ -283,6 +370,12 @@ enum bt_mesh_net_if { BLE_MESH_NET_IF_PROXY_CFG, }; +#define BLE_MESH_NONE_BEARER 0 +#define BLE_MESH_ADV_BEARER BIT(0) +#define BLE_MESH_GATT_BEARER BIT(1) +#define BLE_MESH_LOCAL_BEARER BIT(2) +#define BLE_MESH_ALL_BEARERS (BLE_MESH_ADV_BEARER | BLE_MESH_GATT_BEARER) + /* Decoding context for Network/Transport data */ struct bt_mesh_net_rx { struct bt_mesh_subnet *sub; @@ -290,7 +383,7 @@ struct bt_mesh_net_rx { uint32_t seq; /* Sequence Number */ uint8_t old_iv:1, /* iv_index - 1 was used */ new_key:1, /* Data was encrypted with updated key */ - friend_cred:1, /* Data was encrypted with friend cred */ + 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 */ @@ -304,19 +397,27 @@ struct bt_mesh_net_tx { struct bt_mesh_msg_ctx *ctx; uint16_t src; uint8_t xmit; - uint8_t friend_cred:1, + uint8_t friend_cred:1 __attribute__((deprecated)), aszmic:1, - aid: 6; + aid:6; }; 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)) -#define BLE_MESH_NET_IVI_RX(rx) (bt_mesh.iv_index - (rx)->old_iv) +#define BLE_MESH_NET_IVI_TX (bt_mesh.iv_index - \ + bt_mesh_atomic_test_bit(bt_mesh.flags, \ + 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 +#define BLE_MESH_NET_HDR_LEN 9 + +#define BLE_MESH_NET_HDR_IVI(pdu) ((pdu)[0] >> 7) +#define BLE_MESH_NET_HDR_NID(pdu) ((pdu)[0] & 0x7F) +#define BLE_MESH_NET_HDR_CTL(pdu) ((pdu)[1] >> 7) +#define BLE_MESH_NET_HDR_TTL(pdu) ((pdu)[1] & 0x7F) +#define BLE_MESH_NET_HDR_SEQ(pdu) (sys_get_be24(&(pdu)[2])) +#define BLE_MESH_NET_HDR_SRC(pdu) (sys_get_be16(&(pdu)[5])) +#define BLE_MESH_NET_HDR_DST(pdu) (sys_get_be16(&(pdu)[7])) void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num); @@ -332,9 +433,7 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub); -int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub); - -void bt_mesh_rpl_reset(void); +int bt_mesh_net_secure_beacon_update(struct bt_mesh_subnet *sub); bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); @@ -342,9 +441,9 @@ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub); struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx); -struct bt_mesh_subnet *bt_mesh_subnet_find(const uint8_t net_id[8], uint8_t flags, - uint32_t iv_index, const uint8_t auth[8], - bool *new_key); +struct bt_mesh_subnet *bt_mesh_subnet_find_with_snb(const uint8_t net_id[8], uint8_t flags, + uint32_t iv_index, const uint8_t auth[8], + bool *new_key); int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, bool proxy); @@ -353,8 +452,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data); int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, - bool new_key, const struct bt_mesh_send_cb *cb, - void *cb_data); + bool new_key, uint8_t *tx_cred, uint8_t tx_tag, + const struct bt_mesh_send_cb *cb, void *cb_data); int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); 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 47f0a7ca56..398c1526a9 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -70,7 +70,7 @@ static uint8_t bt_mesh_private_key[32]; /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; -#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +#if CONFIG_BLE_MESH_NODE /* the gatt database list to save the attribute table */ static sys_slist_t bt_mesh_gatts_db; @@ -79,8 +79,7 @@ static struct bt_mesh_conn bt_mesh_gatts_conn[BLE_MESH_MAX_CONN]; static struct bt_mesh_conn_cb *bt_mesh_gatts_conn_cb; static uint8_t bt_mesh_gatts_addr[6]; - -#endif /* defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE */ +#endif /* CONFIG_BLE_MESH_NODE */ int bt_mesh_host_init(void) { @@ -119,12 +118,11 @@ void bt_mesh_hci_init(void) #else bt_mesh_dev.hci_version = ble_hs_hci_get_hci_version(); #endif - return; } static struct ble_gap_disc_params scan_param; #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT static struct gattc_prov_info { /* Service to be found depends on the type of adv pkt received */ struct bt_mesh_conn conn; @@ -149,6 +147,7 @@ static int ble_on_subscribe(uint16_t conn_handle, struct bt_mesh_conn *conn = NULL; uint8_t value[2] = {0x01, 0x00}; int i = (int)arg, j, len; + MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d " "attr_handle=%d\n", error->status, conn_handle, attr->handle); @@ -158,8 +157,8 @@ static int ble_on_subscribe(uint16_t conn_handle, break; } } - if (j == ARRAY_SIZE(bt_mesh_gattc_info)) { + if (j == ARRAY_SIZE(bt_mesh_gattc_info)) { conn = &bt_mesh_gattc_info[i].conn; if (bt_mesh_gattc_info[i].ccc_handle != attr->handle) { @@ -190,7 +189,6 @@ static int ble_on_subscribe(uint16_t conn_handle, } } - return 0; } @@ -248,7 +246,6 @@ static int dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, return rc; } - static int chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg) { @@ -257,9 +254,11 @@ static int chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, int i = (int)arg; /* service index */ struct bt_mesh_conn *conn = &bt_mesh_gattc_info[i].conn; const ble_uuid_any_t *uuid = &chr->uuid; + if (chr) { uuid16 = (uint16_t) BLE_UUID16(uuid)->value; } + switch (error->status) { case 0: /* Get Mesh Provisioning/Proxy Data In/Out Characteristic */ @@ -279,6 +278,7 @@ static int chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, bt_mesh_gattc_info[i].data_out_handle = chr->val_handle; } break; + case BLE_HS_EDONE: /* All characteristics in this service discovered; start discovering * characteristics in the next service. @@ -310,7 +310,6 @@ static int chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, return rc; } - static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { @@ -318,16 +317,19 @@ static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, int rc = 0, i; const ble_uuid_any_t *uuid; uint8_t uuid_length; + switch (error->status) { case 0: if (!service) { return 0; } + uuid = &service->uuid; uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); if (uuid_length != 2) { return 0; } + for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if (bt_mesh_gattc_info[i].service_uuid == (uint16_t)BLE_UUID16(uuid)->value) { bt_mesh_gattc_info[i].start_handle = service->start_handle; @@ -335,8 +337,8 @@ static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, break; } } - break; + case BLE_HS_EDONE: for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if (bt_mesh_gattc_info[i].conn.handle == conn_handle) { @@ -348,10 +350,11 @@ static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, BT_ERR("Conn handle 0x%04x not found", conn_handle); return 0; } + conn = &bt_mesh_gattc_info[i].conn; if (bt_mesh_gattc_info[i].start_handle == 0x00 || - bt_mesh_gattc_info[i].end_handle == 0x00 || - (bt_mesh_gattc_info[i].start_handle > bt_mesh_gattc_info[i].end_handle)) { + bt_mesh_gattc_info[i].end_handle == 0x00 || + (bt_mesh_gattc_info[i].start_handle > bt_mesh_gattc_info[i].end_handle)) { bt_mesh_gattc_disconnect(conn); return 0; } @@ -368,16 +371,13 @@ static int svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, return rc; } - - #endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ static int disc_cb(struct ble_gap_event *event, void *arg) { struct ble_gap_disc_desc *desc; - #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT int rc, i; uint8_t notif_data[100]; uint16_t notif_len; @@ -394,12 +394,13 @@ static int disc_cb(struct ble_gap_event *event, void *arg) net_buf_simple_init_with_data(&buf, (void *)desc->data, desc->length_data); if (bt_mesh_scan_dev_found_cb) { - bt_mesh_scan_dev_found_cb((bt_mesh_addr_t *)&desc->addr, desc->rssi, desc->event_type, &buf); + /* TODO: Support Scan Response data length for NimBLE host */ + bt_mesh_scan_dev_found_cb((bt_mesh_addr_t *)&desc->addr, desc->rssi, desc->event_type, &buf, 0); } break; } #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { /* Connection successfully established. */ @@ -561,7 +562,6 @@ static int disc_cb(struct ble_gap_event *event, void *arg) static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t filter_dup) { - scan_param.filter_duplicates = filter_dup; scan_param.itvl = interval; scan_param.window = window; @@ -600,7 +600,7 @@ static int set_ad(const struct bt_mesh_adv_data *ad, size_t ad_len, uint8_t *buf return 0; } -#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +#if CONFIG_BLE_MESH_NODE static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle); static int gap_event_cb(struct ble_gap_event *event, void *arg) @@ -713,7 +713,6 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) 0 /* offset */, 0)) > 0) { } } - return 0; case BLE_GAP_EVENT_MTU: @@ -747,12 +746,11 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) return 0; } #else - static int gap_event_cb(struct ble_gap_event *event, void *arg) { return 0; } -#endif +#endif /* CONFIG_BLE_MESH_NODE */ /* APIs functions */ int bt_le_adv_start(const struct bt_mesh_adv_param *param, @@ -986,8 +984,7 @@ int bt_le_update_white_list(struct bt_mesh_white_list *wl) } #endif -#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE - +#if CONFIG_BLE_MESH_NODE void bt_mesh_gatts_conn_cb_register(struct bt_mesh_conn_cb *cb) { bt_mesh_gatts_conn_cb = cb; @@ -1084,7 +1081,7 @@ struct gatts_incl { uint16_t start_handle; uint16_t end_handle; uint16_t uuid16; -} __packed; +} __attribute__((packed)); ssize_t bt_mesh_gatts_attr_read_included(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, @@ -1134,7 +1131,7 @@ struct gatts_chrc { uint16_t uuid16; uint8_t uuid[16]; }; -} __packed; +} __attribute__((packed)); ssize_t bt_mesh_gatts_attr_read_chrc(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, @@ -1268,11 +1265,13 @@ int bt_mesh_gatts_service_stop(struct bt_mesh_gatt_service *svc) { int rc; uint16_t handle; + const ble_uuid_t *uuid; + if (!svc) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - const ble_uuid_t *uuid; + if (BLE_MESH_UUID_16(svc->attrs[0].user_data)->val == BT_UUID_MESH_PROXY_VAL) { uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL); } else { @@ -1294,6 +1293,7 @@ int bt_mesh_gatts_service_start(struct bt_mesh_gatt_service *svc) int rc; uint16_t handle; const ble_uuid_t *uuid; + if (BLE_MESH_UUID_16(svc->attrs[0].user_data)->val == BT_UUID_MESH_PROXY_VAL) { uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL); } else { @@ -1314,10 +1314,10 @@ int bt_mesh_gatts_set_local_device_name(const char *name) { return ble_svc_gap_device_name_set(name); } -#endif /* defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE */ +#endif /* CONFIG_BLE_MESH_NODE */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT void bt_mesh_gattc_conn_cb_register(struct bt_mesh_prov_conn_cb *cb) { bt_mesh_gattc_conn_cb = cb; @@ -1335,7 +1335,7 @@ uint8_t bt_mesh_gattc_get_free_conn_count(void) for (i = 0U; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if (bt_mesh_gattc_info[i].conn.handle == 0xFFFF && - bt_mesh_gattc_info[i].service_uuid == 0x0000) { + bt_mesh_gattc_info[i].service_uuid == 0x0000) { ++count; } } @@ -1376,13 +1376,13 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) int i, rc; if (!addr || !memcmp(addr->val, zero, BLE_MESH_ADDR_LEN) || - (addr->type > BLE_ADDR_RANDOM)) { + (addr->type > BLE_ADDR_RANDOM)) { BT_ERR("Invalid remote address"); return -EINVAL; } if (service_uuid != BLE_MESH_UUID_MESH_PROV_VAL && - service_uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { + service_uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { BT_ERR("Invalid service uuid 0x%04x", service_uuid); return -EINVAL; } @@ -1399,7 +1399,7 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) /* Find empty element in queue to store device info */ for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if ((bt_mesh_gattc_info[i].conn.handle == 0xFFFF) && - (bt_mesh_gattc_info[i].service_uuid == 0x0000)) { + (bt_mesh_gattc_info[i].service_uuid == 0x0000)) { memcpy(bt_mesh_gattc_info[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); bt_mesh_gattc_info[i].addr.type = addr->type; /* Service to be found after exchanging mtu size */ @@ -1438,7 +1438,6 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) conn_params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; conn_params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; - ble_addr_t peer_addr; memcpy(peer_addr.val, addr->val, 6); peer_addr.type = addr->type; @@ -1452,8 +1451,8 @@ static int mtu_cb(uint16_t conn_handle, uint16_t mtu, void *arg) { int i; - if (error->status == 0) { + if (error->status == 0) { for (i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { if (bt_mesh_gattc_info[i].conn.handle == conn_handle) { bt_mesh_gattc_info[i].mtu = mtu; @@ -1461,11 +1460,10 @@ static int mtu_cb(uint16_t conn_handle, } } } + return 0; } - - void bt_mesh_gattc_exchange_mtu(uint8_t index) { /** Set local MTU and exchange with GATT server. @@ -1549,6 +1547,7 @@ void bt_mesh_gattc_disconnect(struct bt_mesh_conn *conn) BT_ERR("Conn %p not found", conn); return; } + ble_gap_terminate(bt_mesh_gattc_info[i].conn.handle, BLE_ERR_REM_USER_CONN_TERM); } @@ -1577,7 +1576,7 @@ void bt_mesh_conn_unref(struct bt_mesh_conn *conn) BT_DBG("handle %u ref %u", conn->handle, bt_mesh_atomic_get(&conn->ref)); } -#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +#if CONFIG_BLE_MESH_NODE static int proxy_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { @@ -1660,10 +1659,10 @@ static const struct ble_gatt_svc_def svc_defs [] = { 0, /* No more services. */ }, }; -#endif +#endif /* CONFIG_BLE_MESH_NODE */ void gatt_register_cb(struct ble_gatt_register_ctxt *ctxt, - void *arg ) + void *arg) { if (ctxt->op == BLE_GATT_REGISTER_OP_SVC) { if (ble_uuid_cmp(ctxt->svc.svc_def->uuid, BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL)) == 0) { @@ -1680,7 +1679,7 @@ void bt_mesh_gatt_init(void) ble_hs_cfg.gatts_register_cb = gatt_register_cb; -#if defined(CONFIG_BLE_MESH_NODE) && CONFIG_BLE_MESH_NODE +#if CONFIG_BLE_MESH_NODE static bool init = false; int rc; @@ -1701,10 +1700,10 @@ void bt_mesh_gatt_init(void) init = true; } -#endif +#endif /* CONFIG_BLE_MESH_NODE */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT for (int i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { bt_mesh_gattc_info[i].conn.handle = 0xFFFF; bt_mesh_gattc_info[i].mtu = BLE_ATT_MTU_DFLT; @@ -1717,12 +1716,12 @@ void bt_mesh_gatt_init(void) void bt_mesh_gatt_deinit(void) { #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER memset(bt_mesh_gatts_addr, 0, BLE_MESH_ADDR_LEN); #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT for (int i = 0; i < ARRAY_SIZE(bt_mesh_gattc_info); i++) { bt_mesh_gattc_info[i].conn.handle = 0xFFFF; memset(&bt_mesh_gattc_info[i].addr, 0, sizeof(bt_mesh_addr_t)); @@ -1743,8 +1742,6 @@ void ble_sm_alg_ecc_init(void); void bt_mesh_adapt_init(void) { - BT_DBG("%s", __func__); - /* initialization of P-256 parameters */ ble_sm_alg_ecc_init(); @@ -1838,18 +1835,12 @@ exit: int ble_sm_alg_gen_dhkey(uint8_t *peer_pub_key_x, uint8_t *peer_pub_key_y, uint8_t *our_priv_key, uint8_t *out_dhkey); -int bt_mesh_dh_key_gen(const uint8_t remote_pk[64], bt_mesh_dh_key_cb_t cb, const uint8_t idx) +int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) { - uint8_t dhkey[32]; - BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, 32)); - ble_sm_alg_gen_dhkey((uint8_t *)&remote_pk[0], (uint8_t *)&remote_pk[32], bt_mesh_private_key, dhkey); - - if (cb != NULL) { - cb((const uint8_t *)dhkey, idx); - } - return 0; + return ble_sm_alg_gen_dhkey((uint8_t *)&remote_pub_key[0], (uint8_t *)&remote_pub_key[32], + bt_mesh_private_key, dhkey); } int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], @@ -1942,7 +1933,7 @@ int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], return 0; } -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN int bt_mesh_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) { uint8_t value[6] = {0}; diff --git a/components/bt/esp_ble_mesh/core/prov_common.c b/components/bt/esp_ble_mesh/core/prov_common.c new file mode 100644 index 0000000000..db6109c41b --- /dev/null +++ b/components/bt/esp_ble_mesh/core/prov_common.c @@ -0,0 +1,684 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "adv.h" +#include "crypto.h" +#include "mesh/mutex.h" +#include "mesh/common.h" +#include "mesh/access.h" +#include "prov_common.h" + +static const struct bt_mesh_prov *prov; + +const struct bt_mesh_prov *bt_mesh_prov_get(void) +{ + return prov; +} + +int bt_mesh_prov_set(const struct bt_mesh_prov *val) +{ + prov = val; + return 0; +} + +void bt_mesh_prov_buf_init(struct net_buf_simple *buf, uint8_t type) +{ + net_buf_simple_reserve(buf, PROV_BUF_HEADROOM); + net_buf_simple_add_u8(buf, type); +} + +#define OUTPUT_OOB_BLINK 0x00 +#define OUTPUT_OOB_BEEP 0x01 +#define OUTPUT_OOB_VIBRATE 0x02 +#define OUTPUT_OOB_NUMBER 0x03 +#define OUTPUT_OOB_STRING 0x04 + +#define INPUT_OOB_PUSH 0x00 +#define INPUT_OOB_TWIST 0x01 +#define INPUT_OOB_NUMBER 0x02 +#define INPUT_OOB_STRING 0x03 + +bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action) +{ + switch (action) { + case OUTPUT_OOB_BLINK: + return BLE_MESH_BLINK; + case OUTPUT_OOB_BEEP: + return BLE_MESH_BEEP; + case OUTPUT_OOB_VIBRATE: + return BLE_MESH_VIBRATE; + case OUTPUT_OOB_NUMBER: + return BLE_MESH_DISPLAY_NUMBER; + case OUTPUT_OOB_STRING: + return BLE_MESH_DISPLAY_STRING; + default: + return BLE_MESH_NO_OUTPUT; + } +} + +bt_mesh_input_action_t bt_mesh_prov_input_action(uint8_t action) +{ + switch (action) { + case INPUT_OOB_PUSH: + return BLE_MESH_PUSH; + case INPUT_OOB_TWIST: + return BLE_MESH_TWIST; + case INPUT_OOB_NUMBER: + return BLE_MESH_ENTER_NUMBER; + case INPUT_OOB_STRING: + return BLE_MESH_ENTER_STRING; + default: + return BLE_MESH_NO_INPUT; + } +} + +static const struct { + uint16_t length; +} prov_pdu[] = { + { 1 }, /* Provisioning Invite */ + { 11 }, /* Provisioning Capabilities */ + { 5 }, /* Provisioning Start */ + { 64 }, /* Provisioning Public Key */ + { 0 }, /* Provisioning Input Complete */ + { 16 }, /* Provisioning Confirmation */ + { 16 }, /* Provisioning Random */ + { 33 }, /* Provisioning Data */ + { 0 }, /* Provisioning Complete */ + { 1 }, /* Provisioning Failed */ + { 6 }, /* Provisioning Record Request */ + { 7 }, /* Provisioning Record Response */ + { 0 }, /* Provisioning Records Get */ + { 2 }, /* Provisioning Records List */ +}; + +bool bt_mesh_prov_pdu_check(uint8_t type, uint16_t length, uint8_t *reason) +{ + if (prov_pdu[type].length != length) { +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if ((type == PROV_REC_LIST || type == PROV_REC_RSP) && + length >= prov_pdu[type].length) { + return true; + } +#endif + +#if CONFIG_BLE_MESH_PROV_EPA + /* NOTE: PROV_CONFIRM and PROV_RANDOM PDU may have length 16 or 32 */ + if ((type == PROV_CONFIRM || type == PROV_RANDOM) && length == 32) { + return true; + } +#endif + + BT_ERR("Invalid length %u for type 0x%02x", length, type); + if (reason) { + *reason = PROV_ERR_NVAL_FMT; + } + return false; + } + + return true; +} + +#if CONFIG_BLE_MESH_PB_ADV + +/* 3 transmissions, 20ms interval */ +#define PROV_XMIT BLE_MESH_TRANSMIT(2, 20) + +/* 3 transmissions, 20ms interval */ +#define CLOSE_XMIT BLE_MESH_TRANSMIT(2, 20) + +#define CLOSE_TIMEOUT K_MSEC(100) + +#define BUF_TIMEOUT K_MSEC(400) + +#define XACT_SEG_DATA(link, _seg) (&link->rx.buf->data[20 + (((_seg) - 1) * 23)]) +#define XACT_SEG_RECV(link, _seg) (link->rx.seg &= ~(1 << (_seg))) + +uint8_t node_next_xact_id(struct bt_mesh_prov_link *link) +{ + if (link->tx.id != 0 && link->tx.id != 0xFF) { + return ++link->tx.id; + } + + link->tx.id = 0x80; + return link->tx.id; +} + +uint8_t pvnr_next_xact_id(struct bt_mesh_prov_link *link) +{ + if (link->tx.id > 0x7F) { + link->tx.id = 0; + } + return link->tx.id++; +} + +bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf, + struct prov_rx *rx, bool *close) +{ + if (link->rx.seg) { + BT_INFO("Get Start while there are unreceived segments"); + return false; + } + + if (link->rx.prev_id == rx->xact_id) { + BT_INFO("Resending ack"); + bt_mesh_gen_prov_ack_send(link, rx->xact_id); + return false; + } + + link->rx.buf->len = net_buf_simple_pull_be16(buf); + link->rx.id = rx->xact_id; + link->rx.fcs = net_buf_simple_pull_u8(buf); + + BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, + START_LAST_SEG(rx->gpc), link->rx.buf->len, link->rx.fcs); + + /* At least one-octet pdu type is needed */ + if (link->rx.buf->len < 1) { + BT_ERR("Ignoring zero-length provisioning PDU"); + if (close) { + *close = true; + } + return false; + } + + if (START_LAST_SEG(rx->gpc) > START_LAST_SEG_MAX) { + BT_ERR("Invalid SegN 0x%02x", START_LAST_SEG(rx->gpc)); + if (close) { + *close = true; + } + return false; + } + + if (link->rx.buf->len > link->rx.buf->size) { + BT_ERR("Too large provisioning PDU (%u bytes)", + link->rx.buf->len); + if (close) { + *close = true; + } + return false; + } + + if (START_LAST_SEG(rx->gpc) > 0 && link->rx.buf->len <= 20) { + BT_ERR("Too small total length for multi-segment PDU"); + if (close) { + *close = true; + } + return false; + } + + link->rx.seg = (1 << (START_LAST_SEG(rx->gpc) + 1)) - 1; + link->rx.last_seg = START_LAST_SEG(rx->gpc); + memcpy(link->rx.buf->data, buf->data, buf->len); + XACT_SEG_RECV(link, 0); + + /* Still have some segments to receive */ + if (link->rx.seg) { + return false; + } + + return true; +} + +bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf, + struct prov_rx *rx, bool *close) +{ + uint8_t seg = CONT_SEG_INDEX(rx->gpc); + + BT_DBG("len %u, seg_index %u", buf->len, seg); + + if (link->rx.seg == 0 && link->rx.prev_id == rx->xact_id) { + BT_INFO("Resending ack"); + bt_mesh_gen_prov_ack_send(link, rx->xact_id); + return false; + } + + if (rx->xact_id != link->rx.id) { + BT_WARN("Data for unknown transaction (%u != %u)", + rx->xact_id, link->rx.id); + return false; + } + + if (seg > link->rx.last_seg) { + BT_ERR("Invalid segment index %u", seg); + if (close) { + *close = true; + } + return false; + } + + if (seg == link->rx.last_seg) { + uint8_t expect_len = (link->rx.buf->len - 20 - + (23 * (link->rx.last_seg - 1))); + if (expect_len != buf->len) { + BT_ERR("Incorrect last seg len: %u != %u", + expect_len, buf->len); + if (close) { + *close = true; + } + return false; + } + } + + if ((link->rx.seg & BIT(seg)) == 0) { + BT_INFO("Ignore already received segment"); + return false; + } + + memcpy(XACT_SEG_DATA(link, seg), buf->data, buf->len); + XACT_SEG_RECV(link, seg); + + /* Still have some segments to receive */ + if (link->rx.seg) { + return false; + } + + return true; +} + +static struct net_buf *adv_buf_create(void) +{ + struct net_buf *buf = NULL; + + buf = bt_mesh_adv_create(BLE_MESH_ADV_PROV, BUF_TIMEOUT); + if (!buf) { + BT_ERR("Out of provisioning buffers"); + return NULL; + } + + return buf; +} + +static void ack_complete(uint16_t duration, int err, void *user_data) +{ + struct bt_mesh_prov_link *link = user_data; + + BT_DBG("xact %u complete", link->pending_ack); + + link->pending_ack = PROV_XACT_NVAL; +} + +void bt_mesh_gen_prov_ack_send(struct bt_mesh_prov_link *link, uint8_t xact_id) +{ + static const struct bt_mesh_send_cb cb = { + .start = ack_complete, + }; + const struct bt_mesh_send_cb *complete = NULL; + struct net_buf *buf = NULL; + + BT_DBG("xact_id %u", xact_id); + + if (link->pending_ack == xact_id) { + BT_DBG("Not sending duplicate ack"); + return; + } + + buf = adv_buf_create(); + if (!buf) { + return; + } + + if (link->pending_ack == PROV_XACT_NVAL) { + link->pending_ack = xact_id; + complete = &cb; + } else { + complete = NULL; + } + + net_buf_add_be32(buf, link->link_id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_ACK); + + bt_mesh_adv_send(buf, PROV_XMIT, complete, link); + net_buf_unref(buf); +} + +static void free_segments(struct bt_mesh_prov_link *link) +{ + for (size_t i = 0; i < ARRAY_SIZE(link->tx.buf); i++) { + struct net_buf *buf = link->tx.buf[i]; + + if (!buf) { + break; + } + + link->tx.buf[i] = NULL; + bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + /* Mark as canceled */ + BLE_MESH_ADV(buf)->busy = 0U; + net_buf_unref(buf); + } +} + +void bt_mesh_prov_clear_tx(struct bt_mesh_prov_link *link, bool cancel) +{ + bt_mesh_mutex_lock(&link->buf_lock); + + if (cancel) { + k_delayed_work_cancel(&link->tx.retransmit); + } + + free_segments(link); + + bt_mesh_mutex_unlock(&link->buf_lock); +} + +static void buf_sent(int err, void *user_data) +{ + struct bt_mesh_prov_link *link = user_data; + int32_t timeout = RETRANSMIT_TIMEOUT; + + if (!link->tx.buf[0]) { + return; + } + + /* The following may happen in TWO situations: + * 1. LINK_CLOSING flag is set, and Link Close is sent; + * 2. LINK_CLOSING flag is set, and any other provisioning + * PDU within the adv queue is sent. + * Regarding the second situation, since LINK_CLOSING flag + * is set, so once a pdu is sent, the link could be closed. + */ + if (bt_mesh_atomic_test_bit(link->flags, LINK_CLOSING)) { + timeout = CLOSE_TIMEOUT; + } + + k_delayed_work_submit(&link->tx.retransmit, timeout); +} + +static struct bt_mesh_send_cb buf_sent_cb = { + .end = buf_sent, +}; + +static void prov_retransmit(struct k_work *work) +{ + struct bt_mesh_prov_link *link = work->user_data; + int64_t timeout = TRANSACTION_TIMEOUT; + + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE)) { + BT_WARN("Link not active"); + return; + } + +#if CONFIG_BLE_MESH_FAST_PROV + if (link->tx_pdu_type >= link->last_tx_pdu) { + timeout = K_SECONDS(30); + } +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + + /* Use a timeout of 0 ~ 60s for PB-Remote Link Open Procedure. */ + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE) && + bt_mesh_atomic_test_bit(link->flags, PBR_OPENING)) { + timeout = K_SECONDS(link->pb_remote_timeout); + } + + if (k_uptime_get() - link->tx.start > timeout) { + BT_WARN("Timeout, giving up transaction"); + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + bt_mesh_prov_clear_tx(link, true); + link->pb_remote_cbd = false; + link->pb_remote_reset = false; + link->pb_remote_csp = true; + if (link->pb_remote_close) { + link->pb_remote_close(link, CLOSE_REASON_TIMEOUT); + } + } else { + /* Send Link Close if the device is Provisioner, or + * directly reset adv link if the device is Node. + */ + if (link->retrans_timeout) { + link->retrans_timeout(link, CLOSE_REASON_TIMEOUT); + } + } + return; + } + + if (bt_mesh_atomic_test_bit(link->flags, LINK_CLOSING)) { + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + bt_mesh_prov_clear_tx(link, true); + link->pb_remote_cbd = false; + /* In this case, no need to send Link Close */ + link->pb_remote_reset = true; + if (link->pb_remote_close) { + link->pb_remote_close(link, link->reason); + } + } else { + if (link->reset_adv_link) { + link->reset_adv_link(link, link->reason); + } + } + return; + } + + bt_mesh_mutex_lock(&link->buf_lock); + + for (size_t i = 0; i < ARRAY_SIZE(link->tx.buf); i++) { + struct net_buf *buf = link->tx.buf[i]; + + if (!buf) { + break; + } + + if (BLE_MESH_ADV(buf)->busy) { + continue; + } + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + + if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + bt_mesh_adv_send(buf, PROV_XMIT, NULL, NULL); + } else { + bt_mesh_adv_send(buf, PROV_XMIT, &buf_sent_cb, link); + } + } + + bt_mesh_mutex_unlock(&link->buf_lock); +} + +int bt_mesh_prov_retransmit_init(struct bt_mesh_prov_link *link) +{ + link->tx.retransmit.work.user_data = link; + + return k_delayed_work_init(&link->tx.retransmit, prov_retransmit); +} + +static void send_reliable(struct bt_mesh_prov_link *link, uint8_t xmit) +{ + link->tx.start = k_uptime_get(); + + for (size_t i = 0; i < ARRAY_SIZE(link->tx.buf); i++) { + struct net_buf *buf = link->tx.buf[i]; + + if (!buf) { + break; + } + + if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + bt_mesh_adv_send(buf, xmit, NULL, NULL); + } else { + bt_mesh_adv_send(buf, xmit, &buf_sent_cb, link); + } + } +} + +int bt_mesh_prov_bearer_ctl_send(struct bt_mesh_prov_link *link, uint8_t op, + void *data, uint8_t data_len) +{ + struct net_buf *buf = NULL; + uint8_t xmit = 0; + + BT_DBG("op 0x%02x data_len %u", op, data_len); + + bt_mesh_prov_clear_tx(link, true); + + buf = adv_buf_create(); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_be32(buf, link->link_id); + /* Transaction ID, always 0 for Bearer messages */ + net_buf_add_u8(buf, 0x00); + net_buf_add_u8(buf, GPC_CTL(op)); + net_buf_add_mem(buf, data, data_len); + + link->tx.buf[0] = buf; + link->tx.id = 0; /* Set Transaction ID to 0 */ + + xmit = (op == LINK_CLOSE) ? CLOSE_XMIT : PROV_XMIT; + + send_reliable(link, xmit); + + if (op == LINK_CLOSE) { + bt_mesh_atomic_clear_bit(link->flags, LINK_ACTIVE); + bt_mesh_atomic_set_bit(link->flags, LINK_CLOSING); + link->reason = *((uint8_t *)data); + } + + return 0; +} + +static uint8_t last_seg(uint8_t len) +{ + if (len <= START_PAYLOAD_MAX) { + return 0; + } + + len -= START_PAYLOAD_MAX; + + return 1 + (len / CONT_PAYLOAD_MAX); +} + +int bt_mesh_prov_send_adv(struct bt_mesh_prov_link *link, struct net_buf_simple *msg) +{ + struct net_buf *start = NULL, *buf = NULL; + int32_t timeout = PROTOCOL_TIMEOUT; + uint8_t seg_len = 0U, seg_id = 0U; + uint8_t xact_id = 0U; + + BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + + if (link->next_xact_id == NULL) { + BT_ERR("Empty transaction id cb"); + return -EIO; + } + + bt_mesh_prov_clear_tx(link, true); + + start = adv_buf_create(); + if (!start) { + return -ENOBUFS; + } + + xact_id = link->next_xact_id(link); + net_buf_add_be32(start, link->link_id); + net_buf_add_u8(start, xact_id); + + net_buf_add_u8(start, GPC_START(last_seg(msg->len))); + net_buf_add_be16(start, msg->len); + net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); + + link->tx.buf[0] = start; + +#if CONFIG_BLE_MESH_FAST_PROV + link->tx_pdu_type = msg->data[0]; +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + + seg_len = MIN(msg->len, START_PAYLOAD_MAX); + BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); + net_buf_add_mem(start, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + + for (seg_id = 1; msg->len > 0; seg_id++) { + if (seg_id >= ARRAY_SIZE(link->tx.buf)) { + BT_ERR("Too big message (seg_id %d)", seg_id); + bt_mesh_prov_clear_tx(link, false); + return -E2BIG; + } + + buf = adv_buf_create(); + if (!buf) { + bt_mesh_prov_clear_tx(link, false); + return -ENOBUFS; + } + + link->tx.buf[seg_id] = buf; + + seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); + + BT_DBG("seg_id %u len %u: %s", seg_id, seg_len, + bt_hex(msg->data, seg_len)); + + net_buf_add_be32(buf, link->link_id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_CONT(seg_id)); + net_buf_add_mem(buf, msg->data, seg_len); + net_buf_simple_pull(msg, seg_len); + } + + send_reliable(link, PROV_XMIT); + +#if CONFIG_BLE_MESH_FAST_PROV + if (link->tx_pdu_type >= link->last_tx_pdu) { + timeout = K_SECONDS(60); + } +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + + k_delayed_work_submit(&link->prot_timer, timeout); + + return 0; +} +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +int bt_mesh_prov_send(struct bt_mesh_prov_link *link, struct net_buf_simple *buf) +{ +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(link->flags, PB_NPPI)) { + if (link->pb_remote_send) { + BT_INFO("NPPI, send prov pdu 0x%02x", buf->data[0]); + return link->pb_remote_send(link, buf); + } + + BT_ERR("No NPPI send callback provided"); + return -EIO; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + +#if CONFIG_BLE_MESH_RPR_CLI || CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + if (link->pb_remote_send) { + BT_INFO("PB-Remote, send prov pdu 0x%02x", buf->data[0]); + return link->pb_remote_send(link, buf); + } + BT_ERR("No PB-Remote send callback provided"); + return -EIO; + } +#endif /* CONFIG_BLE_MESH_RPR_CLI || CONFIG_BLE_MESH_RPR_SRV */ + +#if CONFIG_BLE_MESH_PB_GATT + if (link->conn) { + if (link->pb_gatt_send) { + return link->pb_gatt_send(link, buf); + } + + BT_ERR("No PB-GATT send callback provided"); + return -EIO; + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if CONFIG_BLE_MESH_PB_ADV + return bt_mesh_prov_send_adv(link, buf); +#endif /* CONFIG_BLE_MESH_PB_ADV */ + + /* Shall not reach here. */ + return 0; +} diff --git a/components/bt/esp_ble_mesh/core/prov_common.h b/components/bt/esp_ble_mesh/core/prov_common.h new file mode 100644 index 0000000000..4671b07f21 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/prov_common.h @@ -0,0 +1,333 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PROV_COMMON_H_ +#define _PROV_COMMON_H_ + +#include "mesh/config.h" +#include "mesh/types.h" +#include "mesh/main.h" +#include "mesh/mutex.h" +#include "mesh/timer.h" +#include "mesh/adapter.h" + +#include "mesh_v1.1/utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUTH_METHOD_NO_OOB 0x00 +#define AUTH_METHOD_STATIC 0x01 +#define AUTH_METHOD_OUTPUT 0x02 +#define AUTH_METHOD_INPUT 0x03 + +#define PROV_ERR_NONE 0x00 +#define PROV_ERR_NVAL_PDU 0x01 +#define PROV_ERR_NVAL_FMT 0x02 +#define PROV_ERR_UNEXP_PDU 0x03 +#define PROV_ERR_CFM_FAILED 0x04 +#define PROV_ERR_RESOURCES 0x05 +#define PROV_ERR_DECRYPT 0x06 +#define PROV_ERR_UNEXP_ERR 0x07 +#define PROV_ERR_ADDR 0x08 +#define PROV_ERR_NVAL_DATA 0x09 + +#define PROV_INVITE 0x00 +#define PROV_CAPABILITIES 0x01 +#define PROV_START 0x02 +#define PROV_PUB_KEY 0x03 +#define PROV_INPUT_COMPLETE 0x04 +#define PROV_CONFIRM 0x05 +#define PROV_RANDOM 0x06 +#define PROV_DATA 0x07 +#define PROV_COMPLETE 0x08 +#define PROV_FAILED 0x09 +#define PROV_REC_REQ 0x0A +#define PROV_REC_RSP 0x0B +#define PROV_REC_GET 0x0C +#define PROV_REC_LIST 0x0D +/* NOTE: PROV_REC_EXP is specifically defined by Espressif. + * It indicates that the expected PDU may be PROV_INVITE, + * PROV_REC_REQ or PROV_REC_GET. */ +#define PROV_REC_EXP 0xFF + +#define REC_RSP_SUCCESS 0x00 +#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)) + +#if CONFIG_BLE_MESH_PROV_EPA +#define PROV_ENC_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_AUTH_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_CONF_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_RAND_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_CONF_SALT_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_CONF_KEY_SIZE(link) ((link)->algorithm == PROV_ALG_P256_HMAC_SHA256 ? 32 : 16) +#define PROV_AUTH_MAX_SIZE 32 +#define PROV_CONF_MAX_SIZE 32 +#define PROV_RAND_MAX_SIZE 32 +#else /* CONFIG_BLE_MESH_PROV_EPA */ +#define PROV_ENC_SIZE(link) 16 +#define PROV_AUTH_SIZE(link) 16 +#define PROV_CONF_SIZE(link) 16 +#define PROV_RAND_SIZE(link) 16 +#define PROV_CONF_SALT_SIZE(link) 16 +#define PROV_CONF_KEY_SIZE(link) 16 +#define PROV_AUTH_MAX_SIZE 16 +#define PROV_CONF_MAX_SIZE 16 +#define PROV_RAND_MAX_SIZE 16 +#endif /* CONFIG_BLE_MESH_PROV_EPA */ + +#define PROV_STATIC_OOB_AVAILABLE 0x00 +#define PROV_ONLY_OOB_AUTH_SUPPORT 0x01 + +#define PROV_NO_OOB_PUB_KEY 0x00 +#define PROV_OOB_PUB_KEY 0x01 + +#define GPCF(gpc) ((gpc) & 0x03) +#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) +#define GPC_ACK 0x01 +#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) +#define GPC_CTL(op) (((op) << 2) | 0x03) + +#define START_PAYLOAD_MAX 20 +#define CONT_PAYLOAD_MAX 23 +#define START_LAST_SEG_MAX 2 + +#define START_LAST_SEG(gpc) ((gpc) >> 2) +#define CONT_SEG_INDEX(gpc) ((gpc) >> 2) + +#define BEARER_CTL(gpc) ((gpc) >> 2) +#define LINK_OPEN 0x00 +#define LINK_ACK 0x01 +#define LINK_CLOSE 0x02 + +#define CLOSE_REASON_SUCCESS 0x00 +#define CLOSE_REASON_TIMEOUT 0x01 +#define CLOSE_REASON_FAILED 0x02 + +#define PROV_DH_KEY_SIZE 32 + +#define PROV_CONF_INPUTS_SIZE 145 + +#define PROV_XACT_NVAL 0xFF + +#define NPPI_DEV_KEY_REFRESH 0x00 +#define NPPI_NODE_ADDR_REFRESH 0x01 +#define NPPI_NODE_COMP_REFRESH 0x02 +#define NPPI_UNKNOWN 0x03 + +#if CONFIG_BLE_MESH_FAST_PROV +#define RETRANSMIT_TIMEOUT K_MSEC(360) +#define TRANSACTION_TIMEOUT K_SECONDS(3) +#define PROTOCOL_TIMEOUT K_SECONDS(6) +#else +#define RETRANSMIT_TIMEOUT K_MSEC(500) +#define TRANSACTION_TIMEOUT K_SECONDS(30) +#define PROTOCOL_TIMEOUT K_SECONDS(60) +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + +#if CONFIG_BLE_MESH_PB_GATT +#define PROV_BUF_HEADROOM 5 +#else +#define PROV_BUF_HEADROOM 0 +#endif + +#define PROV_BUF(name, len) \ + NET_BUF_SIMPLE_DEFINE(name, PROV_BUF_HEADROOM + len) + +#define PROV_RX_BUF_SIZE 65 + +#define BLE_MESH_REC_MAX_ID 0x0013 + +enum { + PROV_ALG_P256_CMAC_AES128, +#if CONFIG_BLE_MESH_PROV_EPA + PROV_ALG_P256_HMAC_SHA256, +#endif + PROV_ALG_METHOD_MAX_NUM, +}; + +struct prov_rx { + uint32_t link_id; + uint8_t xact_id; + uint8_t gpc; +}; + +enum { + CONNECTING, /* Indicate if PB-GATT connection is in progress (Provisioner) */ + REMOTE_PUB_KEY, /* Remote key has been received (Node & Provisioner) */ + OOB_PUB_KEY, /* OOB public key is available (Node) */ + LINK_ACTIVE, /* Link has been opened (Node & Provisioner) */ + WAIT_GEN_DHKEY, /* Waiting for remote public key to generate DHKey (Provisioner) */ + HAVE_DHKEY, /* DHKey has been calculated (Node & Provisioner) */ + SEND_CONFIRM, /* Waiting to send Confirm value (Node & Provisioner) */ + WAIT_NUMBER, /* Waiting for number input from user (Node & Provisioner) */ + WAIT_STRING, /* Waiting for string input from user (Node & Provisioner) */ + LINK_INVALID, /* Error occurred during provisioning (Node) */ + LINK_CLOSING, /* Indicate Link Close is being sent (Provisioner) */ + PB_REMOTE, /* Indicate if the link is used by PB-Remote */ + PB_NPPI, /* Indicate if the link is used by NPPI */ + PBR_OPENING, /* Indicate if the PB-Remote Open Link Procedure is ongoing*/ + WAIT_PK_OBR, /* Waiting for Remote Provisioning Outbound Report for Public Key */ + PROV_NUM_FLAGS, +}; + +struct bt_mesh_prov_link { + BLE_MESH_ATOMIC_DEFINE(flags, PROV_NUM_FLAGS); + + uint8_t expect; /* Next expected PDU */ + + uint8_t public_key; /* Public Key type */ + + uint8_t auth_method; /* Authentication method */ + uint8_t auth_action; /* Authentication action */ + uint8_t auth_size; /* Authentication size */ + + uint8_t auth[PROV_AUTH_MAX_SIZE]; /* Authentication Value */ + uint8_t rand[PROV_RAND_MAX_SIZE]; /* Local Random */ + uint8_t conf[PROV_CONF_MAX_SIZE]; /* Remote Confirmation */ + uint8_t local_conf[PROV_CONF_MAX_SIZE]; /* Local Confirmation */ + + uint8_t dhkey[32]; /* Calculated DHKey */ + + uint8_t algorithm; /* Provisioning Algorithm */ + + uint8_t conf_salt[PROV_CONF_MAX_SIZE]; /* ConfirmationSalt */ + uint8_t conf_key[PROV_CONF_MAX_SIZE]; /* ConfirmationKey */ + uint8_t conf_inputs[145]; /* ConfirmationInputs */ + uint8_t prov_salt[16]; /* Provisioning Salt */ + + bt_mesh_addr_t addr; /* Device address */ + +#if CONFIG_BLE_MESH_NODE + bool invite_recv; /* Indicate if Provisioning Invite is received or not */ +#endif /* CONFIG_BLE_MESH_NODE */ + +#if CONFIG_BLE_MESH_PROVISIONER + uint8_t uuid[16]; /* Check if device is being provisioned */ + uint16_t oob_info; /* OOB info of this device */ + uint8_t element_num; /* Element num of device */ + uint8_t kri_flags; /* Key refresh flag and iv update flag */ + uint16_t assign_addr; /* Application assigned address for the device */ + uint16_t unicast_addr; /* Unicast address allocated for device */ + +#if CONFIG_BLE_MESH_CERT_BASED_PROV + uint16_t record_id_expect; /* The record id field of expected record response PDU */ + uint16_t offset_expect; /* The offset field of expected record response PDU */ + uint16_t max_size; /* The maximum size of provisioning record fragment can receive*/ + + uint8_t *records[BLE_MESH_REC_MAX_ID]; /* Used to store provisioning records */ +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + +#if CONFIG_BLE_MESH_PB_ADV + uint8_t expect_ack_for; /* Transaction ACK expected for provisioning pdu */ +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +#if CONFIG_BLE_MESH_FAST_PROV + uint8_t tx_pdu_type; /* Current transmitted Provisioning PDU type */ + uint8_t last_tx_pdu; /* Type of last sent Provisioning PDU */ +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + +#if CONFIG_BLE_MESH_PB_GATT + struct bt_mesh_conn *conn; /* GATT connection */ + int (*pb_gatt_send)(struct bt_mesh_prov_link *link, struct net_buf_simple *msg); +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if CONFIG_BLE_MESH_PB_ADV + uint32_t link_id; /* Link ID */ + uint8_t pending_ack; /* Decide which transaction id ack is pending */ + uint8_t reason; /* Reason of closing provisioning link */ + + /* Callback used to get next transaction id */ + uint8_t (*next_xact_id)(struct bt_mesh_prov_link *link); + + /* Callback used to reset PB-ADV link */ + void (*reset_adv_link)(struct bt_mesh_prov_link *link, uint8_t reason); + + /* Callback used to handle PB-ADV 30s timeout */ + void (*retrans_timeout)(struct bt_mesh_prov_link *link, uint8_t reason); + + struct { + uint8_t id; /* Transaction ID */ + uint8_t prev_id; /* Previous Transaction ID */ + uint8_t seg; /* Bit-field of unreceived segments */ + uint8_t last_seg; /* Last segment (to check length) */ + uint8_t fcs; /* Expected FCS value */ + struct net_buf_simple *buf; /* Incoming buffer */ + } rx; + + struct { + int64_t start; /* Start timestamp of the transaction */ + uint8_t id; /* Transaction id*/ + struct net_buf *buf[3]; /* Pending outgoing buffer(s) */ + struct k_delayed_work retransmit; /* Retransmit timer */ + } tx; + + bt_mesh_mutex_t buf_lock; /* Mutex used to protect PB-ADV buffer */ +#endif /* CONFIG_BLE_MESH_PB_ADV */ + + uint8_t pb_remote_uuid[16]; /* Device UUID used by PB-Remote */ + uint8_t pb_remote_timeout; /* Timeout value used by PB-Remote Open Link procedure */ + uint8_t pb_remote_nppi; /* NPPI Procedure */ + uint8_t pb_remote_pub_key; /* Public Key used by PB-Remote */ + uint8_t pb_remote_cbd:1, /* Indicate if the link is closed by the unprovisioned device */ + pb_remote_csp:1, /* Indicate if the link is close as server can not send pdu */ + pb_remote_reset:1; /* Indicate if the link is reset */ + void *pb_remote_data; /* Remote Provisioning Server/Client PB-Remote information */ + /* Callback used to send Remote Provisioning messages */ + int (*pb_remote_send)(struct bt_mesh_prov_link *link, struct net_buf_simple *buf); + /* Callback used to notify Remote Provisioning Server that link is closed */ + void (*pb_remote_close)(struct bt_mesh_prov_link *link, uint8_t reason); + + struct k_delayed_work prot_timer; /* Protocol timer */ +}; + +const struct bt_mesh_prov *bt_mesh_prov_get(void); + +int bt_mesh_prov_set(const struct bt_mesh_prov *val); + +void bt_mesh_prov_buf_init(struct net_buf_simple *buf, uint8_t type); + +bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action); + +bt_mesh_input_action_t bt_mesh_prov_input_action(uint8_t action); + +bool bt_mesh_prov_pdu_check(uint8_t type, uint16_t length, uint8_t *reason); + +int bt_mesh_prov_send_adv(struct bt_mesh_prov_link *link, struct net_buf_simple *msg); + +bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf, + struct prov_rx *rx, bool *close); + +bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf, + struct prov_rx *rx, bool *close); + +void bt_mesh_gen_prov_ack_send(struct bt_mesh_prov_link *link, uint8_t xact_id); + +void bt_mesh_prov_clear_tx(struct bt_mesh_prov_link *link, bool cancel); + +int bt_mesh_prov_retransmit_init(struct bt_mesh_prov_link *link); + +int bt_mesh_prov_bearer_ctl_send(struct bt_mesh_prov_link *link, uint8_t op, + void *data, uint8_t data_len); + +int bt_mesh_prov_send(struct bt_mesh_prov_link *link, struct net_buf_simple *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* _PROV_COMMON_H_ */ diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index f5458008fd..d32e4f2af3 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -16,565 +16,183 @@ #include "foundation.h" #include "mesh/common.h" #include "mesh/proxy.h" +#include "proxy_common.h" #include "proxy_server.h" +#include "proxy_client.h" +#include "prov_common.h" #include "prov_node.h" +#include "mesh_v1.1/utils.h" + #if CONFIG_BLE_MESH_NODE -/* 3 transmissions, 20ms interval */ -#define PROV_XMIT BLE_MESH_TRANSMIT(2, 20) - -#define AUTH_METHOD_NO_OOB 0x00 -#define AUTH_METHOD_STATIC 0x01 -#define AUTH_METHOD_OUTPUT 0x02 -#define AUTH_METHOD_INPUT 0x03 - -#define OUTPUT_OOB_BLINK 0x00 -#define OUTPUT_OOB_BEEP 0x01 -#define OUTPUT_OOB_VIBRATE 0x02 -#define OUTPUT_OOB_NUMBER 0x03 -#define OUTPUT_OOB_STRING 0x04 - -#define INPUT_OOB_PUSH 0x00 -#define INPUT_OOB_TWIST 0x01 -#define INPUT_OOB_NUMBER 0x02 -#define INPUT_OOB_STRING 0x03 - -#define PUB_KEY_NO_OOB 0x00 -#define PUB_KEY_OOB 0x01 - -#define PROV_ERR_NONE 0x00 -#define PROV_ERR_NVAL_PDU 0x01 -#define PROV_ERR_NVAL_FMT 0x02 -#define PROV_ERR_UNEXP_PDU 0x03 -#define PROV_ERR_CFM_FAILED 0x04 -#define PROV_ERR_RESOURCES 0x05 -#define PROV_ERR_DECRYPT 0x06 -#define PROV_ERR_UNEXP_ERR 0x07 -#define PROV_ERR_ADDR 0x08 - -#define PROV_INVITE 0x00 -#define PROV_CAPABILITIES 0x01 -#define PROV_START 0x02 -#define PROV_PUB_KEY 0x03 -#define PROV_INPUT_COMPLETE 0x04 -#define PROV_CONFIRM 0x05 -#define PROV_RANDOM 0x06 -#define PROV_DATA 0x07 -#define PROV_COMPLETE 0x08 -#define PROV_FAILED 0x09 - -#define PROV_ALG_P256 0x00 - -#define GPCF(gpc) (gpc & 0x03) -#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) -#define GPC_ACK 0x01 -#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) -#define GPC_CTL(op) (((op) << 2) | 0x03) - -#define START_PAYLOAD_MAX 20 -#define CONT_PAYLOAD_MAX 23 -#define START_LAST_SEG_MAX 2 - -#define START_LAST_SEG(gpc) (gpc >> 2) -#define CONT_SEG_INDEX(gpc) (gpc >> 2) - -#define BEARER_CTL(gpc) (gpc >> 2) -#define LINK_OPEN 0x00 -#define LINK_ACK 0x01 -#define LINK_CLOSE 0x02 - -#define CLOSE_REASON_SUCCESS 0x00 -#define CLOSE_REASON_TIMEOUT 0x01 -#define CLOSE_REASON_FAILED 0x02 - -#define XACT_SEG_DATA(_seg) (&link.rx.buf->data[20 + ((_seg - 1) * 23)]) -#define XACT_SEG_RECV(_seg) (link.rx.seg &= ~(1 << (_seg))) - -#define XACT_NVAL 0xff - -enum { - REMOTE_PUB_KEY, /* Remote key has been received */ - OOB_PUB_KEY, /* OOB public key is available */ - LINK_ACTIVE, /* Link has been opened */ - HAVE_DHKEY, /* DHKey has been calculated */ - SEND_CONFIRM, /* Waiting to send Confirm value */ - WAIT_NUMBER, /* Waiting for number input from user */ - WAIT_STRING, /* Waiting for string input from user */ - LINK_INVALID, /* Error occurred during provisioning */ - - NUM_FLAGS, -}; - -struct prov_link { - BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); -#if defined(CONFIG_BLE_MESH_PB_GATT) - struct bt_mesh_conn *conn; /* GATT connection */ -#endif - uint8_t dhkey[32]; /* Calculated DHKey */ - uint8_t expect; /* Next expected PDU */ - - bool oob_pk_flag; /* Flag indicates whether using OOB public key */ - - uint8_t oob_method; - uint8_t oob_action; - uint8_t oob_size; - - uint8_t conf[16]; /* Remote Confirmation */ - uint8_t rand[16]; /* Local Random */ - uint8_t auth[16]; /* Authentication Value */ - - uint8_t conf_salt[16]; /* ConfirmationSalt */ - uint8_t conf_key[16]; /* ConfirmationKey */ - uint8_t conf_inputs[145]; /* ConfirmationInputs */ - uint8_t prov_salt[16]; /* Provisioning Salt */ - -#if defined(CONFIG_BLE_MESH_PB_ADV) - uint32_t id; /* Link ID */ - uint8_t tx_pdu_type; /* The previously transmitted Provisioning PDU type */ - - struct { - uint8_t id; /* Transaction ID */ - uint8_t prev_id; /* Previous Transaction ID */ - uint8_t seg; /* Bit-field of unreceived segments */ - uint8_t last_seg; /* Last segment (to check length) */ - uint8_t fcs; /* Expected FCS value */ - struct net_buf_simple *buf; - } rx; - - struct { - /* Start timestamp of the transaction */ - int64_t start; - - /* Transaction id*/ - uint8_t id; - - /* Pending outgoing buffer(s) */ - struct net_buf *buf[3]; - - /* Retransmit timer */ - struct k_delayed_work retransmit; - } tx; +#if CONFIG_BLE_MESH_PB_ADV && !CONFIG_BLE_MESH_PB_GATT +NET_BUF_SIMPLE_DEFINE_STATIC(rx_buf, PROV_RX_BUF_SIZE); #endif - struct k_delayed_work prot_timer; -}; +static struct bt_mesh_prov_link prov_link; -struct prov_rx { - uint32_t link_id; - uint8_t xact_id; - uint8_t gpc; -}; - -#define BUF_TIMEOUT K_MSEC(400) - -#if defined(CONFIG_BLE_MESH_FAST_PROV) -#define RETRANSMIT_TIMEOUT K_MSEC(360) -#define TRANSACTION_TIMEOUT K_SECONDS(3) -#define PROTOCOL_TIMEOUT K_SECONDS(6) -#else -#define RETRANSMIT_TIMEOUT K_MSEC(500) -#define TRANSACTION_TIMEOUT K_SECONDS(30) -#define PROTOCOL_TIMEOUT K_SECONDS(60) -#endif /* CONFIG_BLE_MESH_FAST_PROV */ - -#if defined(CONFIG_BLE_MESH_PB_GATT) -#define PROV_BUF_HEADROOM 5 -#else -#define PROV_BUF_HEADROOM 0 -NET_BUF_SIMPLE_DEFINE_STATIC(rx_buf, 65); +#if CONFIG_BLE_MESH_PB_ADV +static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason); +extern uint8_t node_next_xact_id(struct bt_mesh_prov_link *link); #endif -#define PROV_BUF(name, len) \ - NET_BUF_SIMPLE_DEFINE(name, PROV_BUF_HEADROOM + len) - -static struct prov_link link; - -static const struct bt_mesh_prov *prov; - -#if defined(CONFIG_BLE_MESH_PB_ADV) -static bt_mesh_mutex_t pb_buf_lock; - -static inline void bt_mesh_pb_buf_mutex_new(void) -{ - if (!pb_buf_lock.mutex) { - bt_mesh_mutex_create(&pb_buf_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_pb_buf_mutex_free(void) -{ - bt_mesh_mutex_free(&pb_buf_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_pb_buf_lock(void) -{ - bt_mesh_mutex_lock(&pb_buf_lock); -} - -static inline void bt_mesh_pb_buf_unlock(void) -{ - bt_mesh_mutex_unlock(&pb_buf_lock); -} -#endif /* CONFIG_BLE_MESH_PB_ADV */ - -static void reset_state(void) -{ - k_delayed_work_cancel(&link.prot_timer); - - /* Disable Attention Timer if it was set */ - if (link.conf_inputs[0]) { - bt_mesh_attention(NULL, 0); - } - -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (link.conn) { - bt_mesh_conn_unref(link.conn); - } +#if CONFIG_BLE_MESH_PB_GATT +static int prov_send_gatt(struct bt_mesh_prov_link *link, struct net_buf_simple *msg); #endif -#if defined(CONFIG_BLE_MESH_PB_ADV) - /* Clear everything except the retransmit and protocol timer - * delayed work objects. - */ - (void)memset(&link, 0, offsetof(struct prov_link, tx.retransmit)); - link.rx.prev_id = XACT_NVAL; +static void prov_send_fail_msg(uint8_t err); -#if defined(CONFIG_BLE_MESH_PB_GATT) - link.rx.buf = bt_mesh_proxy_server_get_buf(); -#else - net_buf_simple_reset(&rx_buf); - link.rx.buf = &rx_buf; -#endif /* PB_GATT */ - -#else /* !PB_ADV */ - /* Clear everything except the protocol timer (k_delayed_work) */ - (void)memset(&link, 0, offsetof(struct prov_link, prot_timer)); -#endif /* PB_ADV */ +struct bt_mesh_prov_link *bt_mesh_prov_node_get_link(void) +{ + return &prov_link; } -#if defined(CONFIG_BLE_MESH_PB_ADV) -static void buf_sent(int err, void *user_data) +static void close_link(uint8_t reason) { - if (!link.tx.buf[0]) { + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + if (prov_link.pb_remote_close) { + prov_link.pb_remote_close(&prov_link, reason); + } return; } - k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); + prov_send_fail_msg(reason); } -static struct bt_mesh_send_cb buf_sent_cb = { - .end = buf_sent, -}; - -static void free_segments(void) +void bt_mesh_prov_node_close_link(uint8_t reason) { - int i; + close_link(reason); +} - bt_mesh_pb_buf_lock(); +static void reset_state(void) +{ + k_delayed_work_cancel(&prov_link.prot_timer); - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - link.tx.buf[i] = NULL; - bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); - /* Mark as canceled */ - BLE_MESH_ADV(buf)->busy = 0U; - net_buf_unref(buf); + /* Disable Attention Timer if it was set */ + if (prov_link.conf_inputs[0]) { + bt_mesh_attention(NULL, 0); } - bt_mesh_pb_buf_unlock(); +#if CONFIG_BLE_MESH_PB_GATT + if (prov_link.conn) { + bt_mesh_conn_unref(prov_link.conn); + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if CONFIG_BLE_MESH_PB_ADV + /* Clear everything except the retransmit and protocol timer + * delayed work objects. + */ + (void)memset(&prov_link, 0, offsetof(struct bt_mesh_prov_link, tx.retransmit)); + + prov_link.pending_ack = PROV_XACT_NVAL; + + prov_link.rx.prev_id = PROV_XACT_NVAL; +#if CONFIG_BLE_MESH_PB_GATT + prov_link.rx.buf = bt_mesh_proxy_server_get_buf(); +#else + net_buf_simple_reset(&rx_buf); + prov_link.rx.buf = &rx_buf; +#endif /* CONFIG_BLE_MESH_PB_GATT */ + + prov_link.next_xact_id = node_next_xact_id; + prov_link.reset_adv_link = reset_adv_link; + prov_link.retrans_timeout = reset_adv_link; + prov_link.invite_recv = false; + +#if CONFIG_BLE_MESH_FAST_PROV + prov_link.last_tx_pdu = PROV_COMPLETE; +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + +#else /* !CONFIG_BLE_MESH_PB_ADV */ + /* Clear everything except the protocol timer (k_delayed_work) */ + (void)memset(&prov_link, 0, offsetof(struct bt_mesh_prov_link, prot_timer)); +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if CONFIG_BLE_MESH_PB_GATT + prov_link.pb_gatt_send = prov_send_gatt; +#endif /* CONFIG_BLE_MESH_PB_GATT */ } -static void prov_clear_tx(void) +#if CONFIG_BLE_MESH_PB_ADV +static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { - BT_DBG("%s", __func__); + ARG_UNUSED(link); - k_delayed_work_cancel(&link.tx.retransmit); + bt_mesh_prov_clear_tx(&prov_link, true); - free_segments(); -} - -static void reset_adv_link(void) -{ - prov_clear_tx(); - - if (prov->link_close) { - prov->link_close(BLE_MESH_PROV_ADV); + if (bt_mesh_prov_get()->link_close) { + bt_mesh_prov_get()->link_close(BLE_MESH_PROV_ADV, reason); } -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Remove the link id from exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link.id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &prov_link.link_id); #endif reset_state(); } - -static struct net_buf *adv_buf_create(void) -{ - struct net_buf *buf = NULL; - - buf = bt_mesh_adv_create(BLE_MESH_ADV_PROV, PROV_XMIT, BUF_TIMEOUT); - if (!buf) { - BT_ERR("Out of provisioning buffers"); - return NULL; - } - - return buf; -} - -static uint8_t pending_ack = XACT_NVAL; - -static void ack_complete(uint16_t duration, int err, void *user_data) -{ - BT_DBG("xact %u complete", (uint8_t)pending_ack); - pending_ack = XACT_NVAL; -} - -static void gen_prov_ack_send(uint8_t xact_id) -{ - static const struct bt_mesh_send_cb cb = { - .start = ack_complete, - }; - const struct bt_mesh_send_cb *complete = NULL; - struct net_buf *buf = NULL; - - BT_DBG("xact_id %u", xact_id); - - if (pending_ack == xact_id) { - BT_DBG("Not sending duplicate ack"); - return; - } - - buf = adv_buf_create(); - if (!buf) { - return; - } - - if (pending_ack == XACT_NVAL) { - pending_ack = xact_id; - complete = &cb; - } else { - complete = NULL; - } - - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_ACK); - - bt_mesh_adv_send(buf, complete, NULL); - net_buf_unref(buf); -} - -static void send_reliable(void) -{ - int i; - - link.tx.start = k_uptime_get(); - - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } -} - -static int bearer_ctl_send(uint8_t op, void *data, uint8_t data_len) -{ - struct net_buf *buf = NULL; - - BT_DBG("op 0x%02x data_len %u", op, data_len); - - prov_clear_tx(); - - buf = adv_buf_create(); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_be32(buf, link.id); - /* Transaction ID, always 0 for Bearer messages */ - net_buf_add_u8(buf, 0x00); - net_buf_add_u8(buf, GPC_CTL(op)); - net_buf_add_mem(buf, data, data_len); - - link.tx.buf[0] = buf; - send_reliable(); - - return 0; -} - -static uint8_t last_seg(uint8_t len) -{ - if (len <= START_PAYLOAD_MAX) { - return 0; - } - - len -= START_PAYLOAD_MAX; - - return 1 + (len / CONT_PAYLOAD_MAX); -} - -static inline uint8_t next_transaction_id(void) -{ - if (link.tx.id != 0U && link.tx.id != 0xFF) { - return ++link.tx.id; - } - - link.tx.id = 0x80; - return link.tx.id; -} - -static int prov_send_adv(struct net_buf_simple *msg) -{ - struct net_buf *start = NULL, *buf = NULL; - uint8_t seg_len = 0U, seg_id = 0U; - uint8_t xact_id = 0U; - int32_t timeout = PROTOCOL_TIMEOUT; - - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); - - prov_clear_tx(); - - start = adv_buf_create(); - if (!start) { - return -ENOBUFS; - } - - xact_id = next_transaction_id(); - net_buf_add_be32(start, link.id); - net_buf_add_u8(start, xact_id); - - net_buf_add_u8(start, GPC_START(last_seg(msg->len))); - net_buf_add_be16(start, msg->len); - net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); - - link.tx.buf[0] = start; - /* Changed by Espressif, get message type */ - link.tx_pdu_type = msg->data[0]; - - seg_len = MIN(msg->len, START_PAYLOAD_MAX); - BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); - net_buf_add_mem(start, msg->data, seg_len); - net_buf_simple_pull(msg, seg_len); - - buf = start; - for (seg_id = 1U; msg->len > 0; seg_id++) { - if (seg_id >= ARRAY_SIZE(link.tx.buf)) { - BT_ERR("Too big message (seg_id %d)", seg_id); - free_segments(); - return -E2BIG; - } - - buf = adv_buf_create(); - if (!buf) { - free_segments(); - return -ENOBUFS; - } - - link.tx.buf[seg_id] = buf; - - seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); - - BT_DBG("seg_id %u len %u: %s", seg_id, seg_len, - bt_hex(msg->data, seg_len)); - - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_CONT(seg_id)); - net_buf_add_mem(buf, msg->data, seg_len); - net_buf_simple_pull(msg, seg_len); - } - - send_reliable(); - - /* Changed by Espressif, add provisioning timeout timer operations. - * When sending a provisioning PDU successfully, restart the 60s timer. - */ -#if defined(CONFIG_BLE_MESH_FAST_PROV) - if (link.tx_pdu_type >= PROV_COMPLETE) { - timeout = K_SECONDS(60); - } -#endif - k_delayed_work_submit(&link.prot_timer, timeout); - - return 0; -} - #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) -static int prov_send_gatt(struct net_buf_simple *msg) +#if CONFIG_BLE_MESH_PB_GATT +static int prov_send_gatt(struct bt_mesh_prov_link *link, struct net_buf_simple *msg) { int err = 0; - if (!link.conn) { + ARG_UNUSED(link); + + if (!prov_link.conn) { + BT_ERR("PB-GATT send, not connected"); return -ENOTCONN; } /* Changed by Espressif, add provisioning timeout timer operations. * When sending a provisioning PDU successfully, restart the 60s timer. */ - err = bt_mesh_proxy_server_send(link.conn, BLE_MESH_PROXY_PROV, msg); +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT && CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + err = bt_mesh_proxy_client_send(link->conn, BLE_MESH_PROXY_PROV, msg); + + /* TODO: do we need to check the err here? */ + bt_mesh_rpr_srv_send_outbound_report(link->pb_remote_uuid, true); + } else +#endif + { + err = bt_mesh_proxy_server_send(prov_link.conn, BLE_MESH_PROXY_PROV, msg); + } + if (err) { BT_ERR("Failed to send provisioning PDU"); return err; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_delayed_work_submit(&prov_link.prot_timer, PROTOCOL_TIMEOUT); return 0; } #endif /* CONFIG_BLE_MESH_PB_GATT */ -static inline int prov_send(struct net_buf_simple *buf) -{ -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (link.conn) { - return prov_send_gatt(buf); - } -#endif -#if defined(CONFIG_BLE_MESH_PB_ADV) - return prov_send_adv(buf); -#else - return 0; -#endif -} - -static void prov_buf_init(struct net_buf_simple *buf, uint8_t type) -{ - net_buf_simple_reserve(buf, PROV_BUF_HEADROOM); - net_buf_simple_add_u8(buf, type); -} - static void prov_send_fail_msg(uint8_t err) { PROV_BUF(buf, 2); - prov_buf_init(&buf, PROV_FAILED); + /** + * For the case MESH/NODE/PROV/BV-10-C, Node must send Transaction ACK + * before Provisioning Failed message is transmitted. + */ + bt_mesh_gen_prov_ack_send(&prov_link, prov_link.rx.id); + + bt_mesh_prov_buf_init(&buf, PROV_FAILED); net_buf_simple_add_u8(&buf, err); - if (prov_send(&buf)) { + if (bt_mesh_prov_send(&prov_link, &buf)) { BT_ERR("Failed to send Provisioning Failed message"); } - bt_mesh_atomic_set_bit(link.flags, LINK_INVALID); + bt_mesh_atomic_set_bit(prov_link.flags, LINK_INVALID); } static void prov_invite(const uint8_t *data) @@ -587,108 +205,71 @@ static void prov_invite(const uint8_t *data) bt_mesh_attention(NULL, data[0]); } - link.conf_inputs[0] = data[0]; +#if CONFIG_BLE_MESH_CERT_BASED_PROV + /* Indicate prov_invite is received */ + prov_link.invite_recv = true; +#endif - prov_buf_init(&buf, PROV_CAPABILITIES); + prov_link.conf_inputs[0] = data[0]; + + bt_mesh_prov_buf_init(&buf, PROV_CAPABILITIES); /* Number of Elements supported */ net_buf_simple_add_u8(&buf, bt_mesh_elem_count()); - /* Supported algorithms - FIPS P-256 Eliptic Curve */ - net_buf_simple_add_be16(&buf, BIT(PROV_ALG_P256)); + /* NOTE: If bit 1 of the OOB Type field is set to 1, bit 0 of + * the Algorithms field shall be set to 0. + */ + /* Supported algorithms - FIPS P-256 Elliptic Curve */ +#if CONFIG_BLE_MESH_PROV_EPA + if (bt_mesh_prov_get()->oob_type & BIT(PROV_ONLY_OOB_AUTH_SUPPORT)) { + net_buf_simple_add_be16(&buf, BIT(PROV_ALG_P256_HMAC_SHA256)); + } else { + net_buf_simple_add_be16(&buf, (BIT(PROV_ALG_P256_CMAC_AES128) | + BIT(PROV_ALG_P256_HMAC_SHA256))); + } +#else + net_buf_simple_add_be16(&buf, BIT(PROV_ALG_P256_CMAC_AES128)); +#endif /* Public Key Type */ - net_buf_simple_add_u8(&buf, prov->oob_pub_key); + net_buf_simple_add_u8(&buf, bt_mesh_prov_get()->oob_pub_key); - /* Static OOB Type */ - net_buf_simple_add_u8(&buf, prov->static_val ? BIT(0) : 0x00); + /* OOB Type */ + net_buf_simple_add_u8(&buf, bt_mesh_prov_get()->oob_type); /* Output OOB Size */ - net_buf_simple_add_u8(&buf, prov->output_size); + net_buf_simple_add_u8(&buf, bt_mesh_prov_get()->output_size); /* Output OOB Action */ - net_buf_simple_add_be16(&buf, prov->output_actions); + net_buf_simple_add_be16(&buf, bt_mesh_prov_get()->output_actions); /* Input OOB Size */ - net_buf_simple_add_u8(&buf, prov->input_size); + net_buf_simple_add_u8(&buf, bt_mesh_prov_get()->input_size); /* Input OOB Action */ - net_buf_simple_add_be16(&buf, prov->input_actions); + net_buf_simple_add_be16(&buf, bt_mesh_prov_get()->input_actions); - memcpy(&link.conf_inputs[1], &buf.data[1], 11); + memcpy(&prov_link.conf_inputs[1], &buf.data[1], 11); - if (prov_send(&buf)) { + if (bt_mesh_prov_send(&prov_link, &buf)) { BT_ERR("Failed to send capabilities"); return; } - link.expect = PROV_START; + prov_link.expect = PROV_START; } static void prov_capabilities(const uint8_t *data) -{ - uint16_t algorithms = 0U, output_action = 0U, input_action = 0U; - - BT_DBG("Elements: %u", data[0]); - - algorithms = sys_get_be16(&data[1]); - BT_DBG("Algorithms: %u", algorithms); - - BT_DBG("Public Key Type: 0x%02x", data[3]); - BT_DBG("Static OOB Type: 0x%02x", data[4]); - BT_DBG("Output OOB Size: %u", data[5]); - - output_action = sys_get_be16(&data[6]); - BT_DBG("Output OOB Action: 0x%04x", output_action); - - BT_DBG("Input OOB Size: %u", data[8]); - - input_action = sys_get_be16(&data[9]); - BT_DBG("Input OOB Action: 0x%04x", input_action); - - ((void) algorithms); - ((void) output_action); - ((void) input_action); -} - -static bt_mesh_output_action_t output_action(uint8_t action) -{ - switch (action) { - case OUTPUT_OOB_BLINK: - return BLE_MESH_BLINK; - case OUTPUT_OOB_BEEP: - return BLE_MESH_BEEP; - case OUTPUT_OOB_VIBRATE: - return BLE_MESH_VIBRATE; - case OUTPUT_OOB_NUMBER: - return BLE_MESH_DISPLAY_NUMBER; - case OUTPUT_OOB_STRING: - return BLE_MESH_DISPLAY_STRING; - default: - return BLE_MESH_NO_OUTPUT; - } -} - -static bt_mesh_input_action_t input_action(uint8_t action) -{ - switch (action) { - case INPUT_OOB_PUSH: - return BLE_MESH_PUSH; - case INPUT_OOB_TWIST: - return BLE_MESH_TWIST; - case INPUT_OOB_NUMBER: - return BLE_MESH_ENTER_NUMBER; - case INPUT_OOB_STRING: - return BLE_MESH_ENTER_STRING; - default: - return BLE_MESH_NO_INPUT; - } -} +{} static int prov_auth(uint8_t method, uint8_t action, uint8_t size) { bt_mesh_output_action_t output = 0U; bt_mesh_input_action_t input = 0U; + uint8_t auth_size = 0; + + auth_size = PROV_AUTH_SIZE(&prov_link); switch (method) { case AUTH_METHOD_NO_OOB: @@ -696,30 +277,36 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size) return -EINVAL; } - (void)memset(link.auth, 0, sizeof(link.auth)); + (void)memset(prov_link.auth, 0, sizeof(prov_link.auth)); return 0; + case AUTH_METHOD_STATIC: if (action || size) { return -EINVAL; } - memcpy(link.auth + 16 - prov->static_val_len, - prov->static_val, prov->static_val_len); - (void)memset(link.auth, 0, - sizeof(link.auth) - prov->static_val_len); + if (bt_mesh_prov_get()->static_val_len > auth_size) { + memcpy(prov_link.auth, bt_mesh_prov_get()->static_val, auth_size); + } else { + memcpy(prov_link.auth + auth_size - bt_mesh_prov_get()->static_val_len, + bt_mesh_prov_get()->static_val, bt_mesh_prov_get()->static_val_len); + (void)memset(prov_link.auth, 0, + auth_size - bt_mesh_prov_get()->static_val_len); + } + return 0; case AUTH_METHOD_OUTPUT: - output = output_action(action); + output = bt_mesh_prov_output_action(action); if (!output) { return -EINVAL; } - if (!(prov->output_actions & output)) { + if (!(bt_mesh_prov_get()->output_actions & output)) { return -EINVAL; } - if (size > prov->output_size) { + if (size > bt_mesh_prov_get()->output_size) { return -EINVAL; } @@ -740,11 +327,11 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size) } str[size] = '\0'; - memcpy(link.auth, str, size); - (void)memset(link.auth + size, 0, - sizeof(link.auth) - size); + memcpy(prov_link.auth, str, size); + (void)memset(prov_link.auth + size, 0, + sizeof(prov_link.auth) - size); - return prov->output_string((char *)str); + return bt_mesh_prov_get()->output_string((char *)str); } else { uint32_t div[8] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 @@ -765,33 +352,33 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size) num %= div[size - 1]; } - sys_put_be32(num, &link.auth[12]); - (void)memset(link.auth, 0, 12); + sys_put_be32(num, &prov_link.auth[auth_size - 4]); + (void)memset(prov_link.auth, 0, auth_size - 4); - return prov->output_number(output, num); + return bt_mesh_prov_get()->output_number(output, num); } case AUTH_METHOD_INPUT: - input = input_action(action); + input = bt_mesh_prov_input_action(action); if (!input) { return -EINVAL; } - if (!(prov->input_actions & input)) { + if (!(bt_mesh_prov_get()->input_actions & input)) { return -EINVAL; } - if (size > prov->input_size) { + if (size > bt_mesh_prov_get()->input_size) { return -EINVAL; } if (input == BLE_MESH_ENTER_STRING) { - bt_mesh_atomic_set_bit(link.flags, WAIT_STRING); + bt_mesh_atomic_set_bit(prov_link.flags, WAIT_STRING); } else { - bt_mesh_atomic_set_bit(link.flags, WAIT_NUMBER); + bt_mesh_atomic_set_bit(prov_link.flags, WAIT_NUMBER); } - return prov->input(input, size); + return bt_mesh_prov_get()->input(input, size); default: return -EINVAL; @@ -806,124 +393,193 @@ static void prov_start(const uint8_t *data) BT_INFO("Auth Action: 0x%02x", data[3]); BT_INFO("Auth Size: 0x%02x", data[4]); - if (data[0] != PROV_ALG_P256) { + prov_link.algorithm = data[0]; + if (data[0] >= PROV_ALG_METHOD_MAX_NUM) { BT_ERR("Unknown algorithm 0x%02x", data[0]); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); + close_link(PROV_ERR_NVAL_FMT); return; } - if (data[1] != prov->oob_pub_key) { + /* If bit 1 of the OOB Type field of the Provisioning Capabilities PDU + * is set to 1 (Only OOB authenticated provisioning supported) and any + * of the following conditions is met: + * 1. the Algorithm field of the Provisioning Start PDU is not set to + * BTM_ECDH_P256_CMAC_AES128_AES_CCM and the Provisioning Start PDU + * has the Authentication Method field set to 0x00 (Authentication + * with No OOB). + * 2. the Algorithm field is set to BTM_ECDH_P256_CMAC_AES128_AES_CCM. + * the provisioning protocol shall fail and the message shall be treated + * by the Provisionee as an error in the provisioning protocol. + */ +#if CONFIG_BLE_MESH_PROV_EPA + if ((bt_mesh_prov_get()->oob_type & BIT(PROV_ONLY_OOB_AUTH_SUPPORT)) && + ((data[0] == PROV_ALG_P256_HMAC_SHA256 && data[2] == AUTH_METHOD_NO_OOB) || + data[0] == PROV_ALG_P256_CMAC_AES128)) { + close_link(PROV_ERR_NVAL_FMT); + return; + } +#endif + + if (data[1] != bt_mesh_prov_get()->oob_pub_key) { BT_ERR("Invalid public key type: 0x%02x", data[1]); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); + close_link(PROV_ERR_NVAL_FMT); return; } - memcpy(&link.conf_inputs[12], data, 5); + prov_link.public_key = data[1]; - link.expect = PROV_PUB_KEY; + memcpy(&prov_link.conf_inputs[12], data, 5); + + prov_link.expect = PROV_PUB_KEY; /* If Provisioning Start PDU indicates that provisioner chooses * OOB public key, then callback to the application layer to let * users input public & private key pair. */ - link.oob_pk_flag = data[1] ? true : false; - if (link.oob_pk_flag) { - prov->oob_pub_key_cb(); + if (prov_link.public_key == PROV_OOB_PUB_KEY) { + bt_mesh_prov_get()->oob_pub_key_cb(); } - if (prov_auth(data[2], data[3], data[4]) < 0) { + if (prov_auth(data[2], data[3], data[4])) { BT_ERR("Invalid authentication method: 0x%02x; " "action: 0x%02x; size: 0x%02x", data[2], data[3], data[4]); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); + close_link(PROV_ERR_NVAL_FMT); } } static void send_confirm(void) { uint8_t *local_conf = NULL; - PROV_BUF(cfm, 17); + uint8_t conf_val_size = 0; + uint8_t rand_val_size = 0; + uint8_t conf_salt_size = 0; + uint8_t conf_key_size = 0; - BT_DBG("ConfInputs[0] %s", bt_hex(link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&link.conf_inputs[128], 17)); + conf_val_size = PROV_CONF_SIZE(&prov_link); + rand_val_size = PROV_RAND_SIZE(&prov_link); + conf_salt_size = PROV_CONF_SALT_SIZE(&prov_link); + conf_key_size = PROV_CONF_KEY_SIZE(&prov_link); - if (bt_mesh_prov_conf_salt(link.conf_inputs, link.conf_salt)) { - BT_ERR("Unable to generate confirmation salt"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; + ARG_UNUSED(conf_salt_size); + ARG_UNUSED(conf_key_size); + + PROV_BUF(cfm, (conf_val_size + 1)); + + BT_DBG("ConfInputs[0] %s", bt_hex(prov_link.conf_inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&prov_link.conf_inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&prov_link.conf_inputs[128], 17)); + + if (prov_link.algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf_salt(prov_link.conf_inputs, prov_link.conf_salt)) { + BT_ERR("Unable to generate confirmation salt"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } + + if (bt_mesh_prov_conf_key(prov_link.dhkey, prov_link.conf_salt, + prov_link.conf_key)) { + BT_ERR("Unable to generate confirmation key"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_salt_epa(prov_link.conf_inputs, prov_link.conf_salt)) { + BT_ERR("Unable to generate confirmation salt(epa)"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } - BT_DBG("ConfirmationSalt: %s", bt_hex(link.conf_salt, 16)); - - if (bt_mesh_prov_conf_key(link.dhkey, link.conf_salt, link.conf_key)) { - BT_ERR("Unable to generate confirmation key"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; + if (bt_mesh_prov_conf_key_epa(prov_link.dhkey, prov_link.auth, + prov_link.conf_salt, prov_link.conf_key)) { + BT_ERR("Unable to generate confirmation key(epa)"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } } +#endif - BT_DBG("ConfirmationKey: %s", bt_hex(link.conf_key, 16)); - - if (bt_mesh_rand(link.rand, 16)) { + if (bt_mesh_rand(prov_link.rand, rand_val_size)) { BT_ERR("Unable to generate random number"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return; } - BT_DBG("LocalRandom: %s", bt_hex(link.rand, 16)); + BT_DBG("ConfirmationSalt: %s", bt_hex(prov_link.conf_salt, conf_salt_size)); + BT_DBG("ConfirmationKey: %s", bt_hex(prov_link.conf_key, conf_key_size)); + BT_DBG("LocalRandom: %s", bt_hex(prov_link.rand, rand_val_size)); - prov_buf_init(&cfm, PROV_CONFIRM); + bt_mesh_prov_buf_init(&cfm, PROV_CONFIRM); - local_conf = net_buf_simple_add(&cfm, 16); + local_conf = net_buf_simple_add(&cfm, conf_val_size); - if (bt_mesh_prov_conf(link.conf_key, link.rand, link.auth, - local_conf)) { - BT_ERR("Unable to generate confirmation value"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; + if (prov_link.algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf(prov_link.conf_key, prov_link.rand, + prov_link.auth, local_conf)) { + BT_ERR("Unable to generate confirmation value"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_epa(prov_link.conf_key, prov_link.rand, + local_conf)) { + BT_ERR("Unable to generate confirmation value(epa)"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } + } +#endif - if (!memcmp(link.conf, local_conf, 16)) { + if (!memcmp(prov_link.conf, local_conf, conf_val_size)) { BT_ERR("Confirmation value is identical to ours, rejecting."); prov_send_fail_msg(PROV_ERR_NVAL_FMT); return; } - if (prov_send(&cfm)) { + if (bt_mesh_prov_send(&prov_link, &cfm)) { BT_ERR("Unable to send Provisioning Confirm"); return; } - link.expect = PROV_RANDOM; + prov_link.expect = PROV_RANDOM; } static void send_input_complete(void) { PROV_BUF(buf, 1); - prov_buf_init(&buf, PROV_INPUT_COMPLETE); - if (prov_send(&buf)) { + bt_mesh_prov_buf_init(&buf, PROV_INPUT_COMPLETE); + + if (bt_mesh_prov_send(&prov_link, &buf)) { BT_ERR("Failed to send Provisioning Input Complete"); } } int bt_mesh_input_number(uint32_t num) { + uint8_t auth_size = 0; + + auth_size = PROV_AUTH_SIZE(&prov_link); + BT_INFO("%u", num); - if (!bt_mesh_atomic_test_and_clear_bit(link.flags, WAIT_NUMBER)) { + if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_NUMBER)) { return -EINVAL; } - sys_put_be32(num, &link.auth[12]); + sys_put_be32(num, &prov_link.auth[auth_size - 4]); send_input_complete(); - if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { return 0; } - if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { + if (bt_mesh_atomic_test_and_clear_bit(prov_link.flags, SEND_CONFIRM)) { send_confirm(); } @@ -934,116 +590,113 @@ int bt_mesh_input_string(const char *str) { BT_INFO("%s", str); - if (!bt_mesh_atomic_test_and_clear_bit(link.flags, WAIT_STRING)) { + if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_STRING)) { return -EINVAL; } - (void)memcpy(link.auth, str, prov->input_size); + (void)memcpy(prov_link.auth, str, bt_mesh_prov_get()->input_size); send_input_complete(); - if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { return 0; } - if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { + if (bt_mesh_atomic_test_and_clear_bit(prov_link.flags, SEND_CONFIRM)) { send_confirm(); } return 0; } -static void prov_dh_key_cb(const uint8_t key[32], const uint8_t idx) -{ - BT_DBG("%p", key); - - if (!key) { - BT_ERR("DHKey generation failed"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; - } - - sys_memcpy_swap(link.dhkey, key, 32); - - BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32)); - - bt_mesh_atomic_set_bit(link.flags, HAVE_DHKEY); - - if (bt_mesh_atomic_test_bit(link.flags, WAIT_NUMBER) || - bt_mesh_atomic_test_bit(link.flags, WAIT_STRING)) { - return; - } - - if (bt_mesh_atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) { - send_confirm(); - } -} - static void send_pub_key(void) { - PROV_BUF(buf, 65); const uint8_t *key = NULL; + uint8_t dhkey[32] = {0}; + PROV_BUF(buf, 65); - /* Copy remote key in little-endian for bt_mesh_dh_key_gen(). + /* Copy remote key in little-endian for generating DHKey. * X and Y halves are swapped independently. Use response - * buffer as a temporary storage location. The validating of - * the remote public key is finished when it is received. + * buffer as a temporary storage location. The validating + * of the remote public key is finished when it is received. */ - sys_memcpy_swap(buf.data, &link.conf_inputs[17], 32); - sys_memcpy_swap(&buf.data[32], &link.conf_inputs[49], 32); + sys_memcpy_swap(buf.data, &prov_link.conf_inputs[17], 32); + sys_memcpy_swap(&buf.data[32], &prov_link.conf_inputs[49], 32); - if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { + if (bt_mesh_dh_key_gen(buf.data, dhkey)) { BT_ERR("Unable to generate DHKey"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return; } + sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + + BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); + + bt_mesh_atomic_set_bit(prov_link.flags, HAVE_DHKEY); + key = bt_mesh_pub_key_get(); if (!key) { BT_ERR("No public key available"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return; } BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - prov_buf_init(&buf, PROV_PUB_KEY); + bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); - memcpy(&link.conf_inputs[81], &buf.data[1], 64); + memcpy(&prov_link.conf_inputs[81], &buf.data[1], 64); - if (prov_send(&buf)) { + if (bt_mesh_prov_send(&prov_link, &buf)) { BT_ERR("Failed to send Public Key"); return; } - link.expect = PROV_CONFIRM; + prov_link.expect = PROV_CONFIRM; } static int bt_mesh_calc_dh_key(void) { - NET_BUF_SIMPLE_DEFINE(buf, 64); + uint8_t pub_key[64] = {0}; + uint8_t dhkey[32] = {0}; - /* Copy remote key in little-endian for bt_mesh_dh_key_gen(). + /* Copy remote key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - net_buf_simple_reset(&buf); - sys_memcpy_swap(buf.data, &link.conf_inputs[17], 32); - sys_memcpy_swap(&buf.data[32], &link.conf_inputs[49], 32); + sys_memcpy_swap(&pub_key[0], &prov_link.conf_inputs[17], 32); + sys_memcpy_swap(&pub_key[32], &prov_link.conf_inputs[49], 32); - if (bt_mesh_dh_key_gen(buf.data, prov_dh_key_cb, 0)) { + if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Unable to generate DHKey"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return -EIO; } + sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + + BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); + + bt_mesh_atomic_set_bit(prov_link.flags, HAVE_DHKEY); + + if (bt_mesh_atomic_test_bit(prov_link.flags, WAIT_NUMBER) || + bt_mesh_atomic_test_bit(prov_link.flags, WAIT_STRING)) { + return 0; + } + + if (bt_mesh_atomic_test_and_clear_bit(prov_link.flags, SEND_CONFIRM)) { + send_confirm(); + } + return 0; } -int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], const uint8_t pub_key_y[32], +int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], + const uint8_t pub_key_y[32], const uint8_t pri_key[32]) { if (!pub_key_x || !pub_key_y || !pri_key) { @@ -1055,14 +708,14 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], const uint8_t pub_key_y * X and Y halves are swapped independently. * And set input private key to mesh_bearer_adapt.c */ - sys_memcpy_swap(&link.conf_inputs[81], pub_key_x, 32); - sys_memcpy_swap(&link.conf_inputs[81] + 32, pub_key_y, 32); + sys_memcpy_swap(&prov_link.conf_inputs[81], pub_key_x, 32); + sys_memcpy_swap(&prov_link.conf_inputs[81] + 32, pub_key_y, 32); bt_mesh_set_private_key(pri_key); - bt_mesh_atomic_set_bit(link.flags, OOB_PUB_KEY); + bt_mesh_atomic_set_bit(prov_link.flags, OOB_PUB_KEY); /* If remote public key is not got, just return */ - if (!bt_mesh_atomic_test_bit(link.flags, REMOTE_PUB_KEY)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, REMOTE_PUB_KEY)) { return 0; } @@ -1081,47 +734,41 @@ static void prov_pub_key(const uint8_t *data) */ if (!bt_mesh_check_public_key(data)) { BT_ERR("Invalid public key"); - prov_send_fail_msg(PROV_ERR_UNEXP_PDU); + close_link(PROV_ERR_UNEXP_PDU); return; } - memcpy(&link.conf_inputs[17], data, 64); - bt_mesh_atomic_set_bit(link.flags, REMOTE_PUB_KEY); + memcpy(&prov_link.conf_inputs[17], data, 64); + bt_mesh_atomic_set_bit(prov_link.flags, REMOTE_PUB_KEY); - if (!bt_mesh_pub_key_get()) { - /* Clear retransmit timer */ -#if defined(CONFIG_BLE_MESH_PB_ADV) - prov_clear_tx(); -#endif - BT_WARN("Waiting for a local public key"); - return; - } - - if (!link.oob_pk_flag) { + if (prov_link.public_key == PROV_NO_OOB_PUB_KEY) { send_pub_key(); } else { - link.expect = PROV_CONFIRM; + prov_link.expect = PROV_CONFIRM; } } static void prov_input_complete(const uint8_t *data) -{ - BT_DBG("%s", __func__); -} +{} static void prov_confirm(const uint8_t *data) { - BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + uint8_t conf_val_size = 0; - memcpy(link.conf, data, 16); + conf_val_size = PROV_CONF_SIZE(&prov_link); - if (!bt_mesh_atomic_test_bit(link.flags, HAVE_DHKEY)) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - prov_clear_tx(); + BT_DBG("Remote Confirm: %s", bt_hex(data, conf_val_size)); + + memcpy(prov_link.conf, data, conf_val_size); + + if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_prov_clear_tx(&prov_link, true); #endif - bt_mesh_atomic_set_bit(link.flags, SEND_CONFIRM); + bt_mesh_atomic_set_bit(prov_link.flags, SEND_CONFIRM); /* If using OOB public key and it has already got, calculates dhkey */ - if (link.oob_pk_flag && bt_mesh_atomic_test_bit(link.flags, OOB_PUB_KEY)) { + if (prov_link.public_key == PROV_OOB_PUB_KEY && + bt_mesh_atomic_test_bit(prov_link.flags, OOB_PUB_KEY)) { bt_mesh_calc_dh_key(); } } else { @@ -1131,49 +778,77 @@ static void prov_confirm(const uint8_t *data) static void prov_random(const uint8_t *data) { - PROV_BUF(rnd, 17); - uint8_t conf_verify[16] = {0}; + uint8_t conf_verify[32] = {0}; + uint8_t rand_val_size = 0; + uint8_t conf_val_size = 0; - BT_DBG("Remote Random: %s", bt_hex(data, 16)); + rand_val_size = PROV_RAND_SIZE(&prov_link); + conf_val_size = PROV_CONF_SIZE(&prov_link); + PROV_BUF(rnd, rand_val_size); - if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) { - BT_ERR("Unable to calculate confirmation verification"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; + BT_INFO("Remote Random: %s", bt_hex(data, rand_val_size)); + + if (prov_link.algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf(prov_link.conf_key, data, prov_link.auth, conf_verify)) { + BT_ERR("Unable to calculate confirmation verification"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_epa(prov_link.conf_key, data, conf_verify)) { + BT_ERR("Unable to calculate confirmation verification"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } + } +#endif - if (memcmp(conf_verify, link.conf, 16)) { + if (memcmp(conf_verify, prov_link.conf, conf_val_size)) { BT_ERR("Invalid confirmation value"); - BT_DBG("Received: %s", bt_hex(link.conf, 16)); - BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); - prov_send_fail_msg(PROV_ERR_CFM_FAILED); + BT_ERR("Received: %s", bt_hex(prov_link.conf, conf_val_size)); + BT_ERR("Calculated: %s", bt_hex(conf_verify, conf_val_size)); + close_link(PROV_ERR_CFM_FAILED); return; } - prov_buf_init(&rnd, PROV_RANDOM); - net_buf_simple_add_mem(&rnd, link.rand, 16); + bt_mesh_prov_buf_init(&rnd, PROV_RANDOM); + net_buf_simple_add_mem(&rnd, prov_link.rand, rand_val_size); - if (prov_send(&rnd)) { + if (bt_mesh_prov_send(&prov_link, &rnd)) { BT_ERR("Failed to send Provisioning Random"); return; } - if (bt_mesh_prov_salt(link.conf_salt, data, link.rand, - link.prov_salt)) { - BT_ERR("Failed to generate provisioning salt"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; + if (prov_link.algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_salt(prov_link.conf_salt, data, prov_link.rand, + prov_link.prov_salt)) { + BT_ERR("Failed to generate provisioning salt"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_salt_epa(prov_link.conf_salt, data, prov_link.rand, + prov_link.prov_salt)) { + BT_ERR("Failed to generate provisioning salt"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } + } +#endif - BT_DBG("ProvisioningSalt: %s", bt_hex(link.prov_salt, 16)); + BT_DBG("ProvisioningSalt: %s", bt_hex(prov_link.prov_salt, 16)); - link.expect = PROV_DATA; + prov_link.expect = PROV_DATA; } static inline bool is_pb_gatt(void) { -#if defined(CONFIG_BLE_MESH_PB_GATT) - return !!link.conn; +#if CONFIG_BLE_MESH_PB_GATT + return !!prov_link.conn; #else return false; #endif @@ -1181,33 +856,31 @@ static inline bool is_pb_gatt(void) static void prov_data(const uint8_t *data) { - PROV_BUF(msg, 1); uint8_t session_key[16] = {0}; - uint8_t nonce[13] = {0}; - uint8_t dev_key[16] = {0}; - uint8_t pdu[25] = {0}; - uint8_t flags = 0U; - uint32_t iv_index = 0U; - uint16_t addr = 0U; - uint16_t net_idx = 0U; - int err = 0; bool identity_enable = false; + uint8_t dev_key[16] = {0}; + uint8_t nonce[13] = {0}; + uint32_t iv_index = 0U; + uint16_t net_idx = 0U; + uint8_t pdu[25] = {0}; + uint16_t addr = 0U; + uint8_t flags = 0U; + PROV_BUF(msg, 1); + int err = 0; - BT_DBG("%s", __func__); - - err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key); + err = bt_mesh_session_key(prov_link.dhkey, prov_link.prov_salt, session_key); if (err) { BT_ERR("Unable to generate session key"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return; } BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); - err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce); + err = bt_mesh_prov_nonce(prov_link.dhkey, prov_link.prov_salt, nonce); if (err) { BT_ERR("Unable to generate session nonce"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); + close_link(PROV_ERR_UNEXP_ERR); return; } @@ -1216,35 +889,69 @@ static void prov_data(const uint8_t *data) err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu); if (err) { BT_ERR("Unable to decrypt provisioning data"); - prov_send_fail_msg(PROV_ERR_DECRYPT); + close_link(PROV_ERR_DECRYPT); return; } - err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key); - if (err) { - BT_ERR("Unable to generate device key"); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; - } - - BT_DBG("DevKey: %s", bt_hex(dev_key, 16)); - net_idx = sys_get_be16(&pdu[16]); flags = pdu[18]; iv_index = sys_get_be32(&pdu[19]); addr = sys_get_be16(&pdu[23]); BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", - net_idx, iv_index, addr); + net_idx, iv_index, addr); - prov_buf_init(&msg, PROV_COMPLETE); - if (prov_send(&msg)) { +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_NPPI)) { + uint8_t reason = 0; + if (bt_mesh_rpr_srv_nppi_check(prov_link.pb_remote_nppi, pdu, net_idx, + iv_index, addr, &reason) == false) { + close_link(reason); + return; + } + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + + err = bt_mesh_dev_key(prov_link.dhkey, prov_link.prov_salt, dev_key); + if (err) { + BT_ERR("Unable to generate device key"); + close_link(PROV_ERR_UNEXP_ERR); + return; + } + + BT_DBG("DevKey: %s", bt_hex(dev_key, 16)); + +#if CONFIG_BLE_MESH_RPR_SRV + /* Store NPPI data */ + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_NPPI)) { + err = bt_mesh_rpr_srv_store_nppi_data(prov_link.pb_remote_uuid, + pdu, net_idx, flags, + iv_index, addr, dev_key); + if (err) { + close_link(PROV_ERR_UNEXP_ERR); + return; + } + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + + bt_mesh_prov_buf_init(&msg, PROV_COMPLETE); + + if (bt_mesh_prov_send(&prov_link, &msg)) { BT_ERR("Failed to send Provisioning Complete"); return; } /* Ignore any further PDUs on this link */ - link.expect = 0U; + prov_link.expect = 0U; + + reset_state(); + +#if CONFIG_BLE_MESH_RPR_SRV + /* For NPPI, no need to perform the following actions */ + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_NPPI)) { + return; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ /* Store info, since bt_mesh_provision() will end up clearing it */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { @@ -1268,82 +975,46 @@ static void prov_data(const uint8_t *data) } static void prov_complete(const uint8_t *data) -{ - BT_DBG("%s", __func__); -} +{} static void prov_failed(const uint8_t *data) { BT_WARN("Error: 0x%02x", data[0]); + +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + prov_link.pb_remote_cbd = true; + /* In this case, no need to send Link Close */ + prov_link.pb_remote_reset = true; + close_link(data[0]); + return; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ } static const struct { void (*func)(const uint8_t *data); - uint16_t len; + bool pb_remote; /* Indicate if the PDU could be received when PB-Remote is used */ } prov_handlers[] = { - { prov_invite, 1 }, - { prov_capabilities, 11 }, - { prov_start, 5, }, - { prov_pub_key, 64 }, - { prov_input_complete, 0 }, - { prov_confirm, 16 }, - { prov_random, 16 }, - { prov_data, 33 }, - { prov_complete, 0 }, - { prov_failed, 1 }, + { prov_invite, false }, + { prov_capabilities, true }, + { prov_start, false }, + { prov_pub_key, true }, + { prov_input_complete, true }, + { prov_confirm, true }, + { prov_random, true }, + { prov_data, false }, + { prov_complete, true }, + { prov_failed, true }, +#if CONFIG_BLE_MESH_CERT_BASED_PROV + { bt_mesh_prov_record_req, false }, + { bt_mesh_prov_record_rsp, false }, + { bt_mesh_prov_records_get, false }, + { bt_mesh_prov_records_list, false }, +#endif }; -#if defined(CONFIG_BLE_MESH_PB_ADV) -static void prov_retransmit(struct k_work *work) -{ - int64_t timeout = TRANSACTION_TIMEOUT; - int i; - - BT_DBG("%s", __func__); - - if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { - BT_WARN("Link not active"); - return; - } - -#if defined(CONFIG_BLE_MESH_FAST_PROV) - /* When Provisioning Failed PDU is sent, 3s may be used here. */ - if (link.tx_pdu_type >= PROV_COMPLETE) { - timeout = K_SECONDS(30); - } -#endif - if (k_uptime_get() - link.tx.start > timeout) { - BT_WARN("Node timeout, giving up transaction"); - reset_adv_link(); - return; - } - - bt_mesh_pb_buf_lock(); - - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (BLE_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - - } - - bt_mesh_pb_buf_unlock(); -} - +#if CONFIG_BLE_MESH_PB_ADV static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) { BT_DBG("len %u", buf->len); @@ -1353,52 +1024,93 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) return; } - if (bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE)) { /* Send another link ack if the provisioner missed the last */ - if (link.id == rx->link_id && link.expect == PROV_INVITE) { + if (prov_link.link_id == rx->link_id && prov_link.expect == PROV_INVITE) { BT_DBG("Resending link ack"); - bearer_ctl_send(LINK_ACK, NULL, 0); + bt_mesh_prov_bearer_ctl_send(&prov_link, LINK_ACK, NULL, 0); } else { BT_INFO("Ignoring bearer open: link already active"); } - return; } - if (memcmp(buf->data, prov->uuid, 16)) { + if (memcmp(buf->data, bt_mesh_prov_get()->uuid, 16)) { BT_DBG("Bearer open message not for us"); return; } - if (prov->link_open) { - prov->link_open(BLE_MESH_PROV_ADV); + if (bt_mesh_prov_get()->link_open) { + bt_mesh_prov_get()->link_open(BLE_MESH_PROV_ADV); } - link.id = rx->link_id; - bt_mesh_atomic_set_bit(link.flags, LINK_ACTIVE); - net_buf_simple_reset(link.rx.buf); + prov_link.link_id = rx->link_id; -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) + bt_mesh_atomic_set_bit(prov_link.flags, LINK_ACTIVE); + + net_buf_simple_reset(prov_link.rx.buf); + +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Add the link id into exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link.id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &prov_link.link_id); #endif - bearer_ctl_send(LINK_ACK, NULL, 0); + bt_mesh_prov_bearer_ctl_send(&prov_link, LINK_ACK, NULL, 0); - link.expect = PROV_INVITE; +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(bt_mesh_prov_get()->oob_info)) { + prov_link.expect = PROV_REC_EXP; + } else +#endif + { + prov_link.expect = PROV_INVITE; + } } static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf) { BT_DBG("len %u", buf->len); + +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + if (bt_mesh_atomic_test_and_clear_bit(prov_link.flags, PBR_OPENING)) { + BT_INFO("PB-Remote, receive Link ACK"); + /* Cancel the retransmit timer, in case timeout is caused. */ + bt_mesh_prov_clear_tx(&prov_link, true); + bt_mesh_rpr_srv_recv_link_ack(prov_link.pb_remote_uuid, true); + } else { + BT_INFO("Link ACK for PB-Remote already received"); + } + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ } static void link_close(struct prov_rx *rx, struct net_buf_simple *buf) { + uint8_t reason = 0; + BT_DBG("len %u", buf->len); - reset_adv_link(); + if (buf->len != 1) { + BT_ERR("Invalid Link Close length %d", buf->len); + return; + } + + reason = net_buf_simple_pull_u8(buf); + +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + prov_link.pb_remote_cbd = true; + /* In this case, no need to send Link Close */ + prov_link.pb_remote_reset = true; + close_link(reason); + return; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + + reset_adv_link(&prov_link, reason); } static void gen_prov_ctl(struct prov_rx *rx, struct net_buf_simple *buf) @@ -1407,22 +1119,31 @@ static void gen_prov_ctl(struct prov_rx *rx, struct net_buf_simple *buf) switch (BEARER_CTL(rx->gpc)) { case LINK_OPEN: +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + return; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + link_open(rx, buf); break; + case LINK_ACK: - if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE)) { return; } link_ack(rx, buf); break; + case LINK_CLOSE: - if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE)) { return; } link_close(rx, buf); break; + default: BT_ERR("Unknown bearer opcode: 0x%02x", BEARER_CTL(rx->gpc)); return; @@ -1431,24 +1152,31 @@ static void gen_prov_ctl(struct prov_rx *rx, struct net_buf_simple *buf) static void prov_msg_recv(void) { - uint8_t type = link.rx.buf->data[0]; + uint8_t err_code = 0; + uint8_t type = 0; - BT_DBG("type 0x%02x len %u", type, link.rx.buf->len); + if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_INVALID)) { + BT_WARN("Unexpected msg 0x%02x on invalidated link", type); + close_link(PROV_ERR_UNEXP_PDU); + return; + } - if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { + /* When Link Close is being sent, any received Provisioning PDU + * should be ignored. + */ + if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_CLOSING)) { + BT_WARN("Link is closing, unexpected msg 0x%02x", type); + return; + } + + if (!bt_mesh_fcs_check(prov_link.rx.buf, prov_link.rx.fcs)) { BT_ERR("Incorrect FCS"); return; } - gen_prov_ack_send(link.rx.id); - link.rx.prev_id = link.rx.id; - link.rx.id = 0U; + type = net_buf_simple_pull_u8(prov_link.rx.buf); - if (bt_mesh_atomic_test_bit(link.flags, LINK_INVALID)) { - BT_WARN("Unexpected msg 0x%02x on invalidated link", type); - prov_send_fail_msg(PROV_ERR_UNEXP_PDU); - return; - } + BT_DBG("type 0x%02x len %u", type, prov_link.rx.buf->len); /* For case MESH/NODE/PROV/BI-15-C, when the node receive a Provisioning PDU * with the Type field set to the lowest unsupported or RFU value, it sends a @@ -1460,141 +1188,109 @@ static void prov_msg_recv(void) return; } - if (type != PROV_FAILED && type != link.expect) { - BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect); - prov_send_fail_msg(PROV_ERR_UNEXP_PDU); - return; - } - - if (1 + prov_handlers[type].len != link.rx.buf->len) { - BT_ERR("Invalid length %u for type 0x%02x", - link.rx.buf->len, type); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); - return; - } - - /* Changed by Espressif, add provisioning timeout timer operations. - * When received a provisioning PDU, restart the 60s timer. - */ - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - prov_handlers[type].func(&link.rx.buf->data[1]); -} - -static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) -{ - uint8_t seg = CONT_SEG_INDEX(rx->gpc); - - BT_DBG("len %u, seg_index %u", buf->len, seg); - - if (!link.rx.seg && link.rx.prev_id == rx->xact_id) { - BT_INFO("Resending ack"); - gen_prov_ack_send(rx->xact_id); - return; - } - - if (rx->xact_id != link.rx.id) { - BT_WARN("Data for unknown transaction (%u != %u)", - rx->xact_id, link.rx.id); - return; - } - - if (seg > link.rx.last_seg) { - BT_ERR("Invalid segment index %u", seg); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); - return; - } else if (seg == link.rx.last_seg) { - uint8_t expect_len = 0U; - - expect_len = (link.rx.buf->len - 20U - - ((link.rx.last_seg - 1) * 23U)); - if (expect_len != buf->len) { - BT_ERR("Incorrect last seg len: %u != %u", - expect_len, buf->len); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); + if (type != PROV_FAILED && type != prov_link.expect) { +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (prov_link.expect == PROV_REC_EXP && + (type == PROV_INVITE || type == PROV_REC_GET || type == PROV_REC_REQ)) { + if (prov_link.invite_recv) { + BT_ERR("%s, Provisioning invite PDU already received", __func__); + close_link(PROV_ERR_UNEXP_PDU); + return; + } + } else +#endif + { + BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, prov_link.expect); + close_link(PROV_ERR_UNEXP_PDU); return; } } - if (!(link.rx.seg & BIT(seg))) { - BT_INFO("Ignoring already received segment"); + if (!bt_mesh_prov_pdu_check(type, prov_link.rx.buf->len, &err_code)) { + close_link(err_code); return; } - memcpy(XACT_SEG_DATA(seg), buf->data, buf->len); - XACT_SEG_RECV(seg); + bt_mesh_gen_prov_ack_send(&prov_link, prov_link.rx.id); + prov_link.rx.prev_id = prov_link.rx.id; + prov_link.rx.id = 0U; - if (!link.rx.seg) { - prov_msg_recv(); + k_delayed_work_submit(&prov_link.prot_timer, PROTOCOL_TIMEOUT); + +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + if (prov_handlers[type].pb_remote) { + BT_INFO("PB-Remote, receive prov pdu 0x%02x", type); + /* Note: + * Provisioning implementation should make sure that + * no duplicate provisioning pdu is received by the + * Remote Provisioning Server. + */ + bt_mesh_rpr_srv_send_pdu_report(prov_link.pb_remote_uuid, type, + prov_link.rx.buf); + } + return; } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + + prov_handlers[type].func(prov_link.rx.buf->data); +} + +static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) +{ + bool close = false; + + if (!bt_mesh_gen_prov_cont(&prov_link, buf, rx, &close)) { + if (close) { + close_link(PROV_ERR_NVAL_FMT); + } + return; + } + + prov_msg_recv(); } static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) { BT_DBG("len %u", buf->len); - if (!link.tx.buf[0]) { + if (!prov_link.tx.buf[0]) { return; } - if (rx->xact_id == link.tx.id) { - prov_clear_tx(); +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + if (prov_link.tx.id == 0) { + return; + } + + if (rx->xact_id == prov_link.tx.id - 1) { + bt_mesh_prov_clear_tx(&prov_link, true); + + BT_INFO("PB-Remote, receive Transaction ACK"); + bt_mesh_rpr_srv_send_outbound_report(prov_link.pb_remote_uuid, true); + } + return; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + + if (rx->xact_id == prov_link.tx.id) { + bt_mesh_prov_clear_tx(&prov_link, true); } } static void gen_prov_start(struct prov_rx *rx, struct net_buf_simple *buf) { - if (link.rx.seg) { - BT_INFO("Got Start while there are unreceived segments"); + bool close = false; + + if (!bt_mesh_gen_prov_start(&prov_link, buf, rx, &close)) { + if (close) { + close_link(PROV_ERR_NVAL_FMT); + } return; } - if (link.rx.prev_id == rx->xact_id) { - BT_INFO("Resending ack"); - gen_prov_ack_send(rx->xact_id); - return; - } - - link.rx.buf->len = net_buf_simple_pull_be16(buf); - link.rx.id = rx->xact_id; - link.rx.fcs = net_buf_simple_pull_u8(buf); - - BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, - START_LAST_SEG(rx->gpc), link.rx.buf->len, link.rx.fcs); - - if (link.rx.buf->len < 1) { - BT_ERR("Ignoring zero-length provisioning PDU"); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); - return; - } - - if (START_LAST_SEG(rx->gpc) > START_LAST_SEG_MAX) { - BT_ERR("Invalid SegN 0x%02x", START_LAST_SEG(rx->gpc)); - prov_send_fail_msg(PROV_ERR_UNEXP_ERR); - return; - } - - if (link.rx.buf->len > link.rx.buf->size) { - BT_ERR("Too large provisioning PDU (%u bytes)", - link.rx.buf->len); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); - return; - } - - if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->len <= 20U) { - BT_ERR("Too small total length for multi-segment PDU"); - prov_send_fail_msg(PROV_ERR_NVAL_FMT); - return; - } - - link.rx.seg = (1 << (START_LAST_SEG(rx->gpc) + 1)) - 1; - link.rx.last_seg = START_LAST_SEG(rx->gpc); - memcpy(link.rx.buf->data, buf->data, buf->len); - XACT_SEG_RECV(0); - - if (!link.rx.seg) { - prov_msg_recv(); - } + prov_msg_recv(); } static const struct { @@ -1602,10 +1298,10 @@ static const struct { bool require_link; uint8_t min_len; } gen_prov[] = { - { gen_prov_start, true, 3 }, - { gen_prov_ack, true, 0 }, - { gen_prov_cont, true, 0 }, - { gen_prov_ctl, false, 0 }, + { gen_prov_start, true, 3 }, + { gen_prov_ack, true, 0 }, + { gen_prov_cont, true, 0 }, + { gen_prov_ctl, false, 0 }, }; static void gen_prov_recv(struct prov_rx *rx, struct net_buf_simple *buf) @@ -1615,8 +1311,8 @@ static void gen_prov_recv(struct prov_rx *rx, struct net_buf_simple *buf) return; } - if (!bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE) && - gen_prov[GPCF(rx->gpc)].require_link) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE) && + gen_prov[GPCF(rx->gpc)].require_link) { BT_DBG("Ignoring message that requires active link"); return; } @@ -1628,7 +1324,8 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) { struct prov_rx rx = {0}; - if (!bt_prov_active() && bt_mesh_is_provisioned()) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE) && + bt_mesh_is_provisioned()) { BT_DBG("Ignoring provisioning PDU - already provisioned"); return; } @@ -1644,7 +1341,8 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); - if (bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE) && link.id != rx.link_id) { + if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE) && + prov_link.link_id != rx.link_id) { BT_DBG("Ignoring mesh beacon for unknown link"); return; } @@ -1653,14 +1351,15 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) } #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) { + uint8_t err_code = 0U; uint8_t type = 0U; BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - if (link.conn != conn) { + if (prov_link.conn != conn) { BT_WARN("Data for unexpected connection"); return -ENOTCONN; } @@ -1674,7 +1373,7 @@ int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) * a Provisioning PDU , it will send a Provisioning Failed PDU with the Error Code * field set to Unexpected PDU(0x03). */ - if (bt_mesh_atomic_test_bit(link.flags, LINK_INVALID)) { + if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_INVALID)) { BT_WARN("Unexpected msg 0x%02x on invalid link", type); prov_send_fail_msg(PROV_ERR_UNEXP_PDU); return -EINVAL; @@ -1691,21 +1390,46 @@ int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) return -EINVAL; } - if (type != PROV_FAILED && type != link.expect) { - BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect); - prov_send_fail_msg(PROV_ERR_UNEXP_PDU); + if (type != PROV_FAILED && type != prov_link.expect) { +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (prov_link.expect == PROV_REC_EXP && + (type == PROV_INVITE || type == PROV_REC_GET || type == PROV_REC_REQ)) { + if (prov_link.invite_recv) { + BT_ERR("%s, Provisioning invite PDU already received", __func__); + close_link(PROV_ERR_UNEXP_PDU); + return -EINVAL; + } + } else +#endif + { + BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, prov_link.expect); + close_link(PROV_ERR_UNEXP_PDU); + return -EINVAL; + } + } + + if (!bt_mesh_prov_pdu_check(type, buf->len, &err_code)) { + close_link(err_code); return -EINVAL; } - if (prov_handlers[type].len != buf->len) { - BT_ERR("Invalid length %u for type 0x%02x", buf->len, type); - return -EINVAL; - } + k_delayed_work_submit(&prov_link.prot_timer, PROTOCOL_TIMEOUT); - /* Changed by Espressif, add provisioning timeout timer operations. - * When received a provisioning PDU, restart the 60s timer. - */ - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + if (prov_handlers[type].pb_remote) { + BT_INFO("PB-Remote, receive prov pdu 0x%02x by GATT %s", + type, bt_hex(buf->data, buf->len)); + /* Note: + * Provisioning implementation should make sure that + * no duplicate provisioning pdu is received by the + * Remote Provisioning Server. + */ + bt_mesh_rpr_srv_send_pdu_report(prov_link.pb_remote_uuid, type, buf); + } + return 0; + } +#endif /* CONFIG_BLE_MESH_RPR_SRV */ prov_handlers[type].func(buf->data); @@ -1716,31 +1440,49 @@ int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) { BT_DBG("conn %p", conn); - if (bt_mesh_atomic_test_and_set_bit(link.flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE) && + bt_mesh_atomic_test_and_set_bit(prov_link.flags, LINK_ACTIVE)) { + BT_ERR("Link is busy"); return -EBUSY; } - link.conn = bt_mesh_conn_ref(conn); - link.expect = PROV_INVITE; + prov_link.conn = bt_mesh_conn_ref(conn); - if (prov->link_open) { - prov->link_open(BLE_MESH_PROV_GATT); +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(bt_mesh_prov_get()->oob_info)) { + prov_link.expect = PROV_REC_EXP; + } else +#endif + { + prov_link.expect = PROV_INVITE; + } + + if (bt_mesh_prov_get()->link_open) { + bt_mesh_prov_get()->link_open(BLE_MESH_PROV_GATT); } return 0; } -int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn) +int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason) { BT_DBG("conn %p", conn); - if (link.conn != conn) { + if (prov_link.conn != conn) { BT_ERR("Not connected"); return -ENOTCONN; } - if (prov->link_close) { - prov->link_close(BLE_MESH_PROV_GATT); +#if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + prov_link.pb_remote_cbd = true; + prov_link.pb_remote_reset = true; + prov_link.pb_remote_close(&prov_link, reason); + } +#endif + + if (bt_mesh_prov_get()->link_close) { + bt_mesh_prov_get()->link_close(BLE_MESH_PROV_GATT, reason); } reset_state(); @@ -1749,106 +1491,114 @@ int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn) } #endif /* CONFIG_BLE_MESH_PB_GATT */ -const struct bt_mesh_prov *bt_mesh_prov_get(void) +bool bt_mesh_prov_active(void) { - return prov; -} - -bool bt_prov_active(void) -{ - return bt_mesh_atomic_test_bit(link.flags, LINK_ACTIVE); + return bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE); } static void protocol_timeout(struct k_work *work) { BT_WARN("Protocol timeout"); -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (link.conn) { - bt_mesh_pb_gatt_close(link.conn); +#if CONFIG_BLE_MESH_PB_GATT + if (prov_link.conn) { +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT && CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { + prov_link.pb_remote_reset = true; + bt_mesh_gattc_disconnect(prov_link.conn); + return; + } +#endif + bt_mesh_pb_gatt_close(prov_link.conn, CLOSE_REASON_TIMEOUT); return; } -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ -#if defined(CONFIG_BLE_MESH_PB_ADV) +#if CONFIG_BLE_MESH_PB_ADV uint8_t reason = CLOSE_REASON_TIMEOUT; - - link.rx.seg = 0U; - bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason)); - - reset_state(); -#endif + prov_link.rx.seg = 0U; + bt_mesh_prov_bearer_ctl_send(&prov_link, LINK_CLOSE, &reason, sizeof(reason)); +#endif /* CONFIG_BLE_MESH_PB_ADV */ } -int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info) +int bt_mesh_prov_init(void) { const uint8_t *key = NULL; - if (!prov_info) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } - if (prov_info->static_val_len > BLE_MESH_PROV_STATIC_OOB_MAX_LEN || - prov_info->output_size > BLE_MESH_PROV_OUTPUT_OOB_MAX_LEN || - prov_info->input_size > BLE_MESH_PROV_INPUT_OOB_MAX_LEN) { + if (bt_mesh_prov_get()->static_val_len > BLE_MESH_PROV_STATIC_OOB_MAX_LEN || + bt_mesh_prov_get()->output_size > BLE_MESH_PROV_OUTPUT_OOB_MAX_LEN || + bt_mesh_prov_get()->input_size > BLE_MESH_PROV_INPUT_OOB_MAX_LEN) { BT_ERR("Invalid authentication oob length"); return -EINVAL; } - __ASSERT(prov_info->uuid, "Device UUID not initialized"); + __ASSERT(bt_mesh_prov_get()->uuid, "Device UUID not initialized"); - /* Changed by Espressif. Use micro-ecc to generate public key now. */ key = bt_mesh_pub_key_get(); if (!key) { BT_ERR("Failed to generate public key"); return -EIO; } - k_delayed_work_init(&link.prot_timer, protocol_timeout); + k_delayed_work_init(&prov_link.prot_timer, protocol_timeout); - prov = prov_info; - -#if defined(CONFIG_BLE_MESH_PB_ADV) - k_delayed_work_init(&link.tx.retransmit, prov_retransmit); +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_prov_retransmit_init(&prov_link); #endif reset_state(); -#if defined(CONFIG_BLE_MESH_PB_ADV) - bt_mesh_pb_buf_mutex_new(); +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_mutex_create(&prov_link.buf_lock); #endif +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(bt_mesh_prov_get()->oob_info)) { + int err = bt_mesh_node_cert_based_prov_init(); + if (err) { + BT_ERR("Loading provisioning records failed!"); + return err; + } + } +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + return 0; } #if CONFIG_BLE_MESH_DEINIT int bt_mesh_prov_deinit(void) { - if (prov == NULL) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } - k_delayed_work_free(&link.prot_timer); + k_delayed_work_free(&prov_link.prot_timer); -#if defined(CONFIG_BLE_MESH_PB_ADV) - prov_clear_tx(); - k_delayed_work_free(&link.tx.retransmit); -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_prov_clear_tx(&prov_link, true); + k_delayed_work_free(&prov_link.tx.retransmit); +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Remove the link id from exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link.id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &prov_link.link_id); #endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ + bt_mesh_mutex_free(&prov_link.buf_lock); #endif /* CONFIG_BLE_MESH_PB_ADV */ - (void)memset(&link, 0, sizeof(link)); +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(bt_mesh_prov_get()->oob_info)) { + bt_mesh_node_cert_based_prov_deinit(); + } +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ -#if defined(CONFIG_BLE_MESH_PB_ADV) - bt_mesh_pb_buf_mutex_free(); -#endif - - prov = NULL; + (void)memset(&prov_link, 0, sizeof(prov_link)); return 0; } @@ -1857,16 +1607,46 @@ int bt_mesh_prov_deinit(void) void bt_mesh_prov_complete(uint16_t net_idx, const uint8_t net_key[16], uint16_t addr, uint8_t flags, uint32_t iv_index) { - if (prov->complete) { - prov->complete(net_idx, net_key, addr, flags, iv_index); + if (bt_mesh_prov_get()->complete) { + bt_mesh_prov_get()->complete(net_idx, net_key, addr, flags, iv_index); } } void bt_mesh_prov_reset(void) { - if (prov->reset) { - prov->reset(); + if (bt_mesh_prov_get()->reset) { + bt_mesh_prov_get()->reset(); } } +#if CONFIG_BLE_MESH_RPR_SRV +void bt_mesh_rpr_srv_reset_prov_link(struct bt_mesh_prov_link *link, uint8_t reason) +{ +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN + /* Remove the link id from exceptional list */ + bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &link->link_id); +#endif + + reset_state(); +} + +int bt_mesh_rpr_srv_nppi_pdu_recv(uint8_t type, const uint8_t *data) +{ + if (!bt_mesh_atomic_test_bit(prov_link.flags, PB_NPPI)) { + BT_ERR("Not a NPPI provisioning link"); + return -EINVAL; + } + + if (type != prov_link.expect) { + BT_ERR("NPPI, unexpected msg 0x%02x != 0x%02x", type, prov_link.expect); + return -EINVAL; + } + + prov_handlers[type].func(data); + return 0; +} +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + #endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/esp_ble_mesh/core/prov_node.h b/components/bt/esp_ble_mesh/core/prov_node.h index e71c12de5b..b548e730b2 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.h +++ b/components/bt/esp_ble_mesh/core/prov_node.h @@ -18,24 +18,28 @@ extern "C" { void bt_mesh_pb_adv_recv(struct net_buf_simple *buf); -bool bt_prov_active(void); +bool bt_mesh_prov_active(void); int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn); -int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn); +int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason); int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf); int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], const uint8_t pub_key_y[32], const uint8_t pri_key[32]); -const struct bt_mesh_prov *bt_mesh_prov_get(void); - -int bt_mesh_prov_init(const struct bt_mesh_prov *prov); +int bt_mesh_prov_init(void); int bt_mesh_prov_deinit(void); void bt_mesh_prov_complete(uint16_t net_idx, const uint8_t net_key[16], uint16_t addr, uint8_t flags, uint32_t iv_index); void bt_mesh_prov_reset(void); +struct bt_mesh_prov_link *bt_mesh_prov_node_get_link(void); + +void bt_mesh_rpr_srv_reset_prov_link(struct bt_mesh_prov_link *link, uint8_t reason); + +int bt_mesh_rpr_srv_nppi_pdu_recv(uint8_t type, const uint8_t *data); + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index e194deb50c..ef547613d3 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -15,197 +15,33 @@ #include "settings.h" #include "fast_prov.h" #include "mesh/common.h" +#include "proxy_common.h" #include "proxy_client.h" +#include "prov_common.h" +#include "prov_node.h" #include "prov_pvnr.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + #if CONFIG_BLE_MESH_PROVISIONER _Static_assert(BLE_MESH_MAX_CONN >= CONFIG_BLE_MESH_PBG_SAME_TIME, "Too large BLE Mesh PB-GATT count"); -/* 3 transmissions, 20ms interval */ -#define PROV_XMIT BLE_MESH_TRANSMIT(2, 20) +/* Number of devices can be provisioned at the same time equals to PB-ADV + PB-GATT */ +#define BLE_MESH_PROV_SAME_TIME \ + (CONFIG_BLE_MESH_PBA_SAME_TIME + CONFIG_BLE_MESH_PBG_SAME_TIME) -#define AUTH_METHOD_NO_OOB 0x00 -#define AUTH_METHOD_STATIC 0x01 -#define AUTH_METHOD_OUTPUT 0x02 -#define AUTH_METHOD_INPUT 0x03 +#define UNICAST_ADDR_LIMIT 0x7FFF -#define OUTPUT_OOB_BLINK 0x00 -#define OUTPUT_OOB_BEEP 0x01 -#define OUTPUT_OOB_VIBRATE 0x02 -#define OUTPUT_OOB_NUMBER 0x03 -#define OUTPUT_OOB_STRING 0x04 - -#define INPUT_OOB_PUSH 0x00 -#define INPUT_OOB_TWIST 0x01 -#define INPUT_OOB_NUMBER 0x02 -#define INPUT_OOB_STRING 0x03 - -#define PROV_ERR_NONE 0x00 -#define PROV_ERR_NVAL_PDU 0x01 -#define PROV_ERR_NVAL_FMT 0x02 -#define PROV_ERR_UNEXP_PDU 0x03 -#define PROV_ERR_CFM_FAILED 0x04 -#define PROV_ERR_RESOURCES 0x05 -#define PROV_ERR_DECRYPT 0x06 -#define PROV_ERR_UNEXP_ERR 0x07 -#define PROV_ERR_ADDR 0x08 - -#define PROV_INVITE 0x00 -#define PROV_CAPABILITIES 0x01 -#define PROV_START 0x02 -#define PROV_PUB_KEY 0x03 -#define PROV_INPUT_COMPLETE 0x04 -#define PROV_CONFIRM 0x05 -#define PROV_RANDOM 0x06 -#define PROV_DATA 0x07 -#define PROV_COMPLETE 0x08 -#define PROV_FAILED 0x09 - -#define PROV_ALG_P256 0x00 - -#define GPCF(gpc) (gpc & 0x03) -#define GPC_START(last_seg) (((last_seg) << 2) | 0x00) -#define GPC_ACK 0x01 -#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02) -#define GPC_CTL(op) (((op) << 2) | 0x03) - -#define START_PAYLOAD_MAX 20 -#define CONT_PAYLOAD_MAX 23 -#define START_LAST_SEG_MAX 2 - -#define START_LAST_SEG(gpc) (gpc >> 2) -#define CONT_SEG_INDEX(gpc) (gpc >> 2) - -#define BEARER_CTL(gpc) (gpc >> 2) -#define LINK_OPEN 0x00 -#define LINK_ACK 0x01 -#define LINK_CLOSE 0x02 - -#define CLOSE_REASON_SUCCESS 0x00 -#define CLOSE_REASON_TIMEOUT 0x01 -#define CLOSE_REASON_FAILED 0x02 - -#define PROV_AUTH_VAL_SIZE 0x10 -#define PROV_CONF_SALT_SIZE 0x10 -#define PROV_CONF_KEY_SIZE 0x10 -#define PROV_DH_KEY_SIZE 0x20 -#define PROV_CONFIRM_SIZE 0x10 -#define PROV_RANDOM_SIZE 0x10 -#define PROV_PROV_SALT_SIZE 0x10 -#define PROV_CONF_INPUTS_SIZE 0x91 - -#define XACT_SEG_DATA(_idx, _seg) (&link[_idx].rx.buf->data[20 + ((_seg - 1) * 23)]) -#define XACT_SEG_RECV(_idx, _seg) (link[_idx].rx.seg &= ~(1 << (_seg))) - -#define XACT_NVAL 0xff - -enum { - REMOTE_PUB_KEY, /* Remote key has been received */ - LOCAL_PUB_KEY, /* Local public key is available */ - LINK_ACTIVE, /* Link has been opened */ - WAIT_GEN_DHKEY, /* Waiting for remote public key to generate DHKey */ - HAVE_DHKEY, /* DHKey has been calculated */ - SEND_CONFIRM, /* Waiting to send Confirm value */ - WAIT_NUMBER, /* Waiting for number input from user */ - WAIT_STRING, /* Waiting for string input from user */ - TIMEOUT_START, /* Provision timeout timer has started */ - NUM_FLAGS, -}; - -/** Provisioner link structure allocation +/* Provisioner link structure allocation * |--------------------------------------------------------| * | Link(PB-ADV) | Link(PB-GATT) | * |--------------------------------------------------------| * |<----------------------Total Link---------------------->| */ -struct prov_link { - BLE_MESH_ATOMIC_DEFINE(flags, NUM_FLAGS); - uint8_t uuid[16]; /* check if device is being provisioned*/ - uint16_t oob_info; /* oob info of this device */ - uint8_t element_num; /* element num of device */ - uint8_t ki_flags; /* Key refresh flag and iv update flag */ - uint32_t iv_index; /* IV Index */ - uint8_t auth_method; /* Choosen authentication method */ - uint8_t auth_action; /* Choosen authentication action */ - uint8_t auth_size; /* Choosen authentication size */ - uint16_t assign_addr; /* Application assigned address for the device */ - uint16_t unicast_addr; /* unicast address allocated for device */ - bt_mesh_addr_t addr; /* Device address */ -#if defined(CONFIG_BLE_MESH_PB_GATT) - bool connecting; /* start connecting with device */ - struct bt_mesh_conn *conn; /* GATT connection */ -#endif - uint8_t expect; /* Next expected PDU */ - - uint8_t *dhkey; /* Calculated DHKey */ - uint8_t *auth; /* Authentication Value */ - - uint8_t *conf_salt; /* ConfirmationSalt */ - uint8_t *conf_key; /* ConfirmationKey */ - uint8_t *conf_inputs; /* ConfirmationInputs */ - - uint8_t *rand; /* Local Random */ - uint8_t *conf; /* Remote Confirmation */ - uint8_t *local_conf; /* Local Confirmation */ - - uint8_t *prov_salt; /* Provisioning Salt */ - -#if defined(CONFIG_BLE_MESH_PB_ADV) - bool linking; /* Linking is being establishing */ - uint16_t send_link_close; /* Link close is being sent flag */ - uint32_t link_id; /* Link ID */ - uint8_t pending_ack; /* Decide which transaction id ack is pending */ - uint8_t expect_ack_for; /* Transaction ACK expected for provisioning pdu */ - uint8_t tx_pdu_type; /* The current transmitted Provisioning PDU type */ - - struct { - uint8_t trans_id; /* Transaction ID */ - uint8_t prev_id; /* Previous Transaction ID */ - uint8_t seg; /* Bit-field of unreceived segments */ - uint8_t last_seg; /* Last segment (to check length) */ - uint8_t fcs; /* Expected FCS value */ - uint8_t adv_buf_id; /* index of buf allocated in adv_buf_data */ - struct net_buf_simple *buf; - } rx; - - struct { - /* Start timestamp of the transaction */ - int64_t start; - - /* Transaction id*/ - uint8_t trans_id; - - /* Pending outgoing buffer(s) */ - struct net_buf *buf[3]; - - /* Retransmit timer */ - struct k_delayed_work retransmit; - } tx; -#endif - - /** Provision timeout timer. Spec P259 says: The provisioning protocol - * shall have a minimum timeout of 60 seconds that is reset each time - * a provisioning protocol PDU is sent or received. - */ - struct k_delayed_work timeout; -}; - -/* Number of devices can be provisioned at the same time equals to PB-ADV + PB-GATT */ -#define BLE_MESH_PROV_SAME_TIME \ - (CONFIG_BLE_MESH_PBA_SAME_TIME + CONFIG_BLE_MESH_PBG_SAME_TIME) - -#define PROV_MAX_ADDR_TO_ASSIGN 0x7FFF - -static struct prov_link link[BLE_MESH_PROV_SAME_TIME]; - -struct prov_rx { - uint32_t link_id; - uint8_t xact_id; - uint8_t gpc; -}; +static struct bt_mesh_prov_link prov_links[BLE_MESH_PROV_SAME_TIME]; struct bt_mesh_prov_ctx { /* Primary element address of Provisioner */ @@ -214,29 +50,27 @@ struct bt_mesh_prov_ctx { /* Provisioning bearers used by Provisioner */ bt_mesh_prov_bearer_t bearers; +#if CONFIG_BLE_MESH_PB_ADV /* Current number of PB-ADV provisioned devices simultaneously */ uint8_t pba_count; +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#if CONFIG_BLE_MESH_PB_GATT /* Current number of PB-GATT provisioned devices simultaneously */ uint8_t pbg_count; +#endif /* CONFIG_BLE_MESH_PB_GATT */ /* Current unicast address going to allocated */ - uint16_t curr_alloc_addr; + uint16_t alloc_addr; /* Current net_idx going to be used in provisioning data */ - uint16_t curr_net_idx; - - /* Current flags going to be used in provisioning data */ - uint8_t curr_flags; - - /* Current iv_index going to be used in provisioning data */ - uint16_t curr_iv_index; + uint16_t net_idx; /* Length of Static OOB value */ uint8_t static_oob_len; /* Static OOB value */ - uint8_t static_oob_val[16]; + uint8_t static_oob_val[32]; /* Offset of the device uuid to be matched, based on zero */ uint8_t match_offset; @@ -248,27 +82,22 @@ struct bt_mesh_prov_ctx { uint8_t match_value[16]; /* Indicate when received uuid_match adv_pkts, can provision it at once */ - bool prov_after_match; + bool prov_after_match; -#if defined(CONFIG_BLE_MESH_PB_ADV) +#if CONFIG_BLE_MESH_PB_ADV /* Mutex used to protect the PB-ADV procedure */ bt_mesh_mutex_t pb_adv_lock; +#endif /* CONFIG_BLE_MESH_PB_ADV */ - /* Mutex used to protect the adv buf during PB-ADV procedure */ - bt_mesh_mutex_t pb_buf_lock; -#endif - -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT /* Mutex used to protect the PB-GATT procedure */ bt_mesh_mutex_t pb_gatt_lock; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ /* Fast provisioning related information */ struct { bool enable; uint16_t net_idx; - uint8_t flags; - uint32_t iv_index; uint16_t unicast_addr_min; uint16_t unicast_addr_max; } fast_prov; @@ -284,7 +113,7 @@ struct unprov_dev_queue { uint16_t oob_info; uint8_t bearer; uint8_t flags; -} __packed unprov_dev[CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM] = { +} __attribute__((packed)) unprov_dev[CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM] = { [0 ... (CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM - 1)] = { .addr.type = 0xff, .bearer = 0, @@ -292,74 +121,55 @@ struct unprov_dev_queue { }, }; -static unprov_adv_pkt_cb_t notify_unprov_adv_pkt_cb; +static unprov_adv_pkt_cb_t notify_unprov_adv_pkt_cb; -#define BUF_TIMEOUT K_MSEC(400) - -#if defined(CONFIG_BLE_MESH_FAST_PROV) -#define RETRANSMIT_TIMEOUT K_MSEC(360) -#define TRANSACTION_TIMEOUT K_SECONDS(3) -#define PROVISION_TIMEOUT K_SECONDS(6) -#else -#define RETRANSMIT_TIMEOUT K_MSEC(500) -#define TRANSACTION_TIMEOUT K_SECONDS(30) -#define PROVISION_TIMEOUT K_SECONDS(60) -#endif /* CONFIG_BLE_MESH_FAST_PROV */ - -#if defined(CONFIG_BLE_MESH_PB_GATT) -#define PROV_BUF_HEADROOM 5 -#else -#define PROV_BUF_HEADROOM 0 +#if CONFIG_BLE_MESH_PB_ADV +static void send_link_open(struct bt_mesh_prov_link *link); +extern uint8_t pvnr_next_xact_id(struct bt_mesh_prov_link *link); #endif -#define PROV_BUF(name, len) \ - NET_BUF_SIMPLE_DEFINE(name, PROV_BUF_HEADROOM + len) +static void prov_gen_dh_key(struct bt_mesh_prov_link *link); +static void send_pub_key(struct bt_mesh_prov_link *link); +static void close_link(struct bt_mesh_prov_link *link, uint8_t reason); +static void send_invite(struct bt_mesh_prov_link *link); -static const struct bt_mesh_prov *prov; - -#if defined(CONFIG_BLE_MESH_PB_ADV) -static void send_link_open(const uint8_t idx); -#endif - -static void prov_gen_dh_key(const uint8_t idx); - -static void send_pub_key(const uint8_t idx, uint8_t oob); - -static void close_link(const uint8_t idx, uint8_t reason); - -#if defined(CONFIG_BLE_MESH_PB_ADV) -#define ADV_BUF_SIZE 65 - -static struct prov_adv_buf { +#if CONFIG_BLE_MESH_PB_ADV +static struct prov_rx_buf { struct net_buf_simple buf; -} adv_buf[CONFIG_BLE_MESH_PBA_SAME_TIME]; +} rx_buf[CONFIG_BLE_MESH_PBA_SAME_TIME]; -static uint8_t adv_buf_data[ADV_BUF_SIZE * CONFIG_BLE_MESH_PBA_SAME_TIME]; +static uint8_t rx_buf_data[PROV_RX_BUF_SIZE * CONFIG_BLE_MESH_PBA_SAME_TIME]; #endif /* CONFIG_BLE_MESH_PB_ADV */ -#define PROV_FREE_MEM(_idx, member) \ -{ \ - if (link[_idx].member) { \ - bt_mesh_free(link[_idx].member); \ - link[_idx].member = NULL; \ - } \ +#define PROV_FREE_MEM(_idx, member) \ +{ \ + if (prov_links[_idx].member) { \ + bt_mesh_free(prov_links[_idx].member); \ + prov_links[_idx].member = NULL; \ + } \ } -#if defined(CONFIG_BLE_MESH_PB_ADV) -static inline void bt_mesh_pb_adv_mutex_new(void) +struct bt_mesh_prov_link *bt_mesh_prov_pvnr_get_link(void) { - if (!prov_ctx.pb_adv_lock.mutex) { - bt_mesh_mutex_create(&prov_ctx.pb_adv_lock); - } + return &prov_links[0]; } -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_pb_adv_mutex_free(void) +uint8_t bt_mesh_prov_pvnr_get_link_count(void) { - bt_mesh_mutex_free(&prov_ctx.pb_adv_lock); + return BLE_MESH_PROV_SAME_TIME; } -#endif /* CONFIG_BLE_MESH_DEINIT */ +void bt_mesh_prov_pvnr_close_link(struct bt_mesh_prov_link *link, uint8_t reason) +{ + close_link(link, reason); +} + +void bt_mesh_prov_pvnr_send_invite(struct bt_mesh_prov_link *link) +{ + send_invite(link); +} + +#if CONFIG_BLE_MESH_PB_ADV static inline void bt_mesh_pb_adv_lock(void) { bt_mesh_mutex_lock(&prov_ctx.pb_adv_lock); @@ -369,47 +179,9 @@ static inline void bt_mesh_pb_adv_unlock(void) { bt_mesh_mutex_unlock(&prov_ctx.pb_adv_lock); } - -static inline void bt_mesh_pb_buf_mutex_new(void) -{ - if (!prov_ctx.pb_buf_lock.mutex) { - bt_mesh_mutex_create(&prov_ctx.pb_buf_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_pb_buf_mutex_free(void) -{ - bt_mesh_mutex_free(&prov_ctx.pb_buf_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_pb_buf_lock(void) -{ - bt_mesh_mutex_lock(&prov_ctx.pb_buf_lock); -} - -static inline void bt_mesh_pb_buf_unlock(void) -{ - bt_mesh_mutex_unlock(&prov_ctx.pb_buf_lock); -} #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) -static inline void bt_mesh_pb_gatt_mutex_new(void) -{ - if (!prov_ctx.pb_gatt_lock.mutex) { - bt_mesh_mutex_create(&prov_ctx.pb_gatt_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_pb_gatt_mutex_free(void) -{ - bt_mesh_mutex_free(&prov_ctx.pb_gatt_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - +#if CONFIG_BLE_MESH_PB_GATT static inline void bt_mesh_pb_gatt_lock(void) { bt_mesh_mutex_lock(&prov_ctx.pb_gatt_lock); @@ -444,43 +216,36 @@ void bt_mesh_provisioner_clear_link_info(const uint8_t addr[6]) BT_DBG("Clear device info, addr %s", bt_hex(addr, BLE_MESH_ADDR_LEN)); for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (!memcmp(link[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { - link[i].connecting = false; - link[i].conn = NULL; - link[i].oob_info = 0x0; - memset(link[i].uuid, 0, 16); - memset(&link[i].addr, 0, sizeof(bt_mesh_addr_t)); - bt_mesh_atomic_test_and_clear_bit(link[i].flags, LINK_ACTIVE); - if (bt_mesh_atomic_test_and_clear_bit(link[i].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[i].timeout); - } + if (!memcmp(prov_links[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { + bt_mesh_atomic_clear_bit(prov_links[i].flags, CONNECTING); + prov_links[i].conn = NULL; + prov_links[i].oob_info = 0x0; + memset(prov_links[i].uuid, 0, 16); + memset(&prov_links[i].addr, 0, sizeof(bt_mesh_addr_t)); + bt_mesh_atomic_clear_bit(prov_links[i].flags, LINK_ACTIVE); + k_delayed_work_cancel(&prov_links[i].prot_timer); return; } } BT_WARN("Device not found, addr %s", bt_hex(addr, BLE_MESH_ADDR_LEN)); - return; } #endif /* CONFIG_BLE_MESH_PB_GATT */ -const struct bt_mesh_prov *bt_mesh_provisioner_get_prov_info(void) -{ - return prov; -} - +#if CONFIG_BLE_MESH_SETTINGS void bt_mesh_provisioner_restore_prov_info(uint16_t primary_addr, uint16_t alloc_addr) { prov_ctx.primary_addr = primary_addr; - prov_ctx.curr_alloc_addr = alloc_addr; + prov_ctx.alloc_addr = alloc_addr; } +#endif /* CONFIG_BLE_MESH_SETTINGS */ static bool is_unprov_dev_being_provision(const uint8_t uuid[16]) { int i; -#if defined(CONFIG_BLE_MESH_FAST_PROV) - /** - * During Fast Provisioning test, we found that if a device has already being +#if CONFIG_BLE_MESH_FAST_PROV + /* During Fast Provisioning test, we found that if a device has already being * provisioned, there is still a chance that the Provisioner can receive the * Unprovisioned Device Beacon from the device (because the device will stop * Unprovisioned Device Beacon when Transaction ACK for Provisioning Complete @@ -490,18 +255,15 @@ static bool is_unprov_dev_being_provision(const uint8_t uuid[16]) BT_WARN("Device has already been provisioned"); return true; } -#endif +#endif /* CONFIG_BLE_MESH_FAST_PROV */ for (i = 0; i < BLE_MESH_PROV_SAME_TIME; i++) { -#if defined(CONFIG_BLE_MESH_PB_ADV) && defined(CONFIG_BLE_MESH_PB_GATT) - if (link[i].linking || link[i].connecting || - bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { -#elif defined(CONFIG_BLE_MESH_PB_ADV) && !defined(CONFIG_BLE_MESH_PB_GATT) - if (link[i].linking || bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { -#else - if (link[i].connecting || bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) +#if CONFIG_BLE_MESH_PB_GATT + || bt_mesh_atomic_test_bit(prov_links[i].flags, CONNECTING) #endif - if (!memcmp(link[i].uuid, uuid, 16)) { + ) { + if (!memcmp(prov_links[i].uuid, uuid, 16)) { BT_DBG("Device is being provisioning"); return true; } @@ -513,11 +275,14 @@ static bool is_unprov_dev_being_provision(const uint8_t uuid[16]) static bool is_unprov_dev_uuid_match(const uint8_t uuid[16]) { - if (prov_ctx.match_length) { - if (memcmp(uuid + prov_ctx.match_offset, - prov_ctx.match_value, prov_ctx.match_length)) { - return false; - } + /* Match value is not configured */ + if (prov_ctx.match_length == 0) { + return true; + } + + if (memcmp(uuid + prov_ctx.match_offset, + prov_ctx.match_value, prov_ctx.match_length)) { + return false; } return true; @@ -546,23 +311,25 @@ static int provisioner_check_unprov_dev_info(const uint8_t uuid[16], bt_mesh_pro return -EALREADY; } +#if CONFIG_BLE_MESH_PB_ADV /* Check if the current PB-ADV link is full */ - if (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && - (prov_ctx.bearers & BLE_MESH_PROV_ADV) && + if ((prov_ctx.bearers & BLE_MESH_PROV_ADV) && (bearer == BLE_MESH_PROV_ADV) && (prov_ctx.pba_count == CONFIG_BLE_MESH_PBA_SAME_TIME)) { BT_INFO("Current PB-ADV links reach max limit"); return -ENOMEM; } +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#if CONFIG_BLE_MESH_PB_GATT /* Check if the current PB-GATT link is full */ - if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - (prov_ctx.bearers & BLE_MESH_PROV_GATT) && + if ((prov_ctx.bearers & BLE_MESH_PROV_GATT) && (bearer == BLE_MESH_PROV_GATT) && (prov_ctx.pbg_count == CONFIG_BLE_MESH_PBG_SAME_TIME)) { BT_INFO("Current PB-GATT links reach max limit"); return -ENOMEM; } +#endif /* CONFIG_BLE_MESH_PB_GATT */ /* Check if the device has already been provisioned */ if (bt_mesh_provisioner_get_node_with_uuid(uuid)) { @@ -572,7 +339,7 @@ static int provisioner_check_unprov_dev_info(const uint8_t uuid[16], bt_mesh_pro return 0; } -#if defined(CONFIG_BLE_MESH_PB_ADV) +#if CONFIG_BLE_MESH_PB_ADV static int provisioner_start_prov_pb_adv(const uint8_t uuid[16], const bt_mesh_addr_t *addr, uint16_t oob_info, uint16_t assign_addr) { @@ -585,11 +352,11 @@ static int provisioner_start_prov_pb_adv(const uint8_t uuid[16], const bt_mesh_a bt_mesh_pb_adv_lock(); - /* If the unicast address of the node is going to be allocated internally, - * then we need to check if there are addresses can be allocated. + /* If the unicast address of the device is allocated internally, + * then we need to check if there are addresses available. */ if (assign_addr == BLE_MESH_ADDR_UNASSIGNED && - prov_ctx.curr_alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { + prov_ctx.alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("No available unicast address to assign"); bt_mesh_pb_adv_unlock(); return -EIO; @@ -601,21 +368,21 @@ 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(link[i].flags, LINK_ACTIVE) && !link[i].linking) { - memcpy(link[i].uuid, uuid, 16); - link[i].oob_info = oob_info; + if (!bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE)) { + memcpy(prov_links[i].uuid, uuid, 16); + prov_links[i].oob_info = oob_info; if (addr) { - link[i].addr.type = addr->type; - memcpy(link[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); + prov_links[i].addr.type = addr->type; + memcpy(prov_links[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); } - send_link_open(i); + send_link_open(&prov_links[i]); /* If a specific unicast address is assigned for the device, then * Provisioner will use this address in the Provisioning Data PDU. */ if (BLE_MESH_ADDR_IS_UNICAST(assign_addr)) { - link[i].assign_addr = assign_addr; + prov_links[i].assign_addr = assign_addr; } /* Increase PB-ADV link count */ @@ -633,7 +400,7 @@ static int provisioner_start_prov_pb_adv(const uint8_t uuid[16], const bt_mesh_a } #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_addr_t *addr, uint16_t oob_info, uint16_t assign_addr) { @@ -646,11 +413,11 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ bt_mesh_pb_gatt_lock(); - /* If the unicast address of the node is going to be allocated internally, - * then we need to check if there are addresses can be allocated. + /* If the unicast address of the device is allocated internally, + * then we need to check if there are addresses available. */ if (assign_addr == BLE_MESH_ADDR_UNASSIGNED && - prov_ctx.curr_alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { + prov_ctx.alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("No available unicast address to assign"); bt_mesh_pb_gatt_unlock(); return -EIO; @@ -662,26 +429,27 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ } for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (!link[i].connecting && !bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(prov_links[i].flags, CONNECTING) && + !bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE)) { if (bt_mesh_gattc_conn_create(addr, BLE_MESH_UUID_MESH_PROV_VAL)) { bt_mesh_pb_gatt_unlock(); return -EIO; } - memcpy(link[i].uuid, uuid, 16); - link[i].oob_info = oob_info; - link[i].addr.type = addr->type; - memcpy(link[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); + memcpy(prov_links[i].uuid, uuid, 16); + prov_links[i].oob_info = oob_info; + prov_links[i].addr.type = addr->type; + memcpy(prov_links[i].addr.val, addr->val, BLE_MESH_ADDR_LEN); /* If the application layer assigned a specific unicast address for the device, * then Provisioner will use this address in the Provisioning Data PDU. */ if (BLE_MESH_ADDR_IS_UNICAST(assign_addr)) { - link[i].assign_addr = assign_addr; + prov_links[i].assign_addr = assign_addr; } - /* If creating connection successfully, set connecting flag to 1 */ - link[i].connecting = true; + /* If creating connection successfully, set CONNECTING flag */ + bt_mesh_atomic_set_bit(prov_links[i].flags, CONNECTING); /* Increase PB-GATT link count */ provisioner_pbg_count_inc(); @@ -722,14 +490,14 @@ int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u } if ((!IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) || - !(prov_ctx.bearers & BLE_MESH_PROV_GATT)) + !(prov_ctx.bearers & BLE_MESH_PROV_GATT)) && (add_dev->bearer & BLE_MESH_PROV_GATT)) { BT_ERR("Not support PB-GATT"); return -EINVAL; } if ((!IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) || - !(prov_ctx.bearers & BLE_MESH_PROV_ADV)) + !(prov_ctx.bearers & BLE_MESH_PROV_ADV)) && (add_dev->bearer & BLE_MESH_PROV_ADV)) { BT_ERR("Not support PB-ADV"); return -EINVAL; @@ -757,11 +525,10 @@ int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u } /* Check if the provisioned nodes array is full */ - if (bt_mesh_provisioner_get_node_with_uuid(add_dev->uuid) == NULL) { - if (bt_mesh_provisioner_get_node_count() == CONFIG_BLE_MESH_MAX_PROV_NODES) { - BT_WARN("Current provisioned devices reach max limit"); - return -ENOMEM; - } + if (bt_mesh_provisioner_get_node_with_uuid(add_dev->uuid) == NULL && + bt_mesh_provisioner_get_node_count() == CONFIG_BLE_MESH_MAX_PROV_NODES) { + BT_WARN("Current provisioned devices reach max limit"); + return -ENOMEM; } /* Check if the device already exists in queue */ @@ -818,8 +585,14 @@ start: /* Check if current provisioned node count + active link reach max limit */ if (bt_mesh_provisioner_get_node_with_uuid(add_dev->uuid) == NULL) { - if (bt_mesh_provisioner_get_node_count() + prov_ctx.pba_count + \ - prov_ctx.pbg_count >= CONFIG_BLE_MESH_MAX_PROV_NODES) { + if (bt_mesh_provisioner_get_node_count() +#if CONFIG_BLE_MESH_PB_ADV + + prov_ctx.pba_count /* Add current PB-ADV link count */ +#endif +#if CONFIG_BLE_MESH_PB_GATT + + prov_ctx.pbg_count /* Add current PB-GATT link count */ +#endif + >= CONFIG_BLE_MESH_MAX_PROV_NODES) { BT_WARN("Node count + active link count reach max limit"); return -EIO; } @@ -829,22 +602,21 @@ start: return err; } +#if CONFIG_BLE_MESH_PB_ADV if (add_dev->bearer == BLE_MESH_PROV_ADV) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - if ((err = provisioner_start_prov_pb_adv(add_dev->uuid, addr_valid ? &add_addr : NULL, - add_dev->oob_info, BLE_MESH_ADDR_UNASSIGNED))) { - return err; - } -#endif - } else if (add_dev->bearer == BLE_MESH_PROV_GATT) { -#if defined(CONFIG_BLE_MESH_PB_GATT) - if ((err = provisioner_start_prov_pb_gatt(add_dev->uuid, &add_addr, add_dev->oob_info, - BLE_MESH_ADDR_UNASSIGNED))) { - return err; - } -#endif + return provisioner_start_prov_pb_adv(add_dev->uuid, addr_valid ? &add_addr : NULL, + add_dev->oob_info, BLE_MESH_ADDR_UNASSIGNED); } +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#if CONFIG_BLE_MESH_PB_GATT + if (add_dev->bearer == BLE_MESH_PROV_GATT) { + return provisioner_start_prov_pb_gatt(add_dev->uuid, &add_addr, add_dev->oob_info, + BLE_MESH_ADDR_UNASSIGNED); + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ + + /* Shall not reach here. */ return 0; } @@ -866,14 +638,14 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint } if ((!IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) || - !(prov_ctx.bearers & BLE_MESH_PROV_ADV)) && + !(prov_ctx.bearers & BLE_MESH_PROV_ADV)) && (bearer == BLE_MESH_PROV_ADV)) { BT_ERR("Not support PB-ADV"); return -ENOTSUP; } if ((!IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) || - !(prov_ctx.bearers & BLE_MESH_PROV_GATT)) && + !(prov_ctx.bearers & BLE_MESH_PROV_GATT)) && (bearer == BLE_MESH_PROV_GATT)) { BT_ERR("Not support PB-GATT"); return -ENOTSUP; @@ -892,7 +664,7 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint /* Here we will not check if the assigned unicast address is overlapped * with the unicast addresses of other nodes or Provisioner, because: * 1. At this moment, the element number of the device is unknown - * 2. If the node is a reprovisioned device, then the original allocated + * 2. If the node is a re-provisioned device, then the original allocated * unicast address will be used. * 3. Some other devices may be just being provisioning, and currently we * can not know the exactly allocated addresses of them. @@ -906,8 +678,14 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint } /* Check if current provisioned node count + active link reach max limit */ - if (bt_mesh_provisioner_get_node_count() + prov_ctx.pba_count + \ - prov_ctx.pbg_count >= CONFIG_BLE_MESH_MAX_PROV_NODES) { + if (bt_mesh_provisioner_get_node_count() +#if CONFIG_BLE_MESH_PB_ADV + + prov_ctx.pba_count /* Add current PB-ADV link count */ +#endif +#if CONFIG_BLE_MESH_PB_GATT + + prov_ctx.pbg_count /* Add current PB-GATT link count */ +#endif + >= CONFIG_BLE_MESH_MAX_PROV_NODES) { BT_WARN("Node count + active link count reach max limit"); return -EIO; } @@ -922,20 +700,19 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint memcpy(dev_addr.val, addr, BLE_MESH_ADDR_LEN); } +#if CONFIG_BLE_MESH_PB_ADV if (bearer == BLE_MESH_PROV_ADV) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - if ((err = provisioner_start_prov_pb_adv(uuid, addr ? &dev_addr : NULL, oob_info, unicast_addr))) { - return err; - } -#endif - } else if (bearer == BLE_MESH_PROV_GATT) { -#if defined(CONFIG_BLE_MESH_PB_GATT) - if ((err = provisioner_start_prov_pb_gatt(uuid, &dev_addr, oob_info, unicast_addr))) { - return err; - } -#endif + return provisioner_start_prov_pb_adv(uuid, addr ? &dev_addr : NULL, oob_info, unicast_addr); } +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#if CONFIG_BLE_MESH_PB_GATT + if (bearer == BLE_MESH_PROV_GATT) { + return provisioner_start_prov_pb_gatt(uuid, &dev_addr, oob_info, unicast_addr); + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ + + /* Shall not reach here. */ return 0; } @@ -963,9 +740,9 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) } /* Find if the device is being provisioned */ - for (i = 0; i < ARRAY_SIZE(link); i++) { - if (!memcmp(link[i].uuid, del_dev->uuid, 16)) { - close_link(i, CLOSE_REASON_FAILED); + for (i = 0; i < ARRAY_SIZE(prov_links); i++) { + if (!memcmp(prov_links[i].uuid, del_dev->uuid, 16)) { + close_link(&prov_links[i], CLOSE_REASON_FAILED); break; } } @@ -976,7 +753,7 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) int bt_mesh_provisioner_set_dev_uuid_match(uint8_t offset, uint8_t length, const uint8_t *match, bool prov_flag) { - if (length && (!match || (offset + length > 16))) { + if (length && (match == NULL || (offset + length > 16))) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } @@ -1008,7 +785,7 @@ int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info) { const uint8_t *key = NULL; - if (!info || info->flag == 0) { + if (info == NULL || info->flag == 0) { return -EINVAL; } @@ -1018,31 +795,34 @@ int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info) BT_ERR("Failed to get NetKey"); return -EINVAL; } - prov_ctx.curr_net_idx = info->net_idx; - } else if (info->flag & FLAGS_FLAG) { - prov_ctx.curr_flags = info->flags; - } else if (info->flag & IV_INDEX_FLAG) { - prov_ctx.curr_iv_index = info->iv_index; + + prov_ctx.net_idx = info->net_idx; } return 0; } +static inline uint8_t get_net_flags(uint16_t net_idx) +{ + return bt_mesh_net_flags(bt_mesh_subnet_get(net_idx)); +} + int bt_mesh_provisioner_init_prov_info(void) { if (prov_ctx.primary_addr == BLE_MESH_ADDR_UNASSIGNED) { /* If unicast address of primary element of Provisioner has not been set * before, then the following initialization procedure will be used. */ - if (prov == NULL) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } - if (!BLE_MESH_ADDR_IS_UNICAST(prov->prov_unicast_addr) || - !BLE_MESH_ADDR_IS_UNICAST(prov->prov_start_address)) { + if (!BLE_MESH_ADDR_IS_UNICAST(bt_mesh_prov_get()->prov_unicast_addr) || + !BLE_MESH_ADDR_IS_UNICAST(bt_mesh_prov_get()->prov_start_address)) { BT_ERR("Invalid address, own 0x%04x, start 0x%04x", - prov->prov_unicast_addr, prov->prov_start_address); + bt_mesh_prov_get()->prov_unicast_addr, + bt_mesh_prov_get()->prov_start_address); return -EINVAL; } @@ -1052,26 +832,26 @@ int bt_mesh_provisioner_init_prov_info(void) return -EINVAL; } - if (prov->prov_unicast_addr + comp->elem_count > prov->prov_start_address) { + if (bt_mesh_prov_get()->prov_unicast_addr + comp->elem_count > + bt_mesh_prov_get()->prov_start_address) { BT_WARN("Too small start address 0x%04x, update to 0x%04x", - prov->prov_start_address, prov->prov_unicast_addr + comp->elem_count); - prov_ctx.curr_alloc_addr = prov->prov_unicast_addr + comp->elem_count; + bt_mesh_prov_get()->prov_start_address, + bt_mesh_prov_get()->prov_unicast_addr + comp->elem_count); + + prov_ctx.alloc_addr = bt_mesh_prov_get()->prov_unicast_addr + comp->elem_count; } else { - prov_ctx.curr_alloc_addr = prov->prov_start_address; + prov_ctx.alloc_addr = bt_mesh_prov_get()->prov_start_address; } /* Update primary element address with the initialized value here. */ - prov_ctx.primary_addr = prov->prov_unicast_addr; + prov_ctx.primary_addr = bt_mesh_prov_get()->prov_unicast_addr; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.curr_alloc_addr); + bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.alloc_addr); } } - prov_ctx.curr_net_idx = BLE_MESH_KEY_PRIMARY; - struct bt_mesh_subnet *sub = bt_mesh_provisioner_subnet_get(BLE_MESH_KEY_PRIMARY); - prov_ctx.curr_flags = bt_mesh_net_flags(sub); - prov_ctx.curr_iv_index = bt_mesh.iv_index; + prov_ctx.net_idx = BLE_MESH_KEY_PRIMARY; return 0; } @@ -1094,22 +874,22 @@ int bt_mesh_provisioner_set_static_oob_value(const uint8_t *value, uint8_t lengt { int i; - if (value == NULL || length == 0U || length > 16U) { + if (value == NULL || length == 0U || length > BLE_MESH_PROV_STATIC_OOB_MAX_LEN) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } /* Make sure Static OOB is not being used. */ for (i = 0; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (link[i].auth_method == AUTH_METHOD_STATIC) { + if (prov_links[i].auth_method == AUTH_METHOD_STATIC) { BT_ERR("Static OOB is being used"); return -EINVAL; } } - (void)memset(prov_ctx.static_oob_val, 0, 16); + (void)memset(prov_ctx.static_oob_val, 0, BLE_MESH_PROV_STATIC_OOB_MAX_LEN); - prov_ctx.static_oob_len = MIN(16, length); + prov_ctx.static_oob_len = MIN(BLE_MESH_PROV_STATIC_OOB_MAX_LEN, length); memcpy(prov_ctx.static_oob_val, value, prov_ctx.static_oob_len); return 0; @@ -1141,19 +921,19 @@ int bt_mesh_provisioner_set_primary_elem_addr(uint16_t addr) return -EINVAL; } - /* If the current can-be allocated address is bigger than primary address + - * element number, then the curr_alloc_addr will not be changed, and only + /* If the current can-be allocated address is larger than "primary address + * + element number", then the alloc_addr will not be changed, and only * the Provisioner related addresses will be updated. */ - if (addr + comp->elem_count > prov_ctx.curr_alloc_addr) { - prov_ctx.curr_alloc_addr = addr + comp->elem_count; + if (addr + comp->elem_count > prov_ctx.alloc_addr) { + prov_ctx.alloc_addr = addr + comp->elem_count; } BT_INFO("Primary address updated, old 0x%04x, new 0x%04x", prov_ctx.primary_addr, addr); prov_ctx.primary_addr = addr; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.curr_alloc_addr); + bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.alloc_addr); } bt_mesh_comp_provision(addr); @@ -1164,17 +944,17 @@ int bt_mesh_provisioner_set_primary_elem_addr(uint16_t addr) #if CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK int bt_mesh_test_provisioner_update_alloc_addr(uint16_t unicast_addr, uint16_t element_num) { - uint16_t max_addr = FAST_PROV_ENABLE() ? prov_ctx.fast_prov.unicast_addr_max : PROV_MAX_ADDR_TO_ASSIGN; + uint16_t max_addr = FAST_PROV_ENABLE() ? prov_ctx.fast_prov.unicast_addr_max : UNICAST_ADDR_LIMIT; if (unicast_addr + element_num > max_addr) { BT_WARN("Not enough unicast address to allocate"); - prov_ctx.curr_alloc_addr = BLE_MESH_ADDR_UNASSIGNED; + prov_ctx.alloc_addr = BLE_MESH_ADDR_UNASSIGNED; } else { - prov_ctx.curr_alloc_addr = unicast_addr + element_num; + prov_ctx.alloc_addr = unicast_addr + element_num; } if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.curr_alloc_addr); + bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.alloc_addr); } return 0; @@ -1218,518 +998,216 @@ uint8_t bt_mesh_set_fast_prov_unicast_addr_range(uint16_t min, uint16_t max) prov_ctx.fast_prov.unicast_addr_min = min; prov_ctx.fast_prov.unicast_addr_max = max; - prov_ctx.curr_alloc_addr = prov_ctx.fast_prov.unicast_addr_min; + prov_ctx.alloc_addr = prov_ctx.fast_prov.unicast_addr_min; return 0x0; /* status: success */ } -void bt_mesh_set_fast_prov_flags_iv_index(uint8_t flags, uint32_t iv_index) +static void prov_memory_free(struct bt_mesh_prov_link *link) { - /* BIT0: Key Refresh flag, BIT1: IV Update flag */ - prov_ctx.fast_prov.flags = flags & BIT_MASK(2); - prov_ctx.fast_prov.iv_index = iv_index; + /* TODO: memory optimization - free */ } -#if defined(CONFIG_BLE_MESH_PB_ADV) -static struct net_buf_simple *bt_mesh_pba_get_buf(const uint8_t idx) +#if CONFIG_BLE_MESH_PB_ADV +static struct net_buf_simple *get_rx_buf(const uint8_t idx) { - struct net_buf_simple *buf = &(adv_buf[idx].buf); + struct net_buf_simple *buf = &(rx_buf[idx].buf); net_buf_simple_reset(buf); return buf; } -#endif /* CONFIG_BLE_MESH_PB_ADV */ -static void prov_memory_free(const uint8_t idx) +static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { - PROV_FREE_MEM(idx, dhkey); - PROV_FREE_MEM(idx, auth); - PROV_FREE_MEM(idx, rand); - PROV_FREE_MEM(idx, conf); - PROV_FREE_MEM(idx, local_conf); - PROV_FREE_MEM(idx, conf_salt); - PROV_FREE_MEM(idx, conf_key); - PROV_FREE_MEM(idx, conf_inputs); - PROV_FREE_MEM(idx, prov_salt); -} + bt_mesh_prov_clear_tx(link, true); -#if defined(CONFIG_BLE_MESH_PB_ADV) -static void buf_sent(int err, void *user_data) -{ - uint8_t idx = (int)user_data; - - if (!link[idx].tx.buf[0]) { - return; + if (bt_mesh_prov_get()->prov_link_close) { + bt_mesh_prov_get()->prov_link_close(BLE_MESH_PROV_ADV, reason); } - k_delayed_work_submit(&link[idx].tx.retransmit, RETRANSMIT_TIMEOUT); -} + prov_memory_free(link); -static struct bt_mesh_send_cb buf_sent_cb = { - .end = buf_sent, -}; + k_delayed_work_cancel(&link->prot_timer); -static void free_segments(const uint8_t idx) -{ - int i; - - bt_mesh_pb_buf_lock(); - - for (i = 0; i < ARRAY_SIZE(link[idx].tx.buf); i++) { - struct net_buf *buf = link[idx].tx.buf[i]; - - if (!buf) { - break; - } - - link[idx].tx.buf[i] = NULL; - bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); - /* Mark as canceled */ - BLE_MESH_ADV(buf)->busy = 0U; - net_buf_unref(buf); +#if CONFIG_BLE_MESH_PB_GATT + if (link->conn) { + bt_mesh_conn_unref(link->conn); } +#endif - bt_mesh_pb_buf_unlock(); -} - -static void prov_clear_tx(const uint8_t idx) -{ - BT_DBG("%s", __func__); - - k_delayed_work_cancel(&link[idx].tx.retransmit); - - free_segments(idx); -} - -static void reset_link(const uint8_t idx, uint8_t reason) -{ - prov_clear_tx(idx); - - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } - - if (prov->prov_link_close) { - prov->prov_link_close(BLE_MESH_PROV_ADV, reason); - } - - prov_memory_free(idx); - -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Remove the link id from exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link[idx].link_id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &link->link_id); #endif /* Clear everything except the retransmit delayed work config */ - memset(&link[idx], 0, offsetof(struct prov_link, tx.retransmit)); + memset(link, 0, offsetof(struct bt_mesh_prov_link, tx.retransmit)); - link[idx].pending_ack = XACT_NVAL; - link[idx].rx.prev_id = XACT_NVAL; + link->pending_ack = PROV_XACT_NVAL; - if (bt_mesh_pub_key_get()) { - bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); - } + link->rx.prev_id = PROV_XACT_NVAL; + link->rx.buf = get_rx_buf(link - prov_links); - link[idx].rx.buf = bt_mesh_pba_get_buf(idx); + link->next_xact_id = pvnr_next_xact_id; + link->reset_adv_link = reset_adv_link; + link->retrans_timeout = close_link; + +#if CONFIG_BLE_MESH_FAST_PROV + link->last_tx_pdu = PROV_DATA; +#endif /* CONFIG_BLE_MESH_FAST_PROV */ if (prov_ctx.pba_count) { prov_ctx.pba_count--; } } -static struct net_buf *adv_buf_create(void) -{ - struct net_buf *buf = NULL; - - buf = bt_mesh_adv_create(BLE_MESH_ADV_PROV, PROV_XMIT, BUF_TIMEOUT); - if (!buf) { - BT_ERR("Out of provisioning buffers"); - return NULL; - } - - return buf; -} - -static void ack_complete(uint16_t duration, int err, void *user_data) -{ - uint8_t idx = (int)user_data; - - BT_DBG("xact %u complete", link[idx].pending_ack); - - link[idx].pending_ack = XACT_NVAL; -} - -static void gen_prov_ack_send(const uint8_t idx, uint8_t xact_id) -{ - static const struct bt_mesh_send_cb cb = { - .start = ack_complete, - }; - const struct bt_mesh_send_cb *complete = NULL; - struct net_buf *buf = NULL; - - BT_DBG("xact_id %u", xact_id); - - if (link[idx].pending_ack == xact_id) { - BT_DBG("Not sending duplicate ack"); - return; - } - - buf = adv_buf_create(); - if (!buf) { - return; - } - - if (link[idx].pending_ack == XACT_NVAL) { - link[idx].pending_ack = xact_id; - complete = &cb; - } else { - complete = NULL; - } - - net_buf_add_be32(buf, link[idx].link_id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_ACK); - - bt_mesh_adv_send(buf, complete, (void *)(int)idx); - net_buf_unref(buf); -} - -static void send_reliable(const uint8_t idx) +static void send_link_open(struct bt_mesh_prov_link *link) { int i; - link[idx].tx.start = k_uptime_get(); - - for (i = 0; i < ARRAY_SIZE(link[idx].tx.buf); i++) { - struct net_buf *buf = link[idx].tx.buf[i]; - - if (!buf) { - break; - } - - if (i + 1 < ARRAY_SIZE(link[idx].tx.buf) && link[idx].tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, (void *)(int)idx); - } - } -} - -static int bearer_ctl_send(const uint8_t idx, uint8_t op, void *data, uint8_t data_len) -{ - struct net_buf *buf = NULL; - - BT_DBG("op 0x%02x data_len %u", op, data_len); - - prov_clear_tx(idx); - - buf = adv_buf_create(); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_be32(buf, link[idx].link_id); - /* Transaction ID, always 0 for Bearer messages */ - net_buf_add_u8(buf, 0x00); - net_buf_add_u8(buf, GPC_CTL(op)); - net_buf_add_mem(buf, data, data_len); - - link[idx].tx.buf[0] = buf; - send_reliable(idx); - - /** We can also use buf->ref and a flag to decide that - * link close has been sent 3 times. - * Here we use another way: use retransmit timer and need - * to make sure the timer is not cancelled during sending - * link close pdu, so we add link[i].tx.id = 0 + /* Generate link ID, and may need to check if this id is + * currently being used, which may will not happen ever. */ - if (op == LINK_CLOSE) { - uint8_t reason = *(uint8_t *)data; - link[idx].send_link_close = ((reason & BIT_MASK(2)) << 1) | BIT(0); - link[idx].tx.trans_id = 0; - } + bt_mesh_rand(&link->link_id, sizeof(link->link_id)); - return 0; -} - -static void send_link_open(const uint8_t idx) -{ - int j; - - /** 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[idx].link_id, sizeof(uint32_t)); while (1) { - for (j = 0; j < CONFIG_BLE_MESH_PBA_SAME_TIME; j++) { - if (bt_mesh_atomic_test_bit(link[j].flags, LINK_ACTIVE) || link[j].linking) { - if (link[idx].link_id == link[j].link_id) { - bt_mesh_rand(&link[idx].link_id, sizeof(uint32_t)); - break; - } + 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) { + bt_mesh_rand(&link->link_id, sizeof(link->link_id)); + break; } } - if (j == CONFIG_BLE_MESH_PBA_SAME_TIME) { + if (i == CONFIG_BLE_MESH_PBA_SAME_TIME) { break; } } -#if defined(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN) +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN /* Add the link id into exceptional list */ bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link[idx].link_id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &link->link_id); #endif - bearer_ctl_send(idx, LINK_OPEN, link[idx].uuid, 16); - - /* If Provisioner sets LINK_ACTIVE flag once Link Open is sent, we have - * no need to use linking flag (like PB-GATT connecting) to prevent the - * stored device info (UUID, oob_info) being replaced by other received - * unprovisioned device beacons. - * But if Provisioner sets LINK_ACTIVE flag after Link ACK is received, - * we need to use linking flag to prevent device info being replaced. - * Currently we set LINK_ACTIVE flag after sending Link Open. - */ - link[idx].linking = true; + bt_mesh_prov_bearer_ctl_send(link, LINK_OPEN, link->uuid, 16); /* Set LINK_ACTIVE just to be in compatibility with current Zephyr code */ - bt_mesh_atomic_set_bit(link[idx].flags, LINK_ACTIVE); + bt_mesh_atomic_set_bit(link->flags, LINK_ACTIVE); - if (prov->prov_link_open) { - prov->prov_link_open(BLE_MESH_PROV_ADV); + if (bt_mesh_prov_get()->prov_link_open) { + bt_mesh_prov_get()->prov_link_open(BLE_MESH_PROV_ADV); } } - -static uint8_t last_seg(uint8_t len) -{ - if (len <= START_PAYLOAD_MAX) { - return 0; - } - - len -= START_PAYLOAD_MAX; - - return 1 + (len / CONT_PAYLOAD_MAX); -} - -static inline uint8_t next_transaction_id(const uint8_t idx) -{ - if (link[idx].tx.trans_id > 0x7F) { - link[idx].tx.trans_id = 0x0; - } - return link[idx].tx.trans_id++; -} - -static int prov_send_adv(const uint8_t idx, struct net_buf_simple *msg) -{ - struct net_buf *start = NULL, *buf = NULL; - uint8_t seg_len = 0U, seg_id = 0U; - uint8_t xact_id = 0U; - int32_t timeout = PROVISION_TIMEOUT; - - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); - - prov_clear_tx(idx); - - start = adv_buf_create(); - if (!start) { - return -ENOBUFS; - } - - xact_id = next_transaction_id(idx); - net_buf_add_be32(start, link[idx].link_id); - net_buf_add_u8(start, xact_id); - - net_buf_add_u8(start, GPC_START(last_seg(msg->len))); - net_buf_add_be16(start, msg->len); - net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); - - link[idx].tx.buf[0] = start; - /* Changed by Espressif, get message type */ - link[idx].tx_pdu_type = msg->data[0]; - - seg_len = MIN(msg->len, START_PAYLOAD_MAX); - BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); - net_buf_add_mem(start, msg->data, seg_len); - net_buf_simple_pull(msg, seg_len); - - buf = start; - for (seg_id = 1; msg->len > 0; seg_id++) { - if (seg_id >= ARRAY_SIZE(link[idx].tx.buf)) { - BT_ERR("Too big message (seg_id %d)", seg_id); - free_segments(idx); - return -E2BIG; - } - - buf = adv_buf_create(); - if (!buf) { - free_segments(idx); - return -ENOBUFS; - } - - link[idx].tx.buf[seg_id] = buf; - - seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); - - BT_DBG("seg_id %u len %u: %s", seg_id, seg_len, - bt_hex(msg->data, seg_len)); - - net_buf_add_be32(buf, link[idx].link_id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_CONT(seg_id)); - net_buf_add_mem(buf, msg->data, seg_len); - net_buf_simple_pull(msg, seg_len); - } - - send_reliable(idx); - -#if defined(CONFIG_BLE_MESH_FAST_PROV) - if (link[idx].tx_pdu_type >= PROV_DATA) { - timeout = K_SECONDS(60); - } -#endif - if (!bt_mesh_atomic_test_and_set_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_submit(&link[idx].timeout, timeout); - } - - return 0; -} #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) -static int prov_send_gatt(const uint8_t idx, struct net_buf_simple *msg) +#if CONFIG_BLE_MESH_PB_GATT +static int prov_send_gatt(struct bt_mesh_prov_link *link, struct net_buf_simple *msg) { int err = 0; - if (!link[idx].conn) { + if (link->conn == NULL) { + BT_ERR("PB-GATT send, not connected"); return -ENOTCONN; } - err = bt_mesh_proxy_client_send(link[idx].conn, BLE_MESH_PROXY_PROV, msg); + err = bt_mesh_proxy_client_send(link->conn, BLE_MESH_PROXY_PROV, msg); if (err) { BT_ERR("Failed to send PB-GATT pdu"); return err; } - if (!bt_mesh_atomic_test_and_set_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_submit(&link[idx].timeout, PROVISION_TIMEOUT); - } + k_delayed_work_submit(&link->prot_timer, PROTOCOL_TIMEOUT); return 0; } #endif /* CONFIG_BLE_MESH_PB_GATT */ -static inline int prov_send(const uint8_t idx, struct net_buf_simple *buf) -{ -#if defined(CONFIG_BLE_MESH_PB_ADV) - if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { - return prov_send_adv(idx, buf); - } -#endif +static void prov_invite(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) +{} -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (idx < BLE_MESH_PROV_SAME_TIME -#if defined(CONFIG_BLE_MESH_PB_ADV) - && idx >= CONFIG_BLE_MESH_PBA_SAME_TIME -#endif - ) { - return prov_send_gatt(idx, buf); - } -#endif +static void prov_start(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) +{} - BT_ERR("Invalid link index %d", idx); - return -EINVAL; -} +static void prov_data(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) +{} -static void prov_buf_init(struct net_buf_simple *buf, uint8_t type) -{ - net_buf_simple_reserve(buf, PROV_BUF_HEADROOM); - net_buf_simple_add_u8(buf, type); -} - -static void prov_invite(const uint8_t idx, const uint8_t *data) -{ - BT_DBG("%s", __func__); -} - -static void prov_start(const uint8_t idx, const uint8_t *data) -{ - BT_DBG("%s", __func__); -} - -static void prov_data(const uint8_t idx, const uint8_t *data) -{ - BT_DBG("%s", __func__); -} - -static void send_invite(const uint8_t idx) +static void send_invite(struct bt_mesh_prov_link *link) { PROV_BUF(buf, 2); - prov_buf_init(&buf, PROV_INVITE); + bt_mesh_prov_buf_init(&buf, PROV_INVITE); - net_buf_simple_add_u8(&buf, prov->prov_attention); + net_buf_simple_add_u8(&buf, bt_mesh_prov_get()->prov_attention); - link[idx].conf_inputs[0] = prov->prov_attention; + link->conf_inputs[0] = bt_mesh_prov_get()->prov_attention; - if (prov_send(idx, &buf)) { + if (bt_mesh_prov_send(link, &buf)) { BT_ERR("Failed to send Provisioning Invite"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - link[idx].expect = PROV_CAPABILITIES; + link->expect = PROV_CAPABILITIES; } -static void prov_capabilities(const uint8_t idx, const uint8_t *data) +static void prov_capabilities(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - PROV_BUF(buf, 6); - uint16_t algorithms = 0U, output_action = 0U, input_action = 0U; - uint8_t element_num = 0U, pub_key_oob = 0U, static_oob = 0U, - output_size = 0U, input_size = 0U; - uint8_t auth_method = 0U, auth_action = 0U, auth_size = 0U; + uint16_t output_action = 0U, input_action = 0U; + uint8_t output_size = 0U, input_size = 0U; + uint8_t oob_type = 0U; + uint8_t pub_key_type = 0U; + uint16_t algorithms = 0U; + uint8_t *data = buf->data; + PROV_BUF(prov_buf, 6); - element_num = data[0]; - BT_INFO("Elements: 0x%02x", element_num); - if (!element_num) { - BT_ERR("Invalid element number %d", element_num); + link->element_num = net_buf_simple_pull_u8(buf); + BT_INFO("Elements: 0x%02x", link->element_num); + if (link->element_num == 0) { + BT_ERR("Invalid element number %d", link->element_num); goto fail; } - link[idx].element_num = element_num; - algorithms = sys_get_be16(&data[1]); + algorithms = net_buf_simple_pull_be16(buf); BT_INFO("Algorithms: 0x%04x", algorithms); - if (algorithms != BIT(PROV_ALG_P256)) { + if (algorithms != BIT(PROV_ALG_P256_CMAC_AES128) +#if CONFIG_BLE_MESH_PROV_EPA + && algorithms != BIT(PROV_ALG_P256_HMAC_SHA256) +#endif + ) { BT_ERR("Invalid algorithms 0x%04x", algorithms); goto fail; } - pub_key_oob = data[3]; - BT_INFO("Public Key Type: 0x%02x", pub_key_oob); - if (pub_key_oob > 0x01) { - BT_ERR("Invalid public key type 0x%02x", pub_key_oob); + pub_key_type = net_buf_simple_pull_u8(buf); + BT_INFO("Public Key Type: 0x%02x", pub_key_type); + if (pub_key_type > PROV_OOB_PUB_KEY) { + BT_ERR("Invalid public key type 0x%02x", pub_key_type); goto fail; } - pub_key_oob = ((prov->prov_pub_key_oob && - prov->prov_pub_key_oob_cb) ? pub_key_oob : 0x00); - static_oob = data[4]; - BT_INFO("Static OOB Type: 0x%02x", static_oob); - if (static_oob > 0x01) { - BT_ERR("Invalid Static OOB type 0x%02x", static_oob); - goto fail; - } - static_oob = (prov_ctx.static_oob_len ? static_oob : 0x00); + link->public_key = ((bt_mesh_prov_get()->prov_pub_key_oob && + bt_mesh_prov_get()->prov_pub_key_oob_cb) ? + pub_key_type : PROV_NO_OOB_PUB_KEY); - output_size = data[5]; + oob_type = net_buf_simple_pull_u8(buf); + BT_INFO("OOB Type: 0x%02x", oob_type); + + output_size = net_buf_simple_pull_u8(buf); BT_INFO("Output OOB Size: 0x%02x", output_size); if (output_size > 0x08) { BT_ERR("Invalid Output OOB size %d", output_size); goto fail; } - output_action = sys_get_be16(&data[6]); + output_action = net_buf_simple_pull_be16(buf); BT_INFO("Output OOB Action: 0x%04x", output_action); if (output_action > 0x1f) { BT_ERR("Invalid Output OOB action 0x%04x", output_action); @@ -1737,191 +1215,192 @@ static void prov_capabilities(const uint8_t idx, const uint8_t *data) } /* Provisioner select output action */ - if (prov->prov_input_num && output_size) { + if (bt_mesh_prov_get()->prov_input_num && output_size) { output_action = __builtin_ctz(output_action); } else { output_size = 0x0; output_action = 0x0; } - input_size = data[8]; + input_size = net_buf_simple_pull_u8(buf); BT_INFO("Input OOB Size: 0x%02x", input_size); if (input_size > 0x08) { BT_ERR("Invalid Input OOB size %d", input_size); goto fail; } - input_action = sys_get_be16(&data[9]); + input_action = net_buf_simple_pull_be16(buf); BT_INFO("Input OOB Action: 0x%04x", input_action); if (input_action > 0x0f) { BT_ERR("Invalid Input OOB action 0x%04x", input_action); goto fail; } - /* Make sure received pdu is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); + /* NOTE: If bit 1 of the OOB Type field is set to 1, bit 0 of + * the Algorithms field shall be set to 0 (case_1)and at least one of + * the conditions listed below shall be met: + * • Bit 0 of the OOB Type field is set to 1.(case_2) + * • The Output OOB Size field is not equal to 0x00.(case_3) + * • The Input OOB Size field is not equal to 0x00.(case_4) + * That means: + * !(case_1 && (case_2 || case_3 || case_4)) goto fail + * equals: + * !case1 || !(case_2 || case_3 || case_4) goto fail + */ + if (oob_type & BIT(PROV_ONLY_OOB_AUTH_SUPPORT)) { + if ((algorithms & BIT(PROV_ALG_P256_CMAC_AES128)) || + (!((oob_type & BIT(PROV_STATIC_OOB_AVAILABLE)) == 0x00 || + output_size == 0x00 || input_size == 0x00))) { + goto fail; + } } /* Provisioner select input action */ - if (prov->prov_output_num && input_size) { + if (bt_mesh_prov_get()->prov_output_num && input_size) { input_action = __builtin_ctz(input_action); } else { input_size = 0x0; input_action = 0x0; } - if (static_oob) { + if (oob_type & BIT(PROV_STATIC_OOB_AVAILABLE)) { /* if static oob is valid, just use static oob */ - auth_method = AUTH_METHOD_STATIC; - auth_action = 0x00; - auth_size = 0x00; + link->auth_method = AUTH_METHOD_STATIC; + link->auth_action = 0x00; + link->auth_size = 0x00; } else { if (!output_size && !input_size) { - auth_method = AUTH_METHOD_NO_OOB; - auth_action = 0x00; - auth_size = 0x00; + link->auth_method = AUTH_METHOD_NO_OOB; + link->auth_action = 0x00; + link->auth_size = 0x00; } else if (!output_size && input_size) { - auth_method = AUTH_METHOD_INPUT; - auth_action = (uint8_t)input_action; - auth_size = input_size; + link->auth_method = AUTH_METHOD_INPUT; + link->auth_action = (uint8_t)input_action; + link->auth_size = input_size; } else { - auth_method = AUTH_METHOD_OUTPUT; - auth_action = (uint8_t)output_action; - auth_size = output_size; + link->auth_method = AUTH_METHOD_OUTPUT; + link->auth_action = (uint8_t)output_action; + link->auth_size = output_size; } } /* Store provisioning capabilities value in conf_inputs */ - memcpy(&link[idx].conf_inputs[1], data, 11); + memcpy(&link->conf_inputs[1], data, 11); - prov_buf_init(&buf, PROV_START); - net_buf_simple_add_u8(&buf, prov->prov_algorithm); - net_buf_simple_add_u8(&buf, pub_key_oob); - net_buf_simple_add_u8(&buf, auth_method); - net_buf_simple_add_u8(&buf, auth_action); - net_buf_simple_add_u8(&buf, auth_size); + bt_mesh_prov_buf_init(&prov_buf, PROV_START); - memcpy(&link[idx].conf_inputs[12], &buf.data[1], 5); +#if CONFIG_BLE_MESH_PROV_EPA + if (algorithms & BIT(PROV_ALG_P256_HMAC_SHA256)) { + net_buf_simple_add_u8(&prov_buf, PROV_ALG_P256_HMAC_SHA256); + link->algorithm = PROV_ALG_P256_HMAC_SHA256; + } else { + net_buf_simple_add_u8(&prov_buf, PROV_ALG_P256_CMAC_AES128); + link->algorithm = PROV_ALG_P256_CMAC_AES128; + } +#else + net_buf_simple_add_u8(&prov_buf, PROV_ALG_P256_CMAC_AES128); + link->algorithm = PROV_ALG_P256_CMAC_AES128; +#endif - if (prov_send(idx, &buf)) { + net_buf_simple_add_u8(&prov_buf, link->public_key); + net_buf_simple_add_u8(&prov_buf, link->auth_method); + net_buf_simple_add_u8(&prov_buf, link->auth_action); + net_buf_simple_add_u8(&prov_buf, link->auth_size); + + memcpy(&link->conf_inputs[12], &prov_buf.data[1], 5); + + if (bt_mesh_prov_send(link, &prov_buf)) { BT_ERR("Failed to send Provisioning Start"); goto fail; } - link[idx].auth_method = auth_method; - link[idx].auth_action = auth_action; - link[idx].auth_size = auth_size; - - /** After prov start sent, use OOB to get remote public key. - * And we just follow the procedure in Figure 5.15 of Section - * 5.4.2.3 of Mesh Profile Spec. + /* After prov start is sent, use OOB to get remote public key. + * And we just follow the procedure in Figure 5.15 of Section + * 5.4.2.3 of Mesh Profile Spec. */ - if (pub_key_oob) { - if (prov->prov_pub_key_oob_cb(idx)) { - BT_ERR("Failed to notify input OOB Public Key"); - goto fail; - } + if (link->public_key == PROV_OOB_PUB_KEY && + bt_mesh_prov_get()->prov_pub_key_oob_cb(link - prov_links)) { + BT_ERR("Failed to notify input OOB Public Key"); + goto fail; } - /** If using PB-ADV, need to listen for transaction ack, - * after ack is received, provisioner can send public key. + /* If the link is used by PB-Remote, return here. Need to + * wait for Remote Provisioning PDU Outbound Report, then + * send Remote Provisioning PDU Send with Public Key. */ -#if defined(CONFIG_BLE_MESH_PB_ADV) - if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { - link[idx].expect_ack_for = PROV_START; + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + return; + } + +#if CONFIG_BLE_MESH_PB_ADV + /* If the link is used by PB-ADV, need to wait for the + * Transaction ACK for Provisioning Start. When ACK is + * received, we can send Provisioning Public Key. + */ + if (link - prov_links < CONFIG_BLE_MESH_PBA_SAME_TIME) { + link->expect_ack_for = PROV_START; return; } #endif /* CONFIG_BLE_MESH_PB_ADV */ - send_pub_key(idx, pub_key_oob); + send_pub_key(link); return; fail: - close_link(idx, CLOSE_REASON_FAILED); - return; + close_link(link, CLOSE_REASON_FAILED); } -static bt_mesh_output_action_t output_action(uint8_t action) -{ - switch (action) { - case OUTPUT_OOB_BLINK: - return BLE_MESH_BLINK; - case OUTPUT_OOB_BEEP: - return BLE_MESH_BEEP; - case OUTPUT_OOB_VIBRATE: - return BLE_MESH_VIBRATE; - case OUTPUT_OOB_NUMBER: - return BLE_MESH_DISPLAY_NUMBER; - case OUTPUT_OOB_STRING: - return BLE_MESH_DISPLAY_STRING; - default: - return BLE_MESH_NO_OUTPUT; - } -} - -static bt_mesh_input_action_t input_action(uint8_t action) -{ - switch (action) { - case INPUT_OOB_PUSH: - return BLE_MESH_PUSH; - case INPUT_OOB_TWIST: - return BLE_MESH_TWIST; - case INPUT_OOB_NUMBER: - return BLE_MESH_ENTER_NUMBER; - case INPUT_OOB_STRING: - return BLE_MESH_ENTER_STRING; - default: - return BLE_MESH_NO_INPUT; - } -} - -static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t size) +static int prov_auth(struct bt_mesh_prov_link *link, + uint8_t method, uint8_t action, + uint8_t size) { bt_mesh_output_action_t output = 0U; bt_mesh_input_action_t input = 0U; - - link[idx].auth = (uint8_t *)bt_mesh_calloc(PROV_AUTH_VAL_SIZE); - if (!link[idx].auth) { - BT_ERR("%s, Out of memory", __func__); - close_link(idx, CLOSE_REASON_FAILED); - return -ENOMEM; - } + uint8_t auth_size = PROV_AUTH_SIZE(link); switch (method) { case AUTH_METHOD_NO_OOB: if (action || size) { return -EINVAL; } - memset(link[idx].auth, 0, 16); + + memset(link->auth, 0, PROV_AUTH_MAX_SIZE); return 0; case AUTH_METHOD_STATIC: if (action || size) { return -EINVAL; } - memcpy(link[idx].auth + 16 - prov_ctx.static_oob_len, - prov_ctx.static_oob_val, prov_ctx.static_oob_len); - memset(link[idx].auth, 0, 16 - prov_ctx.static_oob_len); + + if (prov_ctx.static_oob_len > auth_size) { + memcpy(link->auth, prov_ctx.static_oob_val, auth_size); + } else { + memcpy(link->auth + auth_size - prov_ctx.static_oob_len, + prov_ctx.static_oob_val, prov_ctx.static_oob_len); + memset(link->auth, 0, auth_size - prov_ctx.static_oob_len); + } + return 0; case AUTH_METHOD_OUTPUT: /* Use auth_action to get device output action */ - output = output_action(action); + output = bt_mesh_prov_output_action(action); if (!output) { return -EINVAL; } - return prov->prov_input_num(AUTH_METHOD_OUTPUT, output, size, idx); + + return bt_mesh_prov_get()->prov_input_num(AUTH_METHOD_OUTPUT, output, + size, link - prov_links); case AUTH_METHOD_INPUT: /* Use auth_action to get device input action */ - input = input_action(action); + input = bt_mesh_prov_input_action(action); if (!input) { return -EINVAL; } /* Provisioner ouput number/string and wait for device's Provisioning Input Complete PDU */ - link[idx].expect = PROV_INPUT_COMPLETE; + link->expect = PROV_INPUT_COMPLETE; /* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly * selected AuthValue using all of the available bits, where permitted by the @@ -1953,10 +1432,11 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t } str[size] = '\0'; - memcpy(link[idx].auth, str, size); - memset(link[idx].auth + size, 0, PROV_AUTH_VAL_SIZE - size); + memcpy(link->auth, str, size); + memset(link->auth + size, 0, auth_size - size); - return prov->prov_output_num(AUTH_METHOD_INPUT, input, str, size, idx); + return bt_mesh_prov_get()->prov_output_num(AUTH_METHOD_INPUT, input, str, + size, link - prov_links); } else { uint32_t div[8] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; uint32_t num = 0U; @@ -1974,10 +1454,11 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t num %= div[size - 1]; } - sys_put_be32(num, &link[idx].auth[12]); - memset(link[idx].auth, 0, 12); + sys_put_be32(num, &link->auth[auth_size - 4]); + memset(link->auth, 0, auth_size - 4); - return prov->prov_output_num(AUTH_METHOD_INPUT, input, &num, size, idx); + return bt_mesh_prov_get()->prov_output_num(AUTH_METHOD_INPUT, input, &num, + size, link - prov_links); } default: @@ -1985,152 +1466,205 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t } } -static void send_confirm(const uint8_t idx) +static void send_confirm(struct bt_mesh_prov_link *link) { - PROV_BUF(buf, 17); uint8_t *conf = NULL; + uint8_t conf_salt_size = 0; + uint8_t conf_key_size = 0; + uint8_t rand_size = 0; + uint8_t conf_size = 0; - BT_DBG("ConfInputs[0] %s", bt_hex(link[idx].conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(link[idx].conf_inputs + 64, 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(link[idx].conf_inputs + 128, 17)); + conf_salt_size = PROV_CONF_SALT_SIZE(link); + conf_key_size = PROV_CONF_KEY_SIZE(link); + rand_size = PROV_RAND_SIZE(link); + conf_size = PROV_CONF_SIZE(link); - link[idx].conf_salt = (uint8_t *)bt_mesh_calloc(PROV_CONF_SALT_SIZE); - if (!link[idx].conf_salt) { - BT_ERR("%s, Out of memory", __func__); - goto fail; + PROV_BUF(buf, (conf_size + 1)); + + if (!bt_mesh_atomic_test_bit(link->flags, HAVE_DHKEY)) { + BT_WARN("Wait for generating DHKey"); + return; } - link[idx].conf_key = (uint8_t *)bt_mesh_calloc(PROV_CONF_KEY_SIZE); - if (!link[idx].conf_key) { - BT_ERR("%s, Out of memory", __func__); - goto fail; + BT_DBG("ConfInputs[0] %s", bt_hex(link->conf_inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(link->conf_inputs + 64, 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(link->conf_inputs + 128, 17)); + + if (link->algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf_salt(link->conf_inputs, link->conf_salt)) { + BT_ERR("Failed to generate confirmation salt"); + goto fail; + } + + if (bt_mesh_prov_conf_key(link->dhkey, link->conf_salt, link->conf_key)) { + BT_ERR("Failed to generate confirmation key"); + goto fail; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_salt_epa(link->conf_inputs, link->conf_salt)) { + BT_ERR("Failed to generate confirmation salt"); + goto fail; + } - if (bt_mesh_prov_conf_salt(link[idx].conf_inputs, link[idx].conf_salt)) { - BT_ERR("Failed to generate confirmation salt"); - goto fail; + if (bt_mesh_prov_conf_key_epa(link->dhkey, link->auth, link->conf_salt, link->conf_key)) { + BT_ERR("Failed to generate confirmation key"); + goto fail; + } } +#endif - BT_DBG("ConfirmationSalt: %s", bt_hex(link[idx].conf_salt, 16)); - - if (bt_mesh_prov_conf_key(link[idx].dhkey, link[idx].conf_salt, link[idx].conf_key)) { - BT_ERR("Failed to generate confirmation key"); - goto fail; - } - - BT_DBG("ConfirmationKey: %s", bt_hex(link[idx].conf_key, 16)); - - link[idx].rand = bt_mesh_calloc(PROV_RANDOM_SIZE); - if (!link[idx].rand) { - BT_ERR("%s, Out of memory", __func__); - goto fail; - } - - if (bt_mesh_rand(link[idx].rand, PROV_RANDOM_SIZE)) { + if (bt_mesh_rand(link->rand, rand_size)) { BT_ERR("Failed to generate random number"); goto fail; } - BT_DBG("LocalRandom: %s", bt_hex(link[idx].rand, 16)); + BT_DBG("ConfirmationSalt: %s", bt_hex(link->conf_salt, conf_salt_size)); + BT_DBG("ConfirmationKey: %s", bt_hex(link->conf_key, conf_key_size)); + BT_DBG("LocalRandom: %s", bt_hex(link->rand, rand_size)); - prov_buf_init(&buf, PROV_CONFIRM); + bt_mesh_prov_buf_init(&buf, PROV_CONFIRM); - conf = net_buf_simple_add(&buf, 16); + conf = net_buf_simple_add(&buf, conf_size); - if (bt_mesh_prov_conf(link[idx].conf_key, link[idx].rand, - link[idx].auth, conf)) { - BT_ERR("Failed to generate confirmation value"); - goto fail; + if (link->algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf(link->conf_key, link->rand, link->auth, conf)) { + BT_ERR("Failed to generate confirmation value"); + goto fail; + } } - - link[idx].local_conf = bt_mesh_calloc(PROV_CONFIRM_SIZE); - if (!link[idx].local_conf) { - BT_ERR("%s, Out of memory", __func__); - goto fail; +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_epa(link->conf_key, link->rand, conf)) { + BT_ERR("Failed to generate confirmation value"); + goto fail; + } } +#endif - memcpy(link[idx].local_conf, conf, PROV_CONFIRM_SIZE); + memcpy(link->local_conf, conf, conf_size); - if (prov_send(idx, &buf)) { + if (bt_mesh_prov_send(link, &buf)) { BT_ERR("Failed to send Provisioning Confirm"); goto fail; } - link[idx].expect = PROV_CONFIRM; + link->expect = PROV_CONFIRM; return; fail: - close_link(idx, CLOSE_REASON_FAILED); - return; + close_link(link, CLOSE_REASON_FAILED); } int bt_mesh_provisioner_set_oob_input_data(const uint8_t idx, const uint8_t *val, bool num_flag) { - /** This function should be called in the prov_input_num - * callback, after the data output by device has been - * input by provisioner. - * Paramter size is used to indicate the length of data - * indicated by Pointer val, for example, if device output - * data is 12345678(decimal), the data in auth value will - * be 0xBC614E. - * Parameter num_flag is used to indicate whether the value - * input by provisioner is number or string. + /* This function should be called in the prov_input_num callback, + * after the data output by device has been input by Provisioner. + * + * "val" is the auth value, for example, if device output data is + * 12345678(decimal), the data in auth value will be 0xBC614E. + * + * "num_flag" is used to indicate whether the value input by + * Provisioner is number or string. */ - if (!link[idx].auth) { - BT_ERR("Invalid link auth"); + struct bt_mesh_prov_link *link = NULL; + uint8_t auth_size = 0; + + if (idx >= ARRAY_SIZE(prov_links) || val == NULL) { + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_INFO("Link idx %d, type %s", idx, num_flag ? "number" : "string"); + link = &prov_links[idx]; + auth_size = PROV_AUTH_SIZE(link); - memset(link[idx].auth, 0, 16); - if (num_flag) { - /* Provisioner inputs number */ - sys_memcpy_swap(link[idx].auth + 12, val, sizeof(uint32_t)); - } else { - /* Provisioner inputs string */ - memcpy(link[idx].auth, val, link[idx].auth_size); + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) || + link->auth_method != AUTH_METHOD_OUTPUT) { + BT_ERR("Not ready for Output OOB, link idx %d", idx); + return -EIO; } - send_confirm(idx); + memset(link->auth, 0, PROV_AUTH_MAX_SIZE); + + if (num_flag) { + /* Provisioner inputs number */ + sys_memcpy_swap(link->auth + auth_size - 4, val, sizeof(uint32_t)); + } else { + /* Provisioner inputs string */ + memcpy(link->auth, val, link->auth_size); + } + + BT_INFO("Output OOB, idx %d, type %s, auth %s", idx, + num_flag ? "number" : "string", bt_hex(link->auth, auth_size)); + + /* If the link is used by PB-Remote, and we are + * waiting for Remote Provisioning PDU Outbound + * Report for Public Key, return here. + */ + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + if (bt_mesh_atomic_test_bit(link->flags, WAIT_PK_OBR)) { + BT_INFO("PB-Remote, wait for outbound report for public key"); + /* Use SEND_CONFIRM flag to indicate that Remote + * Provisioning PDU Send with confirmation could + * be sent when the Remote Provisioning Outbound + * Report for Public Key is received. + */ + bt_mesh_atomic_set_bit(link->flags, SEND_CONFIRM); + return 0; + } + } + + send_confirm(link); + return 0; } int bt_mesh_provisioner_set_oob_output_data(const uint8_t idx, const uint8_t *num, uint8_t size, bool num_flag) { - /** This function should be called in the prov_output_num - * callback, after the data has been output by provisioner. - * Parameter size is used to indicate the length of data - * indicated by Pointer num, for example, if provisioner - * output data is 12345678(decimal), the data in auth value - * will be 0xBC614E. - * Parameter num_flag is used to indicate whether the value - * output by provisioner is number or string. + /* This function should be called in the prov_output_num callback, + * after the data has been output by Provisioner. + * + * "size" is used to indicate the length of "num", for example, if + * Provisioner output data is 12345678(decimal), the data in auth + * value will be 0xBC614E. + * + * "num_flag" is used to indicate whether the value output by + * Provisioner is number or string. */ - if (num == NULL || size > BLE_MESH_PROV_INPUT_OOB_MAX_LEN) { + struct bt_mesh_prov_link *link = NULL; + uint8_t auth_size = 0; + + if (idx >= ARRAY_SIZE(prov_links) || num == NULL || + size > BLE_MESH_PROV_INPUT_OOB_MAX_LEN) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - if (!link[idx].auth) { - BT_ERR("Invalid link auth"); - return -EINVAL; + link = &prov_links[idx]; + auth_size = PROV_AUTH_SIZE(link); + + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) || + link->auth_method != AUTH_METHOD_INPUT) { + BT_ERR("Not ready for Input OOB, link idx %d", idx); + return -EIO; } - BT_INFO("Link idx %d, type %s", idx, num_flag ? "number" : "string"); + memset(link->auth, 0, PROV_AUTH_MAX_SIZE); if (num_flag) { /* Provisioner output number */ - memset(link[idx].auth, 0, 16); - sys_memcpy_swap(link[idx].auth + 16 - size, num, size); + sys_memcpy_swap(link->auth + auth_size - size, num, size); } else { /* Provisioner output string */ - memset(link[idx].auth, 0, 16); - memcpy(link[idx].auth, num, size); + memcpy(link->auth, num, size); } - link[idx].expect = PROV_INPUT_COMPLETE; + BT_INFO("Input OOB, idx %d, type %s, auth %s", idx, + num_flag ? "number" : "string", bt_hex(link->auth, auth_size)); + + link->expect = PROV_INPUT_COMPLETE; return 0; } @@ -2138,234 +1672,270 @@ int bt_mesh_provisioner_set_oob_output_data(const uint8_t idx, const uint8_t *nu int bt_mesh_provisioner_read_oob_pub_key(const uint8_t idx, const uint8_t pub_key_x[32], const uint8_t pub_key_y[32]) { - if (!link[idx].conf_inputs) { - BT_ERR("Invalid link conf_inputs"); + struct bt_mesh_prov_link *link = NULL; + + if (idx >= ARRAY_SIZE(prov_links) || pub_key_x == NULL || pub_key_y == NULL) { + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + link = &prov_links[idx]; + + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) || + link->public_key != PROV_OOB_PUB_KEY) { + BT_ERR("Not ready for OOB Public Key, link idx %d", idx); + return -EIO; + } + + BT_INFO("OOB Public Key, idx %d, x %s, y %s", idx, + bt_hex(pub_key_x, 32), bt_hex(pub_key_y, 32)); + /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(&link[idx].conf_inputs[81], pub_key_x, 32); - sys_memcpy_swap(&link[idx].conf_inputs[81] + 32, pub_key_y, 32); + sys_memcpy_swap(&link->conf_inputs[81], pub_key_x, 32); + sys_memcpy_swap(&link->conf_inputs[81] + 32, pub_key_y, 32); - bt_mesh_atomic_set_bit(link[idx].flags, REMOTE_PUB_KEY); + bt_mesh_atomic_set_bit(link->flags, REMOTE_PUB_KEY); - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, WAIT_GEN_DHKEY)) { - prov_gen_dh_key(idx); + if (bt_mesh_atomic_test_and_clear_bit(link->flags, WAIT_GEN_DHKEY)) { + prov_gen_dh_key(link); } return 0; } -static void prov_dh_key_cb(const uint8_t key[32], const uint8_t idx) -{ - BT_DBG("%p", key); - - if (!key) { - BT_ERR("Failed to generate DHKey"); - goto fail; - } - - link[idx].dhkey = (uint8_t *)bt_mesh_calloc(PROV_DH_KEY_SIZE); - if (!link[idx].dhkey) { - BT_ERR("%s, Out of memory", __func__); - goto fail; - } - sys_memcpy_swap(link[idx].dhkey, key, 32); - - BT_DBG("DHkey: %s", bt_hex(link[idx].dhkey, 32)); - - bt_mesh_atomic_set_bit(link[idx].flags, HAVE_DHKEY); - - /** After dhkey is generated, if auth_method is No OOB or - * Static OOB, provisioner can start to send confirmation. - * If output OOB is used by the device, provisioner need - * to watch out the output number and input it as auth_val. - * If input OOB is used by the device, provisioner need - * to output a value, and wait for prov input complete pdu. - */ - if (prov_auth(idx, link[idx].auth_method, - link[idx].auth_action, link[idx].auth_size) < 0) { - BT_ERR("Failed to authenticate"); - goto fail; - } - if (link[idx].auth_method == AUTH_METHOD_OUTPUT || - link[idx].auth_method == AUTH_METHOD_INPUT) { - return; - } - - if (link[idx].expect != PROV_INPUT_COMPLETE) { - send_confirm(idx); - } - return; - -fail: - close_link(idx, CLOSE_REASON_FAILED); - return; -} - -static void prov_gen_dh_key(const uint8_t idx) +static void prov_gen_dh_key(struct bt_mesh_prov_link *link) { uint8_t pub_key[64] = {0}; + uint8_t dhkey[32] = {0}; - /* Copy device public key in little-endian for bt_mesh_dh_key_gen(). + /* Copy public key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - sys_memcpy_swap(&pub_key[0], &link[idx].conf_inputs[81], 32); - sys_memcpy_swap(&pub_key[32], &link[idx].conf_inputs[113], 32); + sys_memcpy_swap(&pub_key[0], &link->conf_inputs[81], 32); + sys_memcpy_swap(&pub_key[32], &link->conf_inputs[113], 32); - if (bt_mesh_dh_key_gen(pub_key, prov_dh_key_cb, idx)) { + if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Failed to generate DHKey"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } + + sys_memcpy_swap(link->dhkey, dhkey, 32); + + BT_DBG("DHKey: %s", bt_hex(link->dhkey, 32)); + + bt_mesh_atomic_set_bit(link->flags, HAVE_DHKEY); + + /* After DHKey is generated, if auth_method is No OOB or + * Static OOB, Provisioner can start to send confirmation. + * + * If output OOB is used by the device, Provisioner needs + * to watch out the output number and input it as auth_val. + * + * If input OOB is used by the device, Provisioner needs + * to output a value, and wait for prov input complete pdu. + */ + if (prov_auth(link, link->auth_method, + link->auth_action, link->auth_size)) { + BT_ERR("Failed to authenticate"); + close_link(link, CLOSE_REASON_FAILED); + return; + } + + /* If authentication method is Output OOB, wait for the + * authentication value; + * If authentication method is Input OOB, wait for the + * Provisioning Input Complete. + */ + if (link->auth_method == AUTH_METHOD_OUTPUT || + link->auth_method == AUTH_METHOD_INPUT) { + return; + } + + /* This function will be invoked when the Device Public + * Key is received. + * If the link is used by PB-Remote, we can decide the + * next move depends on the Public Key type. + */ + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + if (bt_mesh_atomic_test_bit(link->flags, WAIT_PK_OBR)) { + BT_INFO("PB-Remote, wait for outbound report for public key"); + /* Use SEND_CONFIRM flag to indicate that Remote + * Provisioning PDU Send with confirmation could + * be sent when the Remote Provisioning Outbound + * Report for Public Key is received. + */ + bt_mesh_atomic_set_bit(link->flags, SEND_CONFIRM); + return; + } + } + + /* If the link is not used by PB-Remote, send confirmation here. + * If the link is used by PB-Remote: + * a) If No OOB Public Key is used, which means Device Public + * Key is received, and WAIT_PK_OBR will not be set, send + * Remote Provisioning PDU Send with confirmation here. + * b) If OOB Public Key is used, which means Device Public Key + * has been input through OOB, and WAIT_PK_OBR is cleared + * (i.e. Remote Provisioning Outbound Report for Public Key + * is received), send Remote Provisioning PDU Send with + * confirmation here. + * Note: + * No need to check if the next expect pdu is Provisioning + * Input Complete, because if the authentication method is + * Output OOB or Input OOB, it will directly return above. + */ + if (link->expect != PROV_INPUT_COMPLETE) { + send_confirm(link); + } } -static void send_pub_key(const uint8_t idx, uint8_t oob) +static void send_pub_key(struct bt_mesh_prov_link *link) { - PROV_BUF(buf, 65); const uint8_t *key = NULL; + PROV_BUF(buf, 65); key = bt_mesh_pub_key_get(); if (!key) { BT_ERR("No public key available"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); - - prov_buf_init(&buf, PROV_PUB_KEY); + bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); /* Store provisioner public key value in conf_inputs */ - memcpy(&link[idx].conf_inputs[17], &buf.data[1], 64); + memcpy(&link->conf_inputs[17], &buf.data[1], 64); - if (prov_send(idx, &buf)) { + if (bt_mesh_prov_send(link, &buf)) { BT_ERR("Failed to send Provisioning Public Key"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - if (!oob) { - link[idx].expect = PROV_PUB_KEY; - } else { - /** Have already got device public key. If next is to - * send confirm(not wait for input complete), need to - * wait for transactiona ack for public key then send - * provisioning confirm pdu. - */ -#if defined(CONFIG_BLE_MESH_PB_ADV) - if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { - link[idx].expect_ack_for = PROV_PUB_KEY; - return; - } + if (link->public_key == PROV_NO_OOB_PUB_KEY) { + link->expect = PROV_PUB_KEY; + return; + } + +#if CONFIG_BLE_MESH_PB_ADV + /* If the link is used by PB-ADV and OOB Public Key is + * used, need to wait for the Transaction ACK for Public + * Key. When ACK is received, we can start to generate + * DHKey and send Provisioning Confirm. + */ + if (!bt_mesh_atomic_test_bit(link->flags, PB_REMOTE) && + (link - prov_links < CONFIG_BLE_MESH_PBA_SAME_TIME)) { + link->expect_ack_for = PROV_PUB_KEY; + return; + } #endif /* CONFIG_BLE_MESH_PB_ADV */ - /* If remote public key has been read, then start to generate DHkey, - * otherwise wait for device oob public key. + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + /* If OOB Public Key is used, try to generate DHKey, + * and we need to wait for the Remote Provisioning + * Outbound Report for Public Key, then we can send + * Remote Provisioning PDU Send with confirmation. */ - if (bt_mesh_atomic_test_bit(link[idx].flags, REMOTE_PUB_KEY)) { - prov_gen_dh_key(idx); - } else { - bt_mesh_atomic_set_bit(link[idx].flags, WAIT_GEN_DHKEY); - } + bt_mesh_atomic_set_bit(link->flags, WAIT_PK_OBR); + } + + /* If OOB Public Key has been read, start to generate + * DHKey; otherwise need to wait for OOB Public Key. + */ + if (bt_mesh_atomic_test_bit(link->flags, REMOTE_PUB_KEY)) { + prov_gen_dh_key(link); + } else { + bt_mesh_atomic_set_bit(link->flags, WAIT_GEN_DHKEY); } } -static void prov_pub_key(const uint8_t idx, const uint8_t *data) +static void prov_pub_key(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + BT_DBG("Remote Public Key: %s", bt_hex(buf->data, 64)); - /* Make sure received pdu is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } - - memcpy(&link[idx].conf_inputs[81], data, 64); - - if (!bt_mesh_atomic_test_bit(link[idx].flags, LOCAL_PUB_KEY)) { - /* Clear retransmit timer */ -#if defined(CONFIG_BLE_MESH_PB_ADV) - prov_clear_tx(idx); -#endif - bt_mesh_atomic_set_bit(link[idx].flags, REMOTE_PUB_KEY); - BT_WARN("Waiting for local public key"); + /* Check public key using the following rules: + * 1. X > 0, Y > 0 + * 2. X > 0, Y = 0 + * 3. X = 0, Y = 0 + */ + if (!bt_mesh_check_public_key(buf->data)) { + BT_ERR("Invalid public key"); + close_link(link, CLOSE_REASON_FAILED); return; } - prov_gen_dh_key(idx); + memcpy(&link->conf_inputs[81], buf->data, 64); + + prov_gen_dh_key(link); } -static void prov_input_complete(const uint8_t idx, const uint8_t *data) +static void prov_input_complete(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - /* Make sure received pdu is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } + /* TODO: + * Add a flag to make sure authentication value has been set + * when using Input OOB. + * + * Currently the authentication value is generated and set + * internally, so this should works fine at this moment. + */ /* Provisioner receives input complete and send confirm */ - send_confirm(idx); + send_confirm(link); } -static void prov_confirm(const uint8_t idx, const uint8_t *data) +static void prov_confirm(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - PROV_BUF(buf, 17); + uint8_t conf_size = PROV_CONF_SIZE(link); - BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + PROV_BUF(prov_buf, conf_size + 1); + + BT_DBG("Remote Confirm: %s", bt_hex(buf->data, conf_size)); /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners * restrict the authentication procedure and not accept provisioning random and * provisioning confirmation numbers from a remote peer that are the same as those * selected by the local device (CVE-2020-26560). */ - if (!memcmp(data, link[idx].local_conf, 16)) { + if (!memcmp(buf->data, link->local_conf, conf_size)) { BT_ERR("Confirmation value is identical to ours, rejecting."); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - /* Make sure received pdu is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } + memcpy(link->conf, buf->data, conf_size); - link[idx].conf = (uint8_t *)bt_mesh_calloc(PROV_CONFIRM_SIZE); - if (!link[idx].conf) { - BT_ERR("%s, Out of memory", __func__); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - - memcpy(link[idx].conf, data, 16); - - if (!bt_mesh_atomic_test_bit(link[idx].flags, HAVE_DHKEY)) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - prov_clear_tx(idx); + if (!bt_mesh_atomic_test_bit(link->flags, HAVE_DHKEY)) { +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_prov_clear_tx(link, true); #endif - bt_mesh_atomic_set_bit(link[idx].flags, SEND_CONFIRM); + bt_mesh_atomic_set_bit(link->flags, SEND_CONFIRM); } - prov_buf_init(&buf, PROV_RANDOM); + bt_mesh_prov_buf_init(&prov_buf, PROV_RANDOM); - net_buf_simple_add_mem(&buf, link[idx].rand, 16); + net_buf_simple_add_mem(&prov_buf, link->rand, PROV_RAND_SIZE(link)); - if (prov_send(idx, &buf)) { + if (bt_mesh_prov_send(link, &prov_buf)) { BT_ERR("Failed to send Provisioning Random"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - link[idx].expect = PROV_RANDOM; + link->expect = PROV_RANDOM; } -static void send_prov_data(const uint8_t idx) +static void send_prov_data(struct bt_mesh_prov_link *link) { - PROV_BUF(buf, 34); uint16_t prev_addr = BLE_MESH_ADDR_UNASSIGNED; uint16_t max_addr = BLE_MESH_ADDR_UNASSIGNED; struct bt_mesh_node *node = NULL; @@ -2373,20 +1943,23 @@ static void send_prov_data(const uint8_t idx) uint8_t session_key[16] = {0}; uint8_t nonce[13] = {0}; uint8_t pdu[25] = {0}; + PROV_BUF(buf, 34); int err = 0; - err = bt_mesh_session_key(link[idx].dhkey, link[idx].prov_salt, session_key); + err = bt_mesh_session_key(link->dhkey, link->prov_salt, session_key); if (err) { BT_ERR("Failed to generate session key"); goto fail; } + BT_DBG("SessionKey: %s", bt_hex(session_key, 16)); - err = bt_mesh_prov_nonce(link[idx].dhkey, link[idx].prov_salt, nonce); + err = bt_mesh_prov_nonce(link->dhkey, link->prov_salt, nonce); if (err) { BT_ERR("Failed to generate session nonce"); goto fail; } + BT_DBG("Nonce: %s", bt_hex(nonce, 13)); /* Assign provisioning data for the device. Currently all provisioned devices @@ -2399,24 +1972,25 @@ static void send_prov_data(const uint8_t idx) BT_ERR("No NetKey for fast provisioning"); goto fail; } + memcpy(pdu, netkey, 16); sys_put_be16(prov_ctx.fast_prov.net_idx, &pdu[16]); - pdu[18] = prov_ctx.fast_prov.flags; - sys_put_be32(prov_ctx.fast_prov.iv_index, &pdu[19]); + pdu[18] = get_net_flags(prov_ctx.fast_prov.net_idx); + sys_put_be32(bt_mesh.iv_index, &pdu[19]); } else { - netkey = bt_mesh_provisioner_net_key_get(prov_ctx.curr_net_idx); + netkey = bt_mesh_provisioner_net_key_get(prov_ctx.net_idx); if (!netkey) { BT_ERR("No NetKey for provisioning data"); goto fail; } + memcpy(pdu, netkey, 16); - sys_put_be16(prov_ctx.curr_net_idx, &pdu[16]); - pdu[18] = prov_ctx.curr_flags; - sys_put_be32(prov_ctx.curr_iv_index, &pdu[19]); + sys_put_be16(prov_ctx.net_idx, &pdu[16]); + pdu[18] = get_net_flags(prov_ctx.net_idx); + sys_put_be32(bt_mesh.iv_index, &pdu[19]); } - /** - * The Provisioner must not reuse unicast addresses that have been + /* The Provisioner must not reuse unicast addresses that have been * allocated to a device and sent in a Provisioning Data PDU until * the Provisioner receives an Unprovisioned Device beacon or * Service Data for the Mesh Provisioning Service from that same @@ -2424,38 +1998,49 @@ static void send_prov_data(const uint8_t idx) */ /* Check if this device is a re-provisioned device */ - node = bt_mesh_provisioner_get_node_with_uuid(link[idx].uuid); + node = bt_mesh_provisioner_get_node_with_uuid(link->uuid); if (node) { - if (link[idx].element_num <= node->element_num) { - /** - * If the device is provisioned before, but the element number of + if (link->element_num <= node->element_num && + link->pb_remote_nppi != NPPI_NODE_ADDR_REFRESH) { + /* If the device is provisioned before, but the element number of * the device is bigger now, then we treat it as a new device. */ prev_addr = node->unicast_addr; } - bt_mesh_provisioner_remove_node(link[idx].uuid); + + /* If the link is a normal provisioning link, or it is a PB-Remote one + * and not used by NPPI, then we could remove the device. + */ + if (!bt_mesh_atomic_test_bit(link->flags, PB_REMOTE) || + link->pb_remote_nppi == NPPI_UNKNOWN) { + bt_mesh_provisioner_remove_node(link->uuid); + } } - max_addr = FAST_PROV_ENABLE() ? prov_ctx.fast_prov.unicast_addr_max : PROV_MAX_ADDR_TO_ASSIGN; + max_addr = FAST_PROV_ENABLE() ? prov_ctx.fast_prov.unicast_addr_max : UNICAST_ADDR_LIMIT; if (BLE_MESH_ADDR_IS_UNICAST(prev_addr)) { + /* For Node Address Refresh, the previous node address + * shall not be used. + */ sys_put_be16(prev_addr, &pdu[23]); - link[idx].unicast_addr = prev_addr; + link->unicast_addr = prev_addr; } else { uint16_t alloc_addr = BLE_MESH_ADDR_UNASSIGNED; - if (BLE_MESH_ADDR_IS_UNICAST(link[idx].assign_addr)) { - alloc_addr = link[idx].assign_addr; + if (BLE_MESH_ADDR_IS_UNICAST(link->assign_addr)) { + alloc_addr = link->assign_addr; } else { /* If this device to be provisioned is a new device */ - if (prov_ctx.curr_alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { + if (prov_ctx.alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("Not enough unicast address to be allocated"); goto fail; } - alloc_addr = prov_ctx.curr_alloc_addr; + + alloc_addr = prov_ctx.alloc_addr; } - if (alloc_addr + link[idx].element_num - 1 > max_addr) { + if (alloc_addr + link->element_num - 1 > max_addr) { BT_ERR("Not enough unicast address for the device"); goto fail; } @@ -2464,16 +2049,16 @@ static void send_prov_data(const uint8_t idx) * address of other nodes. And make sure the address is not identical with * any unicast address of Provisioner. */ - if (bt_mesh_provisioner_check_is_addr_dup(alloc_addr, link[idx].element_num, true)) { + if (bt_mesh_provisioner_check_is_addr_dup(alloc_addr, link->element_num, true)) { BT_ERR("Duplicate assigned address 0x%04x", alloc_addr); goto fail; } sys_put_be16(alloc_addr, &pdu[23]); - link[idx].unicast_addr = alloc_addr; + link->unicast_addr = alloc_addr; } - prov_buf_init(&buf, PROV_DATA); + bt_mesh_prov_buf_init(&buf, PROV_DATA); err = bt_mesh_prov_encrypt(session_key, nonce, pdu, net_buf_simple_add(&buf, 33)); if (err) { @@ -2481,327 +2066,298 @@ static void send_prov_data(const uint8_t idx) goto fail; } - if (prov_send(idx, &buf)) { + if (bt_mesh_prov_send(link, &buf)) { BT_ERR("Failed to send Provisioning Data"); goto fail; } - /** - * We update the next unicast address to be allocated here because if + /* We update the next unicast address to be allocated here because if * Provisioner is provisioning two devices at the same time, we need * to assign the unicast address for them correctly. Hence we should - * not update the prov_ctx.curr_alloc_addr after the proper provisioning + * not update the prov_ctx.alloc_addr after the proper provisioning * complete pdu is received. */ if (!BLE_MESH_ADDR_IS_UNICAST(prev_addr)) { - if (BLE_MESH_ADDR_IS_UNICAST(link[idx].assign_addr)) { + if (BLE_MESH_ADDR_IS_UNICAST(link->assign_addr)) { /* Even if the unicast address of the node is assigned by the - * application, we will also update the prov_ctx.curr_alloc_addr + * application, we will also update the prov_ctx.alloc_addr * here, in case Users use the two methods together (i.e. allocate * the unicast address for the node internally and assign the * unicast address for the node from application). */ - if (prov_ctx.curr_alloc_addr < link[idx].assign_addr + link[idx].element_num) { - prov_ctx.curr_alloc_addr = link[idx].assign_addr + link[idx].element_num; + if (prov_ctx.alloc_addr < link->assign_addr + link->element_num) { + prov_ctx.alloc_addr = link->assign_addr + link->element_num; } } else { - prov_ctx.curr_alloc_addr += link[idx].element_num; - if (prov_ctx.curr_alloc_addr > max_addr) { + prov_ctx.alloc_addr += link->element_num; + if (prov_ctx.alloc_addr > max_addr) { /* No unicast address will be used for further provisioning */ - prov_ctx.curr_alloc_addr = BLE_MESH_ADDR_UNASSIGNED; + prov_ctx.alloc_addr = BLE_MESH_ADDR_UNASSIGNED; } } + /* Store the available unicast address range to flash */ if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.curr_alloc_addr); + bt_mesh_store_prov_info(prov_ctx.primary_addr, prov_ctx.alloc_addr); } } if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && FAST_PROV_ENABLE()) { - link[idx].ki_flags = prov_ctx.fast_prov.flags; - link[idx].iv_index = prov_ctx.fast_prov.iv_index; + link->kri_flags = get_net_flags(prov_ctx.fast_prov.net_idx); } else { - link[idx].ki_flags = prov_ctx.curr_flags; - link[idx].iv_index = prov_ctx.curr_iv_index; + link->kri_flags = get_net_flags(prov_ctx.net_idx); } - link[idx].expect = PROV_COMPLETE; + link->expect = PROV_COMPLETE; return; fail: - close_link(idx, CLOSE_REASON_FAILED); - return; + close_link(link, CLOSE_REASON_FAILED); } -static void prov_random(const uint8_t idx, const uint8_t *data) +static void prov_random(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - uint8_t conf_verify[16] = {0}; + uint8_t conf_verify[32] = {0}; + uint8_t rand_size = 0; + uint8_t *data = buf->data; - BT_DBG("Remote Random: %s", bt_hex(data, 16)); + rand_size = PROV_RAND_SIZE(link); + + BT_DBG("Remote Random: %s", bt_hex(data, rand_size)); /* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners * restrict the authentication procedure and not accept provisioning random and * provisioning confirmation numbers from a remote peer that are the same as those * selected by the local device (CVE-2020-26560). */ - if (!memcmp(data, link[idx].rand, 16)) { + if (!memcmp(data, link->rand, rand_size)) { BT_ERR("Random value is identical to ours, rejecting."); goto fail; } - if (bt_mesh_prov_conf(link[idx].conf_key, data, link[idx].auth, conf_verify)) { - BT_ERR("Failed to calculate confirmation verification"); - goto fail; + if (link->algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_conf(link->conf_key, data, link->auth, conf_verify)) { + BT_ERR("Failed to calculate confirmation verification"); + goto fail; + } } +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_conf_epa(link->conf_key, data, conf_verify)) { + BT_ERR("Failed to calculate confirmation verification"); + goto fail; + } + } +#endif - if (memcmp(conf_verify, link[idx].conf, 16)) { + if (memcmp(conf_verify, link->conf, PROV_CONF_SIZE(link))) { BT_ERR("Invalid confirmation value"); - BT_DBG("Received: %s", bt_hex(link[idx].conf, 16)); - BT_DBG("Calculated: %s", bt_hex(conf_verify, 16)); + BT_ERR("Received: %s", bt_hex(link->conf, PROV_CONF_SIZE(link))); + BT_ERR("Calculated: %s", bt_hex(conf_verify, PROV_CONF_SIZE(link))); goto fail; } - /*Verify received confirm is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } - - /** After provisioner receives provisioning random from device, - * and successfully check the confirmation, the following - * should be done: - * 1. bt_mesh_calloc memory for prov_salt - * 2. calculate prov_salt - * 3. prepare provisioning data and send + /* After Provisioner received Provisioning Random PDU from + * the device, and successfully checked the confirmation, + * the following needs to be done: + * - Calculate prov_salt + * - Prepare and send Provisioning Data PDU */ - link[idx].prov_salt = (uint8_t *)bt_mesh_calloc(PROV_PROV_SALT_SIZE); - if (!link[idx].prov_salt) { - BT_ERR("%s, Out of memory", __func__); - goto fail; + if (link->algorithm == PROV_ALG_P256_CMAC_AES128) { + if (bt_mesh_prov_salt(link->conf_salt, link->rand, data, + link->prov_salt)) { + BT_ERR("Failed to generate ProvisioningSalt"); + goto fail; + } } - - if (bt_mesh_prov_salt(link[idx].conf_salt, link[idx].rand, data, - link[idx].prov_salt)) { - BT_ERR("Failed to generate ProvisioningSalt"); - goto fail; +#if CONFIG_BLE_MESH_PROV_EPA + else { + if (bt_mesh_prov_salt_epa(link->conf_salt, link->rand, data, + link->prov_salt)) { + BT_ERR("Failed to generate ProvisioningSalt"); + goto fail; + } } +#endif - BT_DBG("ProvisioningSalt: %s", bt_hex(link[idx].prov_salt, 16)); + BT_DBG("ProvisioningSalt: %s", bt_hex(link->prov_salt, PROV_CONF_SALT_SIZE(link))); - send_prov_data(idx); + send_prov_data(link); return; fail: - close_link(idx, CLOSE_REASON_FAILED); - return; + close_link(link, CLOSE_REASON_FAILED); } -static void prov_complete(const uint8_t idx, const uint8_t *data) +static void prov_complete(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { uint8_t device_key[16] = {0}; uint16_t net_idx = 0U; uint16_t index = 0U; + bool nppi = false; int err = 0; int i; - /* Make sure received pdu is ok and cancel the timeout timer */ - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); - } - - err = bt_mesh_dev_key(link[idx].dhkey, link[idx].prov_salt, device_key); + err = bt_mesh_dev_key(link->dhkey, link->prov_salt, device_key); if (err) { BT_ERR("Failed to generate device key"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV) && FAST_PROV_ENABLE()) { net_idx = prov_ctx.fast_prov.net_idx; } else { - net_idx = prov_ctx.curr_net_idx; + net_idx = prov_ctx.net_idx; } - err = bt_mesh_provisioner_provision(&link[idx].addr, link[idx].uuid, link[idx].oob_info, - link[idx].unicast_addr, link[idx].element_num, net_idx, - link[idx].ki_flags, link[idx].iv_index, device_key, &index); + + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE) && + link->pb_remote_nppi != NPPI_UNKNOWN) { + nppi = true; + } + + err = bt_mesh_provisioner_provision(&link->addr, link->uuid, link->oob_info, + link->unicast_addr, link->element_num, + net_idx, link->kri_flags, bt_mesh.iv_index, + device_key, &index, nppi); if (err) { BT_ERR("Failed to store node info"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - if (prov->prov_complete) { - prov->prov_complete(index, link[idx].uuid, link[idx].unicast_addr, - link[idx].element_num, net_idx); +#if CONFIG_BLE_MESH_RPR_CLI + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + /* TODO: + * If NPPI info is activated after RP Link Close with + * a success reason is received, then this could be + * removed. + */ + if (link->pb_remote_nppi == NPPI_NODE_ADDR_REFRESH) { + bt_mesh_rpr_cli_node_addr_update(link); + } + + /* Notify to the application layer that provisioning + * is completed successfully. + */ + bt_mesh_rpr_cli_prov_complete(link, index, net_idx); + + close_link(link, CLOSE_REASON_SUCCESS); + return; + } +#endif /* CONFIG_BLE_MESH_RPR_CLI */ + + if (bt_mesh_prov_get()->prov_complete) { + bt_mesh_prov_get()->prov_complete(index, link->uuid, link->unicast_addr, + link->element_num, net_idx); } /* Find if the device is in the device queue */ for (i = 0; i < ARRAY_SIZE(unprov_dev); i++) { - if (!memcmp(unprov_dev[i].uuid, link[idx].uuid, 16) && + if (!memcmp(unprov_dev[i].uuid, link->uuid, 16) && (unprov_dev[i].flags & RM_AFTER_PROV)) { memset(&unprov_dev[i], 0, sizeof(struct unprov_dev_queue)); break; } } - close_link(idx, CLOSE_REASON_SUCCESS); + close_link(link, CLOSE_REASON_SUCCESS); } -static void prov_failed(const uint8_t idx, const uint8_t *data) +static void prov_failed(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf) { - BT_WARN("Error 0x%02x", data[0]); + BT_WARN("Error 0x%02x", buf->data[0]); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); } static const struct { - void (*func)(const uint8_t idx, const uint8_t *data); - uint16_t len; + void (*func)(struct bt_mesh_prov_link *link, struct net_buf_simple *buf); } prov_handlers[] = { - { prov_invite, 1 }, - { prov_capabilities, 11 }, - { prov_start, 5 }, - { prov_pub_key, 64 }, - { prov_input_complete, 0 }, - { prov_confirm, 16 }, - { prov_random, 16 }, - { prov_data, 33 }, - { prov_complete, 0 }, - { prov_failed, 1 }, + { prov_invite, }, + { prov_capabilities, }, + { prov_start, }, + { prov_pub_key, }, + { prov_input_complete, }, + { prov_confirm, }, + { prov_random, }, + { prov_data, }, + { prov_complete, }, + { prov_failed, }, +#if CONFIG_BLE_MESH_CERT_BASED_PROV + { bt_mesh_pvnr_record_req, }, + { bt_mesh_pvnr_record_rsp, }, + { bt_mesh_pvnr_records_get, }, + { bt_mesh_pvnr_records_list, }, +#endif }; -static void close_link(const uint8_t idx, uint8_t reason) +static void close_link(struct bt_mesh_prov_link *link, uint8_t reason) { -#if defined(CONFIG_BLE_MESH_PB_ADV) - if (idx < CONFIG_BLE_MESH_PBA_SAME_TIME) { - bearer_ctl_send(idx, LINK_CLOSE, &reason, sizeof(reason)); - return; - } -#endif - -#if defined(CONFIG_BLE_MESH_PB_GATT) - if (idx < BLE_MESH_PROV_SAME_TIME -#if defined(CONFIG_BLE_MESH_PB_ADV) - && idx >= CONFIG_BLE_MESH_PBA_SAME_TIME -#endif - ) { - if (link[idx].conn) { - bt_mesh_gattc_disconnect(link[idx].conn); + if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + if (link->pb_remote_close) { + link->pb_remote_close(link, reason); } return; } -#endif - BT_ERR("Invalid link idx %d", idx); - return; +#if CONFIG_BLE_MESH_PB_GATT + if (link->conn) { + bt_mesh_gattc_disconnect(link->conn); + return; + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ + +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_prov_bearer_ctl_send(link, LINK_CLOSE, &reason, sizeof(reason)); +#endif /* CONFIG_BLE_MESH_PB_ADV */ } -static void prov_timeout(struct k_work *work) -{ - uint8_t idx = (uint8_t)work->index; - - BT_WARN("%s", __func__); - - close_link(idx, CLOSE_REASON_TIMEOUT); -} - -#if defined(CONFIG_BLE_MESH_PB_ADV) -static void prov_retransmit(struct k_work *work) -{ - int64_t timeout = TRANSACTION_TIMEOUT; - uint8_t idx = (uint8_t)work->index; - int i; - - BT_DBG("%s", __func__); - - if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { - BT_WARN("Link is not active"); - return; - } - -#if defined(CONFIG_BLE_MESH_FAST_PROV) - if (link[idx].tx_pdu_type >= PROV_DATA) { - timeout = K_SECONDS(30); - } -#endif - if (k_uptime_get() - link[idx].tx.start > timeout) { - BT_WARN("Provisioner timeout, giving up transaction"); - /* Provisioner should send Link Close here */ - close_link(idx, CLOSE_REASON_TIMEOUT); - return; - } - - if (link[idx].send_link_close & BIT(0)) { - uint8_t reason = (link[idx].send_link_close >> 1) & BIT_MASK(2); - uint16_t count = (link[idx].send_link_close >> 3); - if (count >= 2) { - reset_link(idx, reason); - return; - } - link[idx].send_link_close += BIT(3); - } - - bt_mesh_pb_buf_lock(); - - for (i = 0; i < ARRAY_SIZE(link[idx].tx.buf); i++) { - struct net_buf *buf = link[idx].tx.buf[i]; - - if (!buf) { - break; - } - - if (BLE_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - - if (i + 1 < ARRAY_SIZE(link[idx].tx.buf) && link[idx].tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, (void *)(int)idx); - } - } - - bt_mesh_pb_buf_unlock(); -} - -static void link_ack(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +#if CONFIG_BLE_MESH_PB_ADV +static void link_ack(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { BT_DBG("len %u", buf->len); if (buf->len) { BT_ERR("Invalid Link ACK length %d", buf->len); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return; } - if (link[idx].expect == PROV_CAPABILITIES) { + if (link->expect == PROV_CAPABILITIES || + link->expect == PROV_REC_LIST || link->expect == PROV_REC_RSP) { BT_INFO("Link ACK is already received"); return; } - link[idx].conf_inputs = (uint8_t *)bt_mesh_calloc(PROV_CONF_INPUTS_SIZE); - if (!link[idx].conf_inputs) { - BT_ERR("%s, Out of memory", __func__); - close_link(idx, CLOSE_REASON_FAILED); +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(link->oob_info)) { + if (bt_mesh_prov_get()->cert_based_prov_start) { + bt_mesh_prov_get()->cert_based_prov_start(link - prov_links); + } + } else +#endif + { + send_invite(link); + } +} + +static void link_close(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) +{ + BT_DBG("len %u", buf->len); + + if (buf->len != 1) { + BT_ERR("Invalid Link Close length %d", buf->len); return; } - send_invite(idx); + reset_adv_link(link, net_buf_simple_pull_u8(buf)); } -static void link_close(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) -{ - uint8_t reason = 0U; - - BT_DBG("len %u", buf->len); - - reason = net_buf_simple_pull_u8(buf); - - reset_link(idx, reason); -} - -static void gen_prov_ctl(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +static void gen_prov_ctl(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { BT_DBG("op 0x%02x len %u", BEARER_CTL(rx->gpc), buf->len); @@ -2810,17 +2366,19 @@ static void gen_prov_ctl(const uint8_t idx, struct prov_rx *rx, struct net_buf_s break; case LINK_ACK: - if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE)) { return; } - link_ack(idx, rx, buf); + + link_ack(link, rx, buf); break; case LINK_CLOSE: - if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE)) { + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE)) { return; } - link_close(idx, rx, buf); + + link_close(link, rx, buf); break; default: @@ -2829,41 +2387,54 @@ static void gen_prov_ctl(const uint8_t idx, struct prov_rx *rx, struct net_buf_s } } -static void prov_msg_recv(const uint8_t idx) +static void prov_msg_recv(struct bt_mesh_prov_link *link) { - uint8_t type = link[idx].rx.buf->data[0]; + uint8_t type = 0; - BT_DBG("type 0x%02x len %u", type, link[idx].rx.buf->len); - - /** - * Provisioner first checks information within the received - * Provisioning PDU. If the check succeeds then check fcs. + /* When Link Close is being sent, any received Provisioning PDU + * should be ignored. */ - if (type != PROV_FAILED && type != link[idx].expect) { - BT_ERR("Unexpected msg 0x%02x != 0x%02x", type, link[idx].expect); - goto fail; + if (bt_mesh_atomic_test_bit(link->flags, LINK_CLOSING)) { + BT_WARN("Link is closing, unexpected msg 0x%02x", type); + return; } - if (type >= 0x0A) { + if (!bt_mesh_fcs_check(link->rx.buf, link->rx.fcs)) { + BT_ERR("Incorrect FCS"); + return; + } + + type = net_buf_simple_pull_u8(link->rx.buf); + + BT_DBG("type 0x%02x len %u", type, link->rx.buf->len); + + if (type >= ARRAY_SIZE(prov_handlers)) { BT_ERR("Unknown provisioning PDU type 0x%02x", type); goto fail; } - if (1 + prov_handlers[type].len != link[idx].rx.buf->len) { - BT_ERR("Invalid length %u for type 0x%02x", link[idx].rx.buf->len, type); + bt_mesh_gen_prov_ack_send(link, link->rx.id); + link->rx.prev_id = link->rx.id; + link->rx.id = 0; + + /* Provisioner first checks information within the received + * Provisioning PDU. If the check succeeds then check fcs. + */ + if (type != PROV_FAILED && type != link->expect) { + BT_ERR("Unexpected msg 0x%02x != 0x%02x", type, link->expect); goto fail; } - if (!bt_mesh_fcs_check(link[idx].rx.buf, link[idx].rx.fcs)) { - BT_ERR("Incorrect FCS"); + if (!bt_mesh_prov_pdu_check(type, link->rx.buf->len, NULL)) { goto fail; } - gen_prov_ack_send(idx, link[idx].rx.trans_id); - link[idx].rx.prev_id = link[idx].rx.trans_id; - link[idx].rx.trans_id = 0; + k_delayed_work_submit(&link->prot_timer, PROTOCOL_TIMEOUT); + + prov_handlers[type].func(link, link->rx.buf); + + net_buf_simple_reset(link->rx.buf); - prov_handlers[type].func(idx, &link[idx].rx.buf->data[1]); return; fail: @@ -2871,85 +2442,49 @@ fail: * For the case MESH/PVNR/PROV/BV-10-C and MESH/PVNR/PROV/BI-14-C, * provisioner should send transaction ack before closing the link. */ - gen_prov_ack_send(idx, link[idx].rx.trans_id); + bt_mesh_gen_prov_ack_send(link, link->rx.id); - close_link(idx, CLOSE_REASON_FAILED); - return; + close_link(link, CLOSE_REASON_FAILED); } -static void gen_prov_cont(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +static void gen_prov_cont(struct bt_mesh_prov_link *link, + struct prov_rx *rx, + struct net_buf_simple *buf) { - uint8_t seg = CONT_SEG_INDEX(rx->gpc); + bool close = false; - BT_DBG("len %u, seg_index %u", buf->len, seg); - - if (!link[idx].rx.seg && link[idx].rx.prev_id == rx->xact_id) { - BT_INFO("Resending ack"); - gen_prov_ack_send(idx, rx->xact_id); - return; - } - - if (rx->xact_id != link[idx].rx.trans_id) { - BT_WARN("Data for unknown transaction (%u != %u)", - rx->xact_id, link[idx].rx.trans_id); - return; - } - - if (seg > link[idx].rx.last_seg) { - BT_ERR("Invalid segment index %u", seg); - goto fail; - } else if (seg == link[idx].rx.last_seg) { - uint8_t expect_len = 0U; - - expect_len = (link[idx].rx.buf->len - 20 - - (23 * (link[idx].rx.last_seg - 1))); - if (expect_len != buf->len) { - BT_ERR("Incorrect last seg len: %u != %u", - expect_len, buf->len); - goto fail; + if (!bt_mesh_gen_prov_cont(link, buf, rx, &close)) { + if (close) { + close_link(link, CLOSE_REASON_FAILED); } - } - - if (!(link[idx].rx.seg & BIT(seg))) { - BT_INFO("Ignore already received segment"); return; } - memcpy(XACT_SEG_DATA(idx, seg), buf->data, buf->len); - XACT_SEG_RECV(idx, seg); - - if (!link[idx].rx.seg) { - prov_msg_recv(idx); - } - return; - -fail: - close_link(idx, CLOSE_REASON_FAILED); - return; + prov_msg_recv(link); } -static void gen_prov_ack(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +static void gen_prov_ack(struct bt_mesh_prov_link *link, + struct prov_rx *rx, + struct net_buf_simple *buf) { - uint8_t ack_type = 0U, pub_key_oob = 0U; - BT_DBG("len %u", buf->len); - if (!link[idx].tx.buf[0]) { + if (!link->tx.buf[0]) { return; } - if (!link[idx].tx.trans_id) { + if (!link->tx.id) { return; } - if (rx->xact_id == (link[idx].tx.trans_id - 1)) { - prov_clear_tx(idx); + if (rx->xact_id == (link->tx.id - 1)) { + bt_mesh_prov_clear_tx(link, true); - ack_type = link[idx].expect_ack_for; - switch (ack_type) { + switch (link->expect_ack_for) { case PROV_START: - pub_key_oob = link[idx].conf_inputs[13]; - send_pub_key(idx, pub_key_oob); + send_pub_key(link); + + uint8_t pub_key_oob = link->conf_inputs[13]; /* For case MESH/PVNR/PROV/BV-04-C, if using OOB public key, * the value of expect_ack_for shall be PROV_PUB_KEY. */ @@ -2958,163 +2493,114 @@ static void gen_prov_ack(const uint8_t idx, struct prov_rx *rx, struct net_buf_s } break; case PROV_PUB_KEY: - prov_gen_dh_key(idx); + prov_gen_dh_key(link); break; default: break; } - link[idx].expect_ack_for = 0x00; + + link->expect_ack_for = 0x00; } } -static void gen_prov_start(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +static void gen_prov_start(struct bt_mesh_prov_link *link, + struct prov_rx *rx, + struct net_buf_simple *buf) { - if (link[idx].rx.seg) { - BT_INFO("Get Start while there are unreceived segments"); + bool close = false; + + if (!bt_mesh_gen_prov_start(link, buf, rx, &close)) { + if (close) { + close_link(link, CLOSE_REASON_FAILED); + } return; } - if (link[idx].rx.prev_id == rx->xact_id) { - BT_INFO("Resending ack"); - gen_prov_ack_send(idx, rx->xact_id); - return; - } - - link[idx].rx.buf->len = net_buf_simple_pull_be16(buf); - link[idx].rx.trans_id = rx->xact_id; - link[idx].rx.fcs = net_buf_simple_pull_u8(buf); - - BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, - START_LAST_SEG(rx->gpc), link[idx].rx.buf->len, link[idx].rx.fcs); - - /* Provisioner can not receive zero-length provisioning pdu */ - if (link[idx].rx.buf->len < 1) { - BT_ERR("Ignoring zero-length provisioning PDU"); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - - if (START_LAST_SEG(rx->gpc) > START_LAST_SEG_MAX) { - BT_ERR("Invalid SegN 0x%02x", START_LAST_SEG(rx->gpc)); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - - if (link[idx].rx.buf->len > link[idx].rx.buf->size) { - BT_ERR("Too large provisioning PDU (%u bytes)", - link[idx].rx.buf->len); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - - if (START_LAST_SEG(rx->gpc) > 0 && link[idx].rx.buf->len <= 20) { - BT_ERR("Too small total length for multi-segment PDU"); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - - link[idx].rx.seg = (1 << (START_LAST_SEG(rx->gpc) + 1)) - 1; - link[idx].rx.last_seg = START_LAST_SEG(rx->gpc); - memcpy(link[idx].rx.buf->data, buf->data, buf->len); - XACT_SEG_RECV(idx, 0); - - if (!link[idx].rx.seg) { - prov_msg_recv(idx); - } + prov_msg_recv(link); } static const struct { - void (*const func)(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf); + void (*const func)(struct bt_mesh_prov_link *link, + struct prov_rx *rx, + struct net_buf_simple *buf); const uint8_t require_link; const uint8_t min_len; } gen_prov[] = { - { gen_prov_start, true, 3 }, - { gen_prov_ack, true, 0 }, - { gen_prov_cont, true, 0 }, - { gen_prov_ctl, true, 0 }, + { gen_prov_start, true, 3 }, + { gen_prov_ack, true, 0 }, + { gen_prov_cont, true, 0 }, + { gen_prov_ctl, true, 0 }, }; -static void gen_prov_recv(const uint8_t idx, struct prov_rx *rx, struct net_buf_simple *buf) +static void gen_prov_recv(struct bt_mesh_prov_link *link, + struct prov_rx *rx, + struct net_buf_simple *buf) { if (buf->len < gen_prov[GPCF(rx->gpc)].min_len) { BT_ERR("Too short GPC message type %u", GPCF(rx->gpc)); - close_link(idx, CLOSE_REASON_FAILED); return; } - /** - * require_link can be used combining with link[].linking flag to - * set LINK_ACTIVE status after Link ACK is received. In this case - * there is no need to check LINK_ACTIVE status in find_link(). - */ - if (!bt_mesh_atomic_test_bit(link[idx].flags, LINK_ACTIVE) && - gen_prov[GPCF(rx->gpc)].require_link) { + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) && + gen_prov[GPCF(rx->gpc)].require_link) { BT_DBG("Ignoring message that requires active link"); return; } - gen_prov[GPCF(rx->gpc)].func(idx, rx, buf); + gen_prov[GPCF(rx->gpc)].func(link, rx, buf); } -static int find_link(uint32_t link_id, uint8_t *idx) +static struct bt_mesh_prov_link *find_pba_link(uint32_t link_id) { int i; - /* link for PB-ADV is from 0 to CONFIG_BLE_MESH_PBA_SAME_TIME */ + /* PB-ADV link is from 0 to CONFIG_BLE_MESH_PBA_SAME_TIME */ for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { - if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { - if (link[i].link_id == link_id) { - if (idx) { - *idx = i; - } - return 0; - } + if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && + prov_links[i].link_id == link_id) { + return &prov_links[i]; } } - return -1; + return NULL; } void bt_mesh_provisioner_pb_adv_recv(struct net_buf_simple *buf) { + struct bt_mesh_prov_link *link = NULL; struct prov_rx rx = {0}; - uint8_t idx = 0U; + + if (buf->len < 6) { + BT_ERR("Too short provisioning packet (len %u)", buf->len); + return; + } rx.link_id = net_buf_simple_pull_be32(buf); - if (find_link(rx.link_id, &idx) < 0) { - BT_DBG("Data for unexpected link"); - return; - } - - if (buf->len < 2) { - BT_ERR("Too short provisioning packet (len %u)", buf->len); - close_link(idx, CLOSE_REASON_FAILED); - return; - } - rx.xact_id = net_buf_simple_pull_u8(buf); rx.gpc = net_buf_simple_pull_u8(buf); BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); - gen_prov_recv(idx, &rx, buf); + link = find_pba_link(rx.link_id); + if (link == NULL) { + BT_DBG("Ignoring mesh beacon for unknown link"); + return; + } + + gen_prov_recv(link, &rx, buf); } #endif /* CONFIG_BLE_MESH_PB_ADV */ -#if defined(CONFIG_BLE_MESH_PB_GATT) -static struct bt_mesh_conn *find_conn(struct bt_mesh_conn *conn, uint8_t *idx) +#if CONFIG_BLE_MESH_PB_GATT +static struct bt_mesh_prov_link *find_pbg_link(struct bt_mesh_conn *conn) { int i; - /* link for PB-GATT is from CONFIG_BLE_MESH_PBA_SAME_TIME to BLE_MESH_PROV_SAME_TIME */ + /* PB-GATT link is from CONFIG_BLE_MESH_PBA_SAME_TIME to BLE_MESH_PROV_SAME_TIME */ for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { - if (link[i].conn == conn) { - if (idx) { - *idx = i; - } - return conn; - } + if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && + prov_links[i].conn == conn) { + return &prov_links[i]; } } @@ -3123,161 +2609,150 @@ static struct bt_mesh_conn *find_conn(struct bt_mesh_conn *conn, uint8_t *idx) int bt_mesh_provisioner_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) { + struct bt_mesh_prov_link *link = NULL; uint8_t type = 0U; - uint8_t idx = 0U; BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - if (!find_conn(conn, &idx)) { - BT_ERR("Data for unexpected connection"); + link = find_pbg_link(conn); + if (link == NULL) { + BT_ERR("Link not found, conn %p", conn); return -ENOTCONN; } if (buf->len < 1) { BT_ERR("Too short provisioning packet (len %u)", buf->len); - goto fail; + return -EINVAL; } type = net_buf_simple_pull_u8(buf); - if (type != PROV_FAILED && type != link[idx].expect) { - BT_ERR("Unexpected msg 0x%02x != 0x%02x", type, link[idx].expect); - goto fail; - } - if (type >= 0x0A) { + if (type >= ARRAY_SIZE(prov_handlers)) { BT_ERR("Unknown provisioning PDU type 0x%02x", type); - goto fail; + close_link(link, CLOSE_REASON_FAILED); + return -EINVAL; } - if (prov_handlers[type].len != buf->len) { - BT_ERR("Invalid length %u for type 0x%02x", buf->len, type); - goto fail; + if (type != PROV_FAILED && type != link->expect) { + BT_ERR("Unexpected msg 0x%02x != 0x%02x", type, link->expect); + close_link(link, CLOSE_REASON_FAILED); + return -EINVAL; } - prov_handlers[type].func(idx, buf->data); + if (!bt_mesh_prov_pdu_check(type, buf->len, NULL)) { + close_link(link, CLOSE_REASON_FAILED); + return -EINVAL; + } + + k_delayed_work_submit(&link->prot_timer, PROTOCOL_TIMEOUT); + + prov_handlers[type].func(link, buf); return 0; - -fail: - /* Mesh Spec Section 5.4.4 Provisioning errors */ - close_link(idx, CLOSE_REASON_FAILED); - return -EINVAL; } -int bt_mesh_provisioner_set_prov_conn(const uint8_t addr[6], struct bt_mesh_conn *conn) +int bt_mesh_provisioner_pb_gatt_open(struct bt_mesh_conn *conn, const uint8_t addr[6]) { + struct bt_mesh_prov_link *link = NULL; int i; - if (!addr || !conn) { + if (conn == NULL || addr == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (!memcmp(link[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { - link[i].conn = bt_mesh_conn_ref(conn); - return 0; - } - } - - BT_ERR("Addr %s not found", bt_hex(addr, BLE_MESH_ADDR_LEN)); - return -ENOMEM; -} - -int bt_mesh_provisioner_pb_gatt_open(struct bt_mesh_conn *conn, uint8_t *addr) -{ - uint8_t idx = 0U; - int i; - - BT_DBG("conn %p", conn); - - /** - * Double check if the device is currently being provisioned using PB-ADV. - * Provisioner binds conn with proper device when proxy_prov_connected() - * is invoked, and here after proper GATT procedures are completed, we just - * check if this conn already exists in the proxy servers array. - */ - for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { - if (link[i].conn == conn) { - idx = i; + if (!memcmp(prov_links[i].addr.val, addr, BLE_MESH_ADDR_LEN)) { + prov_links[i].conn = bt_mesh_conn_ref(conn); + link = &prov_links[i]; break; } } - if (i == BLE_MESH_PROV_SAME_TIME) { - BT_ERR("Link not found"); - return -ENOTCONN; + if (link == NULL) { + BT_ERR("Device address %s not found", bt_hex(addr, BLE_MESH_ADDR_LEN)); + return -ENODEV; } -#if defined(CONFIG_BLE_MESH_PB_ADV) + /* Double check if the device is currently being provisioned using PB-ADV. */ +#if CONFIG_BLE_MESH_PB_ADV for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { - if (bt_mesh_atomic_test_bit(link[i].flags, LINK_ACTIVE)) { - if (!memcmp(link[i].uuid, link[idx].uuid, 16)) { + if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE)) { + if (!memcmp(prov_links[i].uuid, link->uuid, 16)) { BT_WARN("Provision using PB-GATT & PB-ADV same time"); - close_link(idx, CLOSE_REASON_FAILED); + close_link(link, CLOSE_REASON_FAILED); return -EALREADY; } } } -#endif +#endif /* CONFIG_BLE_MESH_PB_ADV */ - bt_mesh_atomic_set_bit(link[idx].flags, LINK_ACTIVE); - link[idx].conn = bt_mesh_conn_ref(conn); + bt_mesh_atomic_set_bit(link->flags, LINK_ACTIVE); /* May use lcd to indicate starting provisioning each device */ - if (prov->prov_link_open) { - prov->prov_link_open(BLE_MESH_PROV_GATT); + if (bt_mesh_prov_get()->prov_link_open) { + bt_mesh_prov_get()->prov_link_open(BLE_MESH_PROV_GATT); } - link[idx].conf_inputs = (uint8_t *)bt_mesh_calloc(PROV_CONF_INPUTS_SIZE); - if (!link[idx].conf_inputs) { - /* Disconnect this connection, clear corresponding informations */ - BT_ERR("%s, Out of memory", __func__); - close_link(idx, CLOSE_REASON_FAILED); - return -ENOMEM; + /* TODO: memory optimization - calloc */ + +#if CONFIG_BLE_MESH_CERT_BASED_PROV + if (PROV_REC_SUPPORT(link->oob_info)) { + if (bt_mesh_prov_get()->cert_based_prov_start) { + bt_mesh_prov_get()->cert_based_prov_start(link - prov_links); + } + } else +#endif + { + send_invite(link); } - send_invite(idx); return 0; } int bt_mesh_provisioner_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason) { - uint8_t idx = 0U; + struct bt_mesh_prov_link *link = NULL; BT_DBG("conn %p", conn); - if (!find_conn(conn, &idx)) { - BT_ERR("Conn %p not found", conn); + link = find_pbg_link(conn); + if (link == NULL) { + BT_ERR("Not connected, conn %p", conn); return -ENOTCONN; } - if (bt_mesh_atomic_test_and_clear_bit(link[idx].flags, TIMEOUT_START)) { - k_delayed_work_cancel(&link[idx].timeout); + k_delayed_work_cancel(&link->prot_timer); + + if (bt_mesh_prov_get()->prov_link_close) { + bt_mesh_prov_get()->prov_link_close(BLE_MESH_PROV_GATT, reason); } - if (prov->prov_link_close) { - prov->prov_link_close(BLE_MESH_PROV_GATT, reason); - } + prov_memory_free(link); - prov_memory_free(idx); + memset(link, 0, offsetof(struct bt_mesh_prov_link, prot_timer)); - memset(&link[idx], 0, offsetof(struct prov_link, timeout)); - - if (bt_mesh_pub_key_get()) { - bt_mesh_atomic_set_bit(link[idx].flags, LOCAL_PUB_KEY); - } + link->pb_gatt_send = prov_send_gatt; return 0; } #endif /* CONFIG_BLE_MESH_PB_GATT */ -int bt_mesh_provisioner_prov_init(const struct bt_mesh_prov *prov_info) +static void protocol_timeout(struct k_work *work) +{ + struct bt_mesh_prov_link *link = work->user_data; + + BT_WARN("Protocol timeout"); + + close_link(link, CLOSE_REASON_TIMEOUT); +} + +int bt_mesh_provisioner_prov_init(void) { const uint8_t *key = NULL; int i; - if (!prov_info) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } @@ -3288,40 +2763,56 @@ int bt_mesh_provisioner_prov_init(const struct bt_mesh_prov *prov_info) return -EIO; } - prov = prov_info; - prov_ctx.primary_addr = BLE_MESH_ADDR_UNASSIGNED; - if (prov->prov_static_oob_val && prov->prov_static_oob_len) { - prov_ctx.static_oob_len = MIN(16, prov->prov_static_oob_len); - memcpy(prov_ctx.static_oob_val, prov->prov_static_oob_val, prov_ctx.static_oob_len); + if (bt_mesh_prov_get()->prov_static_oob_val && + bt_mesh_prov_get()->prov_static_oob_len) { + prov_ctx.static_oob_len = MIN(BLE_MESH_PROV_STATIC_OOB_MAX_LEN, bt_mesh_prov_get()->prov_static_oob_len); + memcpy(prov_ctx.static_oob_val, + bt_mesh_prov_get()->prov_static_oob_val, + prov_ctx.static_oob_len); } -#if defined(CONFIG_BLE_MESH_PB_ADV) +#if CONFIG_BLE_MESH_PB_ADV for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { - struct prov_adv_buf *adv = &adv_buf[i]; - adv->buf.size = ADV_BUF_SIZE; - adv->buf.__buf = adv_buf_data + (i * ADV_BUF_SIZE); + rx_buf[i].buf.size = PROV_RX_BUF_SIZE; + rx_buf[i].buf.__buf = rx_buf_data + (i * PROV_RX_BUF_SIZE); - link[i].pending_ack = XACT_NVAL; - k_delayed_work_init(&link[i].tx.retransmit, prov_retransmit); - link[i].tx.retransmit.work.index = (int)i; - link[i].rx.prev_id = XACT_NVAL; - link[i].rx.buf = bt_mesh_pba_get_buf(i); + prov_links[i].pending_ack = PROV_XACT_NVAL; + + bt_mesh_prov_retransmit_init(&prov_links[i]); + + prov_links[i].rx.prev_id = PROV_XACT_NVAL; + prov_links[i].rx.buf = get_rx_buf(i); + + prov_links[i].next_xact_id = pvnr_next_xact_id; + prov_links[i].reset_adv_link = reset_adv_link; + prov_links[i].retrans_timeout = close_link; + +#if CONFIG_BLE_MESH_FAST_PROV + prov_links[i].last_tx_pdu = PROV_DATA; +#endif /* CONFIG_BLE_MESH_FAST_PROV */ + + bt_mesh_mutex_create(&prov_links[i].buf_lock); } -#endif +#endif /* CONFIG_BLE_MESH_PB_ADV */ + +#if CONFIG_BLE_MESH_PB_GATT + for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { + prov_links[i].pb_gatt_send = prov_send_gatt; + } +#endif /* CONFIG_BLE_MESH_PB_GATT */ for (i = 0; i < BLE_MESH_PROV_SAME_TIME; i++) { - k_delayed_work_init(&link[i].timeout, prov_timeout); - link[i].timeout.work.index = (int)i; + k_delayed_work_init(&prov_links[i].prot_timer, protocol_timeout); + prov_links[i].prot_timer.work.user_data = &prov_links[i]; } -#if defined(CONFIG_BLE_MESH_PB_ADV) - bt_mesh_pb_adv_mutex_new(); - bt_mesh_pb_buf_mutex_new(); +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_mutex_create(&prov_ctx.pb_adv_lock); #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) - bt_mesh_pb_gatt_mutex_new(); +#if CONFIG_BLE_MESH_PB_GATT + bt_mesh_mutex_create(&prov_ctx.pb_gatt_lock); #endif return 0; @@ -3331,35 +2822,41 @@ int bt_mesh_provisioner_prov_reset(bool erase) { int i; - if (prov == NULL) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } for (i = 0; i < BLE_MESH_PROV_SAME_TIME; i++) { - k_delayed_work_cancel(&link[i].timeout); + k_delayed_work_cancel(&prov_links[i].prot_timer); - prov_memory_free(i); + prov_memory_free(&prov_links[i]); if (i < CONFIG_BLE_MESH_PBA_SAME_TIME) { #if CONFIG_BLE_MESH_PB_ADV - prov_clear_tx(i); + bt_mesh_prov_clear_tx(&prov_links[i], true); #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, - BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, &link[i].link_id); + BLE_MESH_EXCEP_LIST_TYPE_MESH_LINK_ID, + &prov_links[i].link_id); #endif - memset(&link[i], 0, offsetof(struct prov_link, tx.retransmit)); - link[i].pending_ack = XACT_NVAL; - link[i].rx.prev_id = XACT_NVAL; - link[i].rx.buf = bt_mesh_pba_get_buf(i); + memset(&prov_links[i], 0, offsetof(struct bt_mesh_prov_link, tx.retransmit)); + prov_links[i].pending_ack = PROV_XACT_NVAL; + prov_links[i].rx.prev_id = PROV_XACT_NVAL; + prov_links[i].rx.buf = get_rx_buf(i); #endif /* CONFIG_BLE_MESH_PB_ADV */ } else { - memset(&link[i], 0, offsetof(struct prov_link, timeout)); + memset(&prov_links[i], 0, offsetof(struct bt_mesh_prov_link, prot_timer)); } - if (bt_mesh_pub_key_get()) { - bt_mesh_atomic_set_bit(link[i].flags, LOCAL_PUB_KEY); +#if CONFIG_BLE_MESH_CERT_BASED_PROV + for (size_t j = 0; j < BLE_MESH_REC_MAX_ID; j++) { + if (prov_links[i].records[j]) { + bt_mesh_free(prov_links[i].records[j]); + prov_links[i].records[j] = NULL; + } } +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ } /* static_oob_len & static_oob_val are initialized during mesh init. @@ -3388,46 +2885,44 @@ int bt_mesh_provisioner_prov_deinit(bool erase) { int i; - if (prov == NULL) { - BT_ERR("%s, No provisioning context provided", __func__); + if (bt_mesh_prov_get() == NULL) { + BT_ERR("No provisioning context provided"); return -EINVAL; } bt_mesh_provisioner_prov_reset(erase); for (i = 0; i < BLE_MESH_PROV_SAME_TIME; i++) { -#if defined(CONFIG_BLE_MESH_PB_ADV) +#if CONFIG_BLE_MESH_PB_ADV if (i < CONFIG_BLE_MESH_PBA_SAME_TIME) { - k_delayed_work_free(&link[i].tx.retransmit); + k_delayed_work_free(&prov_links[i].tx.retransmit); + bt_mesh_mutex_free(&prov_links[i].buf_lock); } #endif - k_delayed_work_free(&link[i].timeout); - memset(&link[i], 0, sizeof(link[i])); + k_delayed_work_free(&prov_links[i].prot_timer); + memset(&prov_links[i], 0, sizeof(prov_links[i])); } -#if defined(CONFIG_BLE_MESH_PB_ADV) - bt_mesh_pb_adv_mutex_free(); - bt_mesh_pb_buf_mutex_free(); +#if CONFIG_BLE_MESH_PB_ADV + bt_mesh_mutex_free(&prov_ctx.pb_adv_lock); #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) - bt_mesh_pb_gatt_mutex_free(); +#if CONFIG_BLE_MESH_PB_GATT + bt_mesh_mutex_free(&prov_ctx.pb_gatt_lock); #endif prov_ctx.static_oob_len = 0U; memset(prov_ctx.static_oob_val, 0, sizeof(prov_ctx.static_oob_val)); -#if defined(CONFIG_BLE_MESH_PB_ADV) - memset(adv_buf, 0, sizeof(adv_buf)); - memset(adv_buf_data, 0, sizeof(adv_buf_data)); +#if CONFIG_BLE_MESH_PB_ADV + memset(rx_buf, 0, sizeof(rx_buf)); + memset(rx_buf_data, 0, sizeof(rx_buf_data)); #endif - prov = NULL; - return 0; } #endif /* CONFIG_BLE_MESH_DEINIT */ -static bool is_unprov_dev_info_callback_to_app(bt_mesh_prov_bearer_t bearer, const uint8_t uuid[16], - const bt_mesh_addr_t *addr, uint16_t oob_info, int8_t rssi) +static bool notify_unprov_dev_info(bt_mesh_prov_bearer_t bearer, const uint8_t uuid[16], + const bt_mesh_addr_t *addr, uint16_t oob_info, int8_t rssi) { int i; @@ -3444,7 +2939,8 @@ static bool is_unprov_dev_info_callback_to_app(bt_mesh_prov_bearer_t bearer, con if (i == ARRAY_SIZE(unprov_dev)) { BT_DBG("Device not in queue, notify to app layer"); if (notify_unprov_adv_pkt_cb) { - notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, uuid, oob_info, bearer, rssi); + notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, + uuid, oob_info, bearer, rssi); } return true; } @@ -3453,7 +2949,8 @@ static bool is_unprov_dev_info_callback_to_app(bt_mesh_prov_bearer_t bearer, con BT_WARN("Device in queue not support PB-%s", (bearer == BLE_MESH_PROV_ADV) ? "ADV" : "GATT"); if (notify_unprov_adv_pkt_cb) { - notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, uuid, oob_info, bearer, rssi); + notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, + uuid, oob_info, bearer, rssi); } return true; } @@ -3462,9 +2959,9 @@ static bool is_unprov_dev_info_callback_to_app(bt_mesh_prov_bearer_t bearer, con return false; } +#if CONFIG_BLE_MESH_PB_ADV void bt_mesh_provisioner_unprov_beacon_recv(struct net_buf_simple *buf, int8_t rssi) { -#if defined(CONFIG_BLE_MESH_PB_ADV) const bt_mesh_addr_t *addr = NULL; const uint8_t *uuid = NULL; uint16_t oob_info = 0U; @@ -3489,19 +2986,18 @@ void bt_mesh_provisioner_unprov_beacon_recv(struct net_buf_simple *buf, int8_t r return; } - if (is_unprov_dev_info_callback_to_app( - BLE_MESH_PROV_ADV, uuid, addr, oob_info, rssi)) { + if (notify_unprov_dev_info(BLE_MESH_PROV_ADV, uuid, addr, oob_info, rssi)) { return; } provisioner_start_prov_pb_adv(uuid, addr, oob_info, BLE_MESH_ADDR_UNASSIGNED); -#endif /* CONFIG_BLE_MESH_PB_ADV */ } +#endif /* CONFIG_BLE_MESH_PB_ADV */ +#if CONFIG_BLE_MESH_PB_GATT void bt_mesh_provisioner_prov_adv_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, int8_t rssi) { -#if defined(CONFIG_BLE_MESH_PB_GATT) const uint8_t *uuid = NULL; uint16_t oob_info = 0U; @@ -3524,8 +3020,7 @@ void bt_mesh_provisioner_prov_adv_recv(struct net_buf_simple *buf, return; } - if (is_unprov_dev_info_callback_to_app( - BLE_MESH_PROV_GATT, uuid, addr, oob_info, rssi)) { + if (notify_unprov_dev_info(BLE_MESH_PROV_GATT, uuid, addr, oob_info, rssi)) { return; } @@ -3538,11 +3033,133 @@ void bt_mesh_provisioner_prov_adv_recv(struct net_buf_simple *buf, * activated first, the other one will be dropped finally and the link struct * occupied by the dropped link will be used by other devices (because the link * is not activated). - * Use connecting flag to prevent if two devices's adv pkts are both received, + * Use CONNECTING flag to prevent if two devices's adv pkts are both received, * the previous one info will be replaced by the second one. */ provisioner_start_prov_pb_gatt(uuid, addr, oob_info, BLE_MESH_ADDR_UNASSIGNED); +} #endif /* CONFIG_BLE_MESH_PB_GATT */ + +/* This function can be invoked by Remote Provisioning Client + * to handle received Provisioning PDUs. + */ +int bt_mesh_rpr_cli_pdu_recv(struct bt_mesh_prov_link *link, uint8_t type, + struct net_buf_simple *buf) +{ + if (type != link->expect) { + BT_ERR("PB-Remote, unexpected msg 0x%02x != 0x%02x", type, link->expect); + return -EINVAL; + } + + prov_handlers[type].func(link, buf); + return 0; +} + +int bt_mesh_rpr_cli_pdu_send(struct bt_mesh_prov_link *link, uint8_t type) +{ + switch (type) { + case PROV_INVITE: + send_invite(link); + break; + case PROV_PUB_KEY: + send_pub_key(link); + break; + case PROV_CONFIRM: + send_confirm(link); + break; + default: + break; + } + + return 0; +} + +/* The behavior of sending confirmation based on the combination + * of Public Key and authentication: + * + * 1. No OOB Public Key + No OOB + * - No need to send confirmation manually, it will be sent when + * Device Public Key is received. + * + * 2. No OOB Public Key + Static OOB + * - Same with 1. + * + * 3. No OOB Public Key + Output OOB + * - Confirmation will be sent after the authentication value is + * set with bt_mesh_provisioner_set_oob_input_data(). + * + * 4. No OOB Public Key + Input OOB + * - No need to send confirmation manually, it will be sent when + * Input Complete is received. + * Note: + * Need to make sure the authentication value has been set with + * bt_mesh_provisioner_set_oob_output_data() before sending + * confirmation. + * + * 5. OOB Public Key + No OOB + * - If OOB Public Key is set before sending Public Key, we need + * to wait for the Remote Provisioning PDU Outbound Report for + * Public Key, then send confirmation manually; + * - If OOB Public Key is set after sending Public Key, and before + * receiving the Remote Provisioning PDU Outbound Report for + * Public Key, need to send confirmation manually; + * - If OOB Public Key is set after sending Public Key, and after + * receiving the Remote Provisioning PDU Outbound Report for + * Public Key, no need to sending confirmation manually, it will + * be sent after DHKey is generated successfully. + * + * 6. OOB Public Key + Static OOB + * - Same with 5. + * + * 7. OOB Public Key + Output OOB + * - If OOB Public Key is set before sending Public Key, DHKey + * will be generated after Public Key is sent, and: + * - If authentication value is set before receiving Remote + * Provisioning PDU Outbound Report, we need to wait for + * the Remote Provisioning PDU Outbound Report for Public + * Key, then send confirmation manually; + * - If authentication value is set after receiving Remote + * Provisioning PDU Outbound Report, no need to send + * confirmation manually, it will be sent in + * bt_mesh_provisioner_set_oob_input_data(). + * - If OOB Public Key is set after sending Public Key, and the + * OOB Public Key should be set before setting authentication + * value. After OOB Public Key is set, DHKey will be generated. + * And after the authentication value is set: + * - If authentication value is set before receiving Remote + * Provisioning PDU Outbound Report, we need to wait for + * the Remote Provisioning PDU Outbound Report for Public + * Key, then send confirmation manually; + * - If authentication value is set after receiving Remote + * Provisioning PDU Outbound Report, no need to send + * confirmation manually, it will be sent in + * bt_mesh_provisioner_set_oob_input_data(). + * + * 8. OOB Public Key + Input OOB + * - No need to send confirmation manually, it will be sent + * when Input Complete is received. + * Note: + * Need to make sure the authentication value has been set + * with bt_mesh_provisioner_set_oob_output_data() before + * sending confirmation. + * + * Can change the behavior that after sending Public Key, then + * notify the application layer to input OOB Public Key, this + * could simplify the implementation. + */ + +/* The following two functions need to be used based on the above + * considerations. + */ +int bt_mesh_rpr_cli_recv_pub_key_outbound_report(struct bt_mesh_prov_link *link) +{ + bt_mesh_atomic_test_and_clear_bit(link->flags, WAIT_PK_OBR); + + if (bt_mesh_atomic_test_and_clear_bit(link->flags, SEND_CONFIRM)) { + send_confirm(link); + } + + return 0; } #endif /* CONFIG_BLE_MESH_PROVISIONER */ diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.h b/components/bt/esp_ble_mesh/core/prov_pvnr.h index 22ca891fa8..0553a72d36 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.h +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.h @@ -8,20 +8,13 @@ #define _PROV_PVNR_H_ #include "mesh/main.h" +#include "prov_common.h" #include "mesh/adapter.h" #ifdef __cplusplus extern "C" { #endif -#ifndef CONFIG_BLE_MESH_PBA_SAME_TIME -#define CONFIG_BLE_MESH_PBA_SAME_TIME 0 -#endif - -#ifndef CONFIG_BLE_MESH_PBG_SAME_TIME -#define CONFIG_BLE_MESH_PBG_SAME_TIME 0 -#endif - #define RM_AFTER_PROV BIT(0) #define START_PROV_NOW BIT(1) #define FLUSHABLE_DEV BIT(2) @@ -80,17 +73,6 @@ void bt_mesh_provisioner_clear_link_info(const uint8_t addr[6]); */ void bt_mesh_provisioner_pb_adv_recv(struct net_buf_simple *buf); -/** - * @brief This function sends provisioning invite to start - * provisioning this unprovisioned device. - * - * @param[in] addr: Remote device address - * @param[in] conn: Pointer to the bt_conn structure - * - * @return Zero - success, otherwise - fail - */ -int bt_mesh_provisioner_set_prov_conn(const uint8_t addr[6], struct bt_mesh_conn *conn); - /** * @brief This function sends provisioning invite to start * provisioning this unprovisioned device. @@ -100,7 +82,7 @@ int bt_mesh_provisioner_set_prov_conn(const uint8_t addr[6], struct bt_mesh_conn * * @return Zero - success, otherwise - fail */ -int bt_mesh_provisioner_pb_gatt_open(struct bt_mesh_conn *conn, uint8_t *addr); +int bt_mesh_provisioner_pb_gatt_open(struct bt_mesh_conn *conn, const uint8_t addr[6]); /** * @brief This function resets the used information when @@ -128,11 +110,9 @@ int bt_mesh_provisioner_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_s * @brief This function initializes provisioner's PB-GATT and PB-ADV * related information. * - * @param[in] prov_info: Pointer to the application-initialized provisioner info. - * * @return Zero - success, otherwise - fail */ -int bt_mesh_provisioner_prov_init(const struct bt_mesh_prov *prov_info); +int bt_mesh_provisioner_prov_init(void); int bt_mesh_provisioner_prov_reset(bool erase); @@ -161,13 +141,6 @@ void bt_mesh_provisioner_unprov_beacon_recv(struct net_buf_simple *buf, int8_t r void bt_mesh_provisioner_prov_adv_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, int8_t rssi); -/** - * @brief This function gets the bt_mesh_prov pointer. - * - * @return bt_mesh_prov pointer(prov) - */ -const struct bt_mesh_prov *bt_mesh_provisioner_get_prov_info(void); - void bt_mesh_provisioner_restore_prov_info(uint16_t primary_addr, uint16_t alloc_addr); /* The following APIs are for primary provisioner application use */ @@ -406,15 +379,12 @@ uint16_t bt_mesh_provisioner_get_fast_prov_net_idx(void); */ uint8_t bt_mesh_set_fast_prov_unicast_addr_range(uint16_t min, uint16_t max); -/** - * @brief This function is called to set flags & iv_index used for fast provisioning. - * - * @param[in] flags: Key refresh flag and iv update flag - * @param[in] iv_index: IV index - * - * @return None - */ -void bt_mesh_set_fast_prov_flags_iv_index(uint8_t flags, uint32_t iv_index); +int bt_mesh_rpr_cli_pdu_recv(struct bt_mesh_prov_link *link, uint8_t type, + struct net_buf_simple *buf); + +int bt_mesh_rpr_cli_pdu_send(struct bt_mesh_prov_link *link, uint8_t type); + +int bt_mesh_rpr_cli_recv_pub_key_outbound_report(struct bt_mesh_prov_link *link); #ifdef __cplusplus } diff --git a/components/bt/esp_ble_mesh/core/proxy_client.c b/components/bt/esp_ble_mesh/core/proxy_client.c index 891d8ea45a..9382cf6147 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.c +++ b/components/bt/esp_ble_mesh/core/proxy_client.c @@ -8,49 +8,51 @@ #include #include "mesh.h" +#include "rpl.h" #include "access.h" #include "beacon.h" #include "transport.h" #include "mesh/common.h" #include "foundation.h" +#include "proxy_common.h" #include "proxy_client.h" #include "prov_pvnr.h" +#include "prov_node.h" #include "pvnr_mgmt.h" #include "mesh/adapter.h" -#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) -#define PDU_SAR(data) (data[0] >> 6) - -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define SAR_COMPLETE 0x00 -#define SAR_FIRST 0x01 -#define SAR_CONT 0x02 -#define SAR_LAST 0x03 - -#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) - -#define SERVER_BUF_SIZE 68 +#include "mesh_v1.1/utils.h" #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT static struct bt_mesh_proxy_server { struct bt_mesh_conn *conn; - enum __packed { - NONE, - PROV, - PROXY, + + enum __attribute__((packed)) { + CLI_NONE, + CLI_PROV, + CLI_PROXY, } conn_type; + #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT uint16_t net_idx; #endif uint8_t msg_type; + struct k_delayed_work sar_timer; + struct net_buf_simple buf; } servers[BLE_MESH_MAX_CONN]; -static uint8_t server_buf_data[SERVER_BUF_SIZE * BLE_MESH_MAX_CONN]; +#if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT +static struct { + struct bt_mesh_prov_link *link; + bt_mesh_addr_t addr; +} waiting_conn_link[BLE_MESH_MAX_CONN]; +#endif + +static uint8_t server_buf_data[BLE_MESH_PROXY_BUF_SIZE * BLE_MESH_MAX_CONN]; static struct bt_mesh_proxy_server *find_server(struct bt_mesh_conn *conn) { @@ -111,6 +113,22 @@ void bt_mesh_proxy_client_set_filter_status_cb(proxy_client_recv_filter_status_c proxy_client_filter_status_recv_cb = cb; } +#if (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) +int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link *link, + bt_mesh_addr_t *addr) +{ + for (size_t i = 0; i < ARRAY_SIZE(waiting_conn_link);i++) { + if (waiting_conn_link[i].link == NULL) { + waiting_conn_link[i].link = link; + memcpy(&waiting_conn_link[i].addr, addr, sizeof(bt_mesh_addr_t)); + return 0; + } + } + + return -ENOBUFS; +} +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ + static void filter_status(struct bt_mesh_proxy_server *server, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) @@ -136,10 +154,23 @@ static void filter_status(struct bt_mesh_proxy_server *server, if (proxy_client_filter_status_recv_cb) { proxy_client_filter_status_recv_cb(server - servers, rx->ctx.addr, server->net_idx, filter_type, list_size); } - - return; } +#if CONFIG_BLE_MESH_DF_SRV +static void recv_directed_proxy_caps_status(struct bt_mesh_proxy_server *server, + struct bt_mesh_net_rx *rx, + struct net_buf_simple *buf) +{ + uint8_t directed_proxy = net_buf_simple_pull_u8(buf); + uint8_t use_directed = net_buf_simple_pull_u8(buf); + + BT_INFO("Directed Proxy 0x%02x, Use Directed 0x%02x", directed_proxy, use_directed); + + ARG_UNUSED(directed_proxy); + ARG_UNUSED(use_directed); +} +#endif /* CONFIG_BLE_MESH_DF_SRV */ + static void proxy_cfg(struct bt_mesh_proxy_server *server) { NET_BUF_SIMPLE_DEFINE(buf, 29); @@ -188,6 +219,18 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) case BLE_MESH_PROXY_CFG_FILTER_STATUS: filter_status(server, &rx, &buf); break; + +#if CONFIG_BLE_MESH_DF_SRV + case BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CAPS_STATUS: + if (buf.len != 2) { + BT_WARN("Invalid Directed Proxy Caps Status (len %d)", buf.len); + break; + } + + recv_directed_proxy_caps_status(server, &rx, &buf); + break; +#endif /* CONFIG_BLE_MESH_DF_SRV */ + default: BT_WARN("Unknown Proxy Configuration OpCode 0x%02x", opcode); break; @@ -212,10 +255,17 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) proxy_cfg(server); break; #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ -#if CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT +#if CONFIG_BLE_MESH_PB_GATT && (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) case BLE_MESH_PROXY_PROV: BT_DBG("Mesh Provisioning PDU"); - bt_mesh_provisioner_pb_gatt_recv(server->conn, &server->buf); +#if CONFIG_BLE_MESH_RPR_SRV + if (server->conn == bt_mesh_prov_node_get_link()->conn) { + bt_mesh_pb_gatt_recv(server->conn, &server->buf); + } else +#endif + { + bt_mesh_provisioner_pb_gatt_recv(server->conn, &server->buf); + } break; #endif default: @@ -252,7 +302,7 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, return -ENOTCONN; } - if (ATTR_IS_PROV(srvc_uuid) != (PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { + if (ATTR_IS_PROV(srvc_uuid) != (BLE_MESH_PROXY_PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { BT_WARN("Proxy PDU type doesn't match GATT service uuid"); return -EINVAL; } @@ -262,51 +312,51 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, return -EINVAL; } - switch (PDU_SAR(data)) { - case SAR_COMPLETE: + switch (BLE_MESH_PROXY_PDU_SAR(data)) { + case BLE_MESH_PROXY_SAR_COMP: if (server->buf.len) { BT_WARN("Complete PDU while a pending incomplete one"); return -EINVAL; } - server->msg_type = PDU_TYPE(data); + server->msg_type = BLE_MESH_PROXY_PDU_TYPE(data); net_buf_simple_add_mem(&server->buf, data + 1, len - 1); proxy_complete_pdu(server); break; - case SAR_FIRST: + case BLE_MESH_PROXY_SAR_FIRST: if (server->buf.len) { BT_WARN("First PDU while a pending incomplete one"); return -EINVAL; } - k_delayed_work_submit(&server->sar_timer, PROXY_SAR_TIMEOUT); - server->msg_type = PDU_TYPE(data); + k_delayed_work_submit(&server->sar_timer, BLE_MESH_PROXY_SAR_TIMEOUT); + server->msg_type = BLE_MESH_PROXY_PDU_TYPE(data); net_buf_simple_add_mem(&server->buf, data + 1, len - 1); break; - case SAR_CONT: + case BLE_MESH_PROXY_SAR_CONT: if (!server->buf.len) { BT_WARN("Continuation with no prior data"); return -EINVAL; } - if (server->msg_type != PDU_TYPE(data)) { + if (server->msg_type != BLE_MESH_PROXY_PDU_TYPE(data)) { BT_WARN("Unexpected message type in continuation"); return -EINVAL; } - k_delayed_work_submit(&server->sar_timer, PROXY_SAR_TIMEOUT); + k_delayed_work_submit(&server->sar_timer, BLE_MESH_PROXY_SAR_TIMEOUT); net_buf_simple_add_mem(&server->buf, data + 1, len - 1); break; - case SAR_LAST: + case BLE_MESH_PROXY_SAR_LAST: if (!server->buf.len) { BT_WARN("Last SAR PDU with no prior data"); return -EINVAL; } - if (server->msg_type != PDU_TYPE(data)) { + if (server->msg_type != BLE_MESH_PROXY_PDU_TYPE(data)) { BT_WARN("Unexpected message type in last SAR PDU"); return -EINVAL; } @@ -320,7 +370,6 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, return len; } - static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { BT_DBG("%u bytes: %s", len, bt_hex(data, len)); @@ -328,8 +377,8 @@ static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) return bt_mesh_gattc_write_no_rsp(conn, NULL, data, len); } -static int proxy_segment_and_send(struct bt_mesh_conn *conn, uint8_t type, - struct net_buf_simple *msg) +int bt_mesh_proxy_client_segment_send(struct bt_mesh_conn *conn, uint8_t type, + struct net_buf_simple *msg) { uint16_t mtu = 0U; int err = 0; @@ -351,22 +400,22 @@ static int proxy_segment_and_send(struct bt_mesh_conn *conn, uint8_t type, /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu -= 3; if (mtu > msg->len) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_COMP, type)); return proxy_send(conn, msg->data, msg->len); } - net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_FIRST, type)); err = proxy_send(conn, msg->data, mtu); net_buf_simple_pull(msg, mtu); while (msg->len) { if (msg->len + 1 < mtu) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_LAST, type)); err = proxy_send(conn, msg->data, msg->len); break; } - net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_CONT, type)); err = proxy_send(conn, msg->data, mtu); net_buf_simple_pull(msg, mtu); } @@ -384,12 +433,12 @@ int bt_mesh_proxy_client_send(struct bt_mesh_conn *conn, uint8_t type, return -ENOTCONN; } - if ((server->conn_type == PROV) != (type == BLE_MESH_PROXY_PROV)) { + if ((server->conn_type == CLI_PROV) != (type == BLE_MESH_PROXY_PROV)) { BT_ERR("Invalid PDU type for Proxy Server"); return -EINVAL; } - return proxy_segment_and_send(conn, type, msg); + return bt_mesh_proxy_client_segment_send(conn, type, msg); } static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int id) @@ -402,19 +451,27 @@ static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int if (!server) { BT_ERR("No free Proxy Server objects"); - /** Disconnect current connection, clear part of prov_link - * information, like uuid, dev_addr, linking flag, etc. + /* Disconnect current connection, clear part of prov_link + * information, like uuid, dev_addr, linking flag, etc. */ bt_mesh_gattc_disconnect(conn); return; } server->conn = bt_mesh_conn_ref(conn); - server->conn_type = NONE; + server->conn_type = CLI_NONE; net_buf_simple_reset(&server->buf); +#if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT + for (size_t i = 0; i < ARRAY_SIZE(waiting_conn_link); i++) { + if (!memcmp(addr, &waiting_conn_link[i].addr, sizeof(bt_mesh_addr_t))) { + waiting_conn_link[i].link->conn = conn; + break; + } + } +#endif + bt_mesh_gattc_exchange_mtu(id); - return; } static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, uint8_t reason) @@ -428,14 +485,29 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, return; } -#if CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT - if (server->conn_type == PROV) { - bt_mesh_provisioner_pb_gatt_close(conn, reason); +#if CONFIG_BLE_MESH_PB_GATT && \ + (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) + if (server->conn_type == CLI_PROV) { +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_prov_node_get_link()->conn == conn) { + for (size_t i = 0; i < ARRAY_SIZE(waiting_conn_link); i++) { + if (waiting_conn_link[i].link->conn == conn) { + memset(&waiting_conn_link[i].addr, 0, sizeof(bt_mesh_addr_t)); + break; + } + } + + bt_mesh_pb_gatt_close(conn, reason); + } else +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + { + bt_mesh_provisioner_pb_gatt_close(conn, reason); + } } -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT && (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT - if (server->conn_type == PROXY) { + if (server->conn_type == CLI_PROXY) { if (proxy_client_disconnect_cb) { proxy_client_disconnect_cb(addr, server - servers, server->net_idx, reason); } @@ -444,15 +516,14 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, k_delayed_work_cancel(&server->sar_timer); server->conn = NULL; - server->conn_type = NONE; + server->conn_type = CLI_NONE; #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; #endif - - return; } -#if CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT +#if CONFIG_BLE_MESH_PB_GATT && \ + (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); @@ -462,13 +533,21 @@ static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) return -ENOTCONN; } - if (server->conn_type == NONE) { - server->conn_type = PROV; + if (server->conn_type == CLI_NONE) { + server->conn_type = CLI_PROV; - if (bt_mesh_provisioner_set_prov_conn(addr->val, server->conn)) { - bt_mesh_gattc_disconnect(server->conn); - return -EIO; +#if CONFIG_BLE_MESH_RPR_SRV + if (bt_mesh_prov_node_get_link()->conn == conn) { + int err = bt_mesh_pb_gatt_open(conn); + if (err) { + BT_ERR("proxy write ccc error %d", err); + return err; + } + + return bt_mesh_rpr_srv_recv_link_ack(addr->val, false); } +#endif + return bt_mesh_provisioner_pb_gatt_open(conn, addr->val); } @@ -484,7 +563,7 @@ static ssize_t prov_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t return -ENOTCONN; } - if (server->conn_type == PROV) { + if (server->conn_type == CLI_PROV) { return proxy_recv(conn, NULL, data, len, 0, 0); } @@ -495,11 +574,9 @@ int bt_mesh_proxy_client_prov_enable(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { - servers[i].conn_type = PROV; + servers[i].conn_type = CLI_PROV; } } @@ -510,22 +587,20 @@ int bt_mesh_proxy_client_prov_disable(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; - if (server->conn && server->conn_type == PROV) { + if (server->conn && server->conn_type == CLI_PROV) { bt_mesh_gattc_disconnect(server->conn); - server->conn_type = NONE; + server->conn_type = CLI_NONE; } } return 0; } -#endif /* CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT */ +#endif /* CONFIG_BLE_MESH_PB_GATT */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); @@ -535,8 +610,8 @@ static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) return -ENOTCONN; } - if (server->conn_type == NONE) { - server->conn_type = PROXY; + if (server->conn_type == CLI_NONE) { + server->conn_type = CLI_PROXY; if (proxy_client_connect_cb) { proxy_client_connect_cb(addr, server - servers, server->net_idx); @@ -556,7 +631,7 @@ static ssize_t proxy_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t return -ENOTCONN; } - if (server->conn_type == PROXY) { + if (server->conn_type == CLI_PROXY) { return proxy_recv(conn, NULL, data, len, 0, 0); } @@ -575,16 +650,13 @@ int bt_mesh_proxy_client_gatt_enable(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { - servers[i].conn_type = PROXY; + servers[i].conn_type = CLI_PROXY; } } - /** - * TODO: + /* TODO: * Once at least one device has been provisioned, proxy client can be * set to allow receiving and parsing node_id & net_id adv packets, * and we may use a global flag to indicate this. @@ -597,8 +669,6 @@ int bt_mesh_proxy_client_gatt_disable(void) { int i; - BT_DBG("%s", __func__); - /** * TODO: * Once this function is invoked, proxy client shall stop handling @@ -609,9 +679,9 @@ int bt_mesh_proxy_client_gatt_disable(void) for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; - if (server->conn && server->conn_type == PROXY) { + if (server->conn && server->conn_type == CLI_PROXY) { bt_mesh_gattc_disconnect(server->conn); - server->conn_type = NONE; + server->conn_type = CLI_NONE; } } @@ -626,13 +696,13 @@ static struct bt_mesh_prov_conn_cb conn_callbacks = { .prov_write_descr = prov_write_ccc, .prov_notify = prov_recv_ntf, #endif /* CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT .proxy_write_descr = proxy_write_ccc, .proxy_notify = proxy_recv_ntf, #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ }; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_CLIENT) +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT static struct bt_mesh_subnet *bt_mesh_is_net_id_exist(const uint8_t net_id[8]) { struct bt_mesh_subnet *sub = NULL; @@ -688,6 +758,12 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, * the hash value (8 octets) with the received one. */ return; + case BLE_MESH_PROXY_ADV_PRIVATE_NET_ID: + BT_DBG("Mesh Proxy Private Network ID adv 0x%02x", type); + return; + case BLE_MESH_PROXY_ADV_PRIVATE_NODE_ID: + BT_DBG("Mesh Proxy Private Node Identity adv 0x%02x", type); + return; default: BT_DBG("Unknown Mesh Proxy adv type 0x%02x", type); return; @@ -752,14 +828,14 @@ bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst) struct bt_mesh_proxy_server *server = &servers[i]; NET_BUF_SIMPLE_DEFINE(msg, 32); - if (!server->conn || server->conn_type != PROXY) { + if (!server->conn || server->conn_type != CLI_PROXY) { continue; } /* Proxy PDU sending modifies the original buffer, * so we need to make a copy. */ - net_buf_simple_init(&msg, 1); + net_buf_simple_reserve(&msg, 1); net_buf_simple_add_mem(&msg, buf->data, buf->len); err = bt_mesh_proxy_client_send(server->conn, BLE_MESH_PROXY_NET_PDU, &msg); @@ -774,29 +850,36 @@ bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst) return send; } -static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub) +static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub, bool private) { - NET_BUF_SIMPLE_DEFINE(buf, 23); + NET_BUF_SIMPLE_DEFINE(buf, 28); - net_buf_simple_init(&buf, 1); - bt_mesh_beacon_create(sub, &buf); + net_buf_simple_reserve(&buf, 1); +#if CONFIG_BLE_MESH_PRB_SRV + if (private) { + bt_mesh_private_beacon_create(sub, &buf); + } else +#endif + { + bt_mesh_secure_beacon_create(sub, &buf); + } return bt_mesh_proxy_client_send(conn, BLE_MESH_PROXY_BEACON, &buf); } -bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub) +bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub, bool private) { bool send = false; int err = 0; int i; - /* NULL means we send Secure Network Beacon on all subnets */ + /* NULL means we send Secure Network Beacon or Mesh Private Beacon on all subnets */ if (!sub) { #if CONFIG_BLE_MESH_NODE if (bt_mesh_is_provisioned()) { for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx != BLE_MESH_KEY_UNUSED) { - send = bt_mesh_proxy_client_beacon_send(&bt_mesh.sub[i]); + send = bt_mesh_proxy_client_beacon_send(&bt_mesh.sub[i], private); } } return send; @@ -806,7 +889,7 @@ bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub) if (bt_mesh_is_provisioner_en()) { for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { if (bt_mesh.p_sub[i] && bt_mesh.p_sub[i]->net_idx != BLE_MESH_KEY_UNUSED) { - send = bt_mesh_proxy_client_beacon_send(bt_mesh.p_sub[i]); + send = bt_mesh_proxy_client_beacon_send(bt_mesh.p_sub[i], private); } } return send; @@ -816,8 +899,8 @@ bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub) } for (i = 0; i < ARRAY_SIZE(servers); i++) { - if (servers[i].conn && servers[i].conn_type == PROXY) { - err = beacon_send(servers[i].conn, sub); + if (servers[i].conn && servers[i].conn_type == CLI_PROXY) { + err = beacon_send(servers[i].conn, sub, private); if (err) { BT_ERR("Failed to send proxy beacon message (err %d)", err); } else { @@ -832,10 +915,11 @@ bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub) static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt_mesh_proxy_cfg_pdu *cfg) { struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, /* CTL shall be set to 1 */ - .addr = BLE_MESH_ADDR_UNASSIGNED, /* DST shall be set to the unassigned address */ - .send_ttl = 0U, /* TTL shall be set to 0 */ + .net_idx = net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, /* CTL shall be set to 1 */ + .addr = BLE_MESH_ADDR_UNASSIGNED, /* DST shall be set to the unassigned address */ + .send_ttl = 0U, /* TTL shall be set to 0 */ + .send_cred = BLE_MESH_FLOODING_CRED, }; struct bt_mesh_net_tx tx = { .ctx = &ctx, @@ -845,13 +929,9 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt uint16_t alloc_len = 0U; int err = 0; - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { - tx.sub = bt_mesh_subnet_get(net_idx); - } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { - tx.sub = bt_mesh_provisioner_subnet_get(net_idx); - } + tx.sub = bt_mesh_subnet_get(net_idx); if (!tx.sub) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("NetKey 0x%04x not found", net_idx); return -EIO; } @@ -864,6 +944,7 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt alloc_len = sizeof(cfg->opcode) + sizeof(cfg->set.filter_type); break; + case BLE_MESH_PROXY_CFG_FILTER_ADD: if (cfg->add.addr == NULL || cfg->add.addr_num == 0) { BT_ERR("Empty proxy addr list to add"); @@ -872,6 +953,7 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt alloc_len = sizeof(cfg->opcode) + (cfg->add.addr_num << 1); break; + case BLE_MESH_PROXY_CFG_FILTER_REMOVE: if (cfg->remove.addr == NULL || cfg->remove.addr_num == 0) { BT_ERR("Empty proxy addr list to remove"); @@ -880,14 +962,33 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt alloc_len = sizeof(cfg->opcode) + (cfg->remove.addr_num << 1); break; + +#if CONFIG_BLE_MESH_DF_SRV + case BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL: + if (cfg->direct_proxy_ctrl.use_directed > BLE_MESH_PROXY_USE_DIRECTED_ENABLED) { + BT_ERR("Invalid Use Directed 0x%02x", cfg->direct_proxy_ctrl.use_directed); + return -EINVAL; + } + + if (cfg->direct_proxy_ctrl.use_directed == BLE_MESH_PROXY_USE_DIRECTED_ENABLED && + !bt_mesh_uar_valid(&cfg->direct_proxy_ctrl.proxy_client_uar)) { + BT_ERR("Invalid Proxy Client Unicast Addr Range (0x%04x, %d)", + cfg->direct_proxy_ctrl.proxy_client_uar.range_start, + cfg->direct_proxy_ctrl.proxy_client_uar.range_length); + return -EINVAL; + } + + alloc_len = sizeof(cfg->opcode) + 4; + break; +#endif /* CONFIG_BLE_MESH_DF_SRV */ + default: BT_ERR("Unknown Proxy Configuration opcode 0x%02x", cfg->opcode); return -EINVAL; } - /** - * For Proxy Configuration PDU: - * 1 octet Proxy PDU type + 9 octets network pdu header + Tranport PDU + 8 octets NetMIC + /* For Proxy Configuration PDU: + * 1 octet Proxy PDU type + 9 octets network pdu header + Transport PDU + 8 octets NetMIC */ buf = bt_mesh_alloc_buf(1 + BLE_MESH_NET_HDR_LEN + alloc_len + 8); if (!buf) { @@ -902,32 +1003,43 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt case BLE_MESH_PROXY_CFG_FILTER_SET: net_buf_simple_add_u8(buf, cfg->set.filter_type); break; + case BLE_MESH_PROXY_CFG_FILTER_ADD: for (uint16_t i = 0U; i < cfg->add.addr_num; i++) { net_buf_simple_add_le16(buf, cfg->add.addr[i]); } break; + case BLE_MESH_PROXY_CFG_FILTER_REMOVE: for (uint16_t i = 0U; i < cfg->remove.addr_num; i++) { net_buf_simple_add_le16(buf, cfg->remove.addr[i]); } break; + +#if CONFIG_BLE_MESH_DF_SRV + case BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL: + net_buf_simple_add_u8(buf, cfg->direct_proxy_ctrl.use_directed); + if (cfg->direct_proxy_ctrl.use_directed == BLE_MESH_PROXY_USE_DIRECTED_ENABLED) { + bt_mesh_add_uar_be(buf, &cfg->direct_proxy_ctrl.proxy_client_uar); + } + break; +#endif /* CONFIG_BLE_MESH_DF_SRV */ } BT_DBG("len %u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy message failed (err %d)", err); - bt_mesh_free_buf(buf); - return err; + BT_ERR("Encoding proxy cfg message failed (err %d)", err); + goto end; } err = bt_mesh_proxy_client_send(conn, BLE_MESH_PROXY_CONFIG, buf); if (err) { - BT_ERR("Failed to send proxy cfg message (err %d)", err); + BT_ERR("Failed to send proxy cfg message 0x%02x (err %d)", cfg->opcode, err); } +end: bt_mesh_free_buf(buf); return err; } @@ -937,7 +1049,7 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, { struct bt_mesh_conn *conn = NULL; - if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || pdu->opcode > BLE_MESH_PROXY_CFG_FILTER_REMOVE) { + if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || pdu->opcode > BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } @@ -950,8 +1062,7 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, return -ENOTCONN; } - /** - * Check if net_idx used to encrypt Proxy Configuration are the same + /* Check if net_idx used to encrypt Proxy Configuration are the same * with the one added when creating proxy connection. */ if (servers[conn_handle].net_idx != net_idx) { @@ -973,8 +1084,8 @@ int bt_mesh_proxy_client_init(void) struct bt_mesh_proxy_server *server = &servers[i]; k_delayed_work_init(&server->sar_timer, proxy_sar_timeout); - server->buf.size = SERVER_BUF_SIZE; - server->buf.__buf = server_buf_data + (i * SERVER_BUF_SIZE); + server->buf.size = BLE_MESH_PROXY_BUF_SIZE; + server->buf.__buf = server_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; #endif @@ -984,7 +1095,8 @@ int bt_mesh_proxy_client_init(void) #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN && CONFIG_BLE_MESH_GATT_PROXY_CLIENT bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, - BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV, NULL); + BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV, + NULL); #endif return 0; @@ -1010,4 +1122,5 @@ int bt_mesh_proxy_client_deinit(void) } #endif /* CONFIG_BLE_MESH_DEINIT */ -#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ diff --git a/components/bt/esp_ble_mesh/core/proxy_client.h b/components/bt/esp_ble_mesh/core/proxy_client.h index f7a9d509ea..d2d8501701 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.h +++ b/components/bt/esp_ble_mesh/core/proxy_client.h @@ -9,24 +9,14 @@ #include "net.h" #include "mesh/adapter.h" +#include "prov_common.h" + +#include "mesh_v1.1/utils.h" #ifdef __cplusplus extern "C" { #endif -#define BLE_MESH_PROXY_ADV_NET_ID 0x00 -#define BLE_MESH_PROXY_ADV_NODE_ID 0x01 - -#define BLE_MESH_PROXY_NET_PDU 0x00 -#define BLE_MESH_PROXY_BEACON 0x01 -#define BLE_MESH_PROXY_CONFIG 0x02 -#define BLE_MESH_PROXY_PROV 0x03 - -#define BLE_MESH_PROXY_CFG_FILTER_SET 0x00 -#define BLE_MESH_PROXY_CFG_FILTER_ADD 0x01 -#define BLE_MESH_PROXY_CFG_FILTER_REMOVE 0x02 -#define BLE_MESH_PROXY_CFG_FILTER_STATUS 0x03 - typedef union { struct { uint8_t net_id[8]; @@ -35,6 +25,13 @@ typedef union { struct { uint16_t src; } node_id; + struct { + uint8_t net_id[8]; + uint16_t net_idx; + } private_net_id; + struct { + uint16_t src; + } private_node_id; } bt_mesh_proxy_adv_ctx_t; struct bt_mesh_proxy_net_pdu { @@ -55,6 +52,14 @@ struct bt_mesh_proxy_cfg_pdu { uint16_t *addr; uint16_t addr_num; } remove; + struct cfg_direct_proxy_ctrl { + uint8_t use_directed; + struct { + uint16_t len_present:1, + range_start:15; + uint8_t range_length; + } proxy_client_uar; + } direct_proxy_ctrl; }; }; @@ -95,13 +100,18 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, int bt_mesh_proxy_client_connect(const uint8_t addr[6], uint8_t addr_type, uint16_t net_idx); int bt_mesh_proxy_client_disconnect(uint8_t conn_handle); -bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub); +bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub, bool private); bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst); int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, struct bt_mesh_proxy_cfg_pdu *pdu); +#if CONFIG_BLE_MESH_RPR_SRV +int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link* link, + bt_mesh_addr_t *addr); +#endif + int bt_mesh_proxy_client_init(void); int bt_mesh_proxy_client_deinit(void); diff --git a/components/bt/esp_ble_mesh/core/proxy_common.h b/components/bt/esp_ble_mesh/core/proxy_common.h new file mode 100644 index 0000000000..4ffb5e95f6 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/proxy_common.h @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PROXY_COMMON_H_ +#define _PROXY_COMMON_H_ + +#include "mesh/config.h" +#include "mesh/utils.h" +#include "mesh/timer.h" +#include "net.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_MESH_PROXY_ADV_NET_ID 0x00 +#define BLE_MESH_PROXY_ADV_NODE_ID 0x01 +#define BLE_MESH_PROXY_ADV_PRIVATE_NET_ID 0x02 +#define BLE_MESH_PROXY_ADV_PRIVATE_NODE_ID 0x03 + +#define BLE_MESH_PROXY_NET_PDU 0x00 +#define BLE_MESH_PROXY_BEACON 0x01 +#define BLE_MESH_PROXY_CONFIG 0x02 +#define BLE_MESH_PROXY_PROV 0x03 + +#define BLE_MESH_PROXY_SAR_COMP 0x00 +#define BLE_MESH_PROXY_SAR_FIRST 0x01 +#define BLE_MESH_PROXY_SAR_CONT 0x02 +#define BLE_MESH_PROXY_SAR_LAST 0x03 + +#define BLE_MESH_PROXY_CFG_FILTER_SET 0x00 +#define BLE_MESH_PROXY_CFG_FILTER_ADD 0x01 +#define BLE_MESH_PROXY_CFG_FILTER_REMOVE 0x02 +#define BLE_MESH_PROXY_CFG_FILTER_STATUS 0x03 +#define BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CAPS_STATUS 0x04 +#define BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL 0x05 + +#define BLE_MESH_PROXY_PRIVACY_DISABLED 0x00 +#define BLE_MESH_PROXY_PRIVACY_ENABLED 0x01 +#define BLE_MESH_PROXY_PRIVACY_NOT_SUPPORTED 0x02 + +#define BLE_MESH_PROXY_CLI_TYPE_UNSET BIT(0) +#define BLE_MESH_PROXY_CLI_TYPE_DIRECT_PROXY_CLIENT BIT(1) +#define BLE_MESH_PROXY_CLI_TYPE_BLACK_LIST_CLIENT BIT(2) +#define BLE_MESH_PROXY_CLI_TYPE_PROXY_CLIENT BIT(3) + +#define BLE_MESH_PROXY_PDU_TYPE(data) (data[0] & BIT_MASK(6)) +#define BLE_MESH_PROXY_PDU_SAR(data) (data[0] >> 6) + +#define BLE_MESH_PROXY_PDU_HDR(sar, type) ((sar) << 6 | ((type) & BIT_MASK(6))) + +/* Mesh spec 1.0.1 Section 6.6: + * "The timeout for the SAR transfer is 20 seconds. When the timeout + * expires, the Proxy Server shall disconnect." + */ +#define BLE_MESH_PROXY_SAR_TIMEOUT K_SECONDS(20) + +#define BLE_MESH_PROXY_BUF_SIZE 68 + +#ifdef __cplusplus +} +#endif + +#endif /* _PROXY_COMMON_H_ */ diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index bf907303a2..aa360b85f8 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -10,48 +10,40 @@ #include #include "mesh.h" +#include "rpl.h" #include "adv.h" -#include "prov_node.h" #include "beacon.h" #include "access.h" #include "transport.h" #include "foundation.h" #include "mesh/common.h" +#include "proxy_common.h" #include "proxy_server.h" +#include "prov_common.h" +#include "prov_node.h" + +#include "mesh_v1.1/utils.h" #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER #if !CONFIG_BLE_MESH_BQB_TEST /* Not support enabling Proxy Client and Proxy Server simultaneously */ -_Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) &&IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)), +_Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)), "Not support Proxy Server and Proxy Client simultaneously"); #endif -#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) -#define PDU_SAR(data) (data[0] >> 6) +#define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) -/* Mesh Profile 1.0 Section 6.6: - * "The timeout for the SAR transfer is 20 seconds. When the timeout - * expires, the Proxy Server shall disconnect." +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV +#define RAND_UPDATE_INTERVAL K_MINUTES(10) + +/* The Random field of Private Network Identity + * Advertisement should be updated every 10 minutes. */ -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define SAR_COMPLETE 0x00 -#define SAR_FIRST 0x01 -#define SAR_CONT 0x02 -#define SAR_LAST 0x03 - -#define CFG_FILTER_SET 0x00 -#define CFG_FILTER_ADD 0x01 -#define CFG_FILTER_REMOVE 0x02 -#define CFG_FILTER_STATUS 0x03 - -#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) - -#define CLIENT_BUF_SIZE 68 - -#define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) +static struct k_delayed_work rand_upd_timer; +static uint8_t net_id_random[8] = {0}; +#endif static const struct bt_mesh_adv_param slow_adv_param = { .options = ADV_OPT, @@ -67,37 +59,26 @@ static const struct bt_mesh_adv_param fast_adv_param = { static bool proxy_adv_enabled; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER static void proxy_send_beacons(struct k_work *work); static uint16_t proxy_ccc_val; #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT static uint16_t prov_ccc_val; static bool prov_fast_adv; static uint32_t prov_start_time; #endif -static struct bt_mesh_proxy_client { - struct bt_mesh_conn *conn; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) - uint16_t filter[CONFIG_BLE_MESH_PROXY_FILTER_SIZE]; +static struct bt_mesh_proxy_client clients[BLE_MESH_MAX_CONN] = { + [0 ... (BLE_MESH_MAX_CONN - 1)] = { +#if CONFIG_BLE_MESH_PROXY_PRIVACY + .proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED, #endif - enum __packed { - NONE, - WHITELIST, - BLACKLIST, - PROV, - } filter_type; - uint8_t msg_type; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) - struct k_work send_beacons; -#endif - struct k_delayed_work sar_timer; - struct net_buf_simple buf; -} clients[BLE_MESH_MAX_CONN]; + }, +}; -static uint8_t client_buf_data[CLIENT_BUF_SIZE * BLE_MESH_MAX_CONN]; +static uint8_t client_buf_data[BLE_MESH_PROXY_BUF_SIZE * BLE_MESH_MAX_CONN]; /* Track which service is enabled */ static enum { @@ -108,6 +89,16 @@ static enum { static char device_name[DEVICE_NAME_SIZE + 1]; +struct bt_mesh_proxy_client *bt_mesh_proxy_server_get_client(uint8_t index) +{ + return &clients[0]; +} + +uint8_t bt_mesh_proxy_server_get_client_count(void) +{ + return ARRAY_SIZE(clients); +} + int bt_mesh_set_device_name(const char *name) { if (!name) { @@ -126,6 +117,11 @@ int bt_mesh_set_device_name(const char *name) return bt_mesh_gatts_set_local_device_name(device_name); } +const char *bt_mesh_get_device_name(void) +{ + return device_name; +} + static struct bt_mesh_proxy_client *find_client(struct bt_mesh_conn *conn) { int i; @@ -155,7 +151,7 @@ static void proxy_sar_timeout(struct k_work *work) bt_mesh_gatts_disconnect(client->conn, 0x13); } -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER /** * The following callbacks are used to notify proper information * to the application layer. @@ -176,8 +172,37 @@ void bt_mesh_proxy_server_set_disconn_cb(proxy_server_disconnect_cb_t cb) /* Next subnet in queue to be advertised */ static int next_idx; -static int proxy_segment_and_send(struct bt_mesh_conn *conn, uint8_t type, - struct net_buf_simple *msg); +bool bt_mesh_proxy_server_find_client_by_addr(uint16_t addr) +{ + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn) { + for (size_t j = 0; j < ARRAY_SIZE(clients[i].filter); j++) { + if (clients[i].filter[j].proxy_client && clients[i].filter[j].addr == addr) { + return true; + } + } + } + } + + return false; +} + +uint8_t bt_mesh_proxy_server_get_all_client_type(void) +{ + uint8_t client_type = 0; + + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn) { + for (size_t j = 0; j < ARRAY_SIZE(clients[i].filter); j++) { + if (clients[i].filter[j].proxy_client) { + client_type |= clients[i].proxy_client_type; + } + } + } + } + + return client_type; +} static int filter_set(struct bt_mesh_proxy_client *client, struct net_buf_simple *buf) @@ -195,11 +220,14 @@ static int filter_set(struct bt_mesh_proxy_client *client, switch (type) { case 0x00: (void)memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = WHITELIST; + client->filter_type = SRV_WHITELIST; break; case 0x01: +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_proxy_server_set_blacklist(client); +#endif /* CONFIG_BLE_MESH_DF_SRV */ (void)memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = BLACKLIST; + client->filter_type = SRV_BLACKLIST; break; default: BT_WARN("Prohibited Filter Type 0x%02x", type); @@ -209,26 +237,41 @@ static int filter_set(struct bt_mesh_proxy_client *client, return 0; } -static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr) +static void filter_add(struct bt_mesh_proxy_client *client, + uint16_t addr, bool proxy_client) { int i; + /* The flag proxy_client is used to indicate if the added address + * is the element address of Proxy Client. + */ + BT_DBG("addr 0x%04x", addr); if (addr == BLE_MESH_ADDR_UNASSIGNED) { return; } + if (!BLE_MESH_ADDR_IS_UNICAST(addr) && proxy_client == true) { + BT_ERR("Invalid proxy client element addr 0x%04x", addr); + return; + } + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { + if (client->filter[i].addr == addr) { return; } } for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == BLE_MESH_ADDR_UNASSIGNED) { - client->filter[i] = addr; - BT_INFO("Add filter addr 0x%04x", addr); + if (client->filter[i].addr == addr) { + BT_INFO("client addr 0x%04x already added", addr); + return; + } + if (client->filter[i].addr == BLE_MESH_ADDR_UNASSIGNED) { + BT_INFO("Add client or filter addr 0x%04x", addr); + client->filter[i].addr = addr; + client->filter[i].proxy_client = proxy_client; return; } } @@ -247,8 +290,9 @@ static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) } for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - client->filter[i] = BLE_MESH_ADDR_UNASSIGNED; + if (client->filter[i].addr == addr) { + client->filter[i].addr = BLE_MESH_ADDR_UNASSIGNED; + client->filter[i].proxy_client = false; BT_INFO("Remove filter addr 0x%04x", addr); return; } @@ -269,20 +313,21 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, /* Configuration messages always have dst unassigned */ tx.ctx->addr = BLE_MESH_ADDR_UNASSIGNED; + tx.ctx->send_cred = BLE_MESH_FLOODING_CRED, net_buf_simple_reset(buf); net_buf_simple_reserve(buf, 10); - net_buf_simple_add_u8(buf, CFG_FILTER_STATUS); + net_buf_simple_add_u8(buf, BLE_MESH_PROXY_CFG_FILTER_STATUS); - if (client->filter_type == WHITELIST) { + if (client->filter_type == SRV_WHITELIST) { net_buf_simple_add_u8(buf, 0x00); } else { net_buf_simple_add_u8(buf, 0x01); } for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] != BLE_MESH_ADDR_UNASSIGNED) { + if (client->filter[i].addr != BLE_MESH_ADDR_UNASSIGNED) { filter_size++; } } @@ -293,13 +338,13 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy cfg message failed (err %d)", err); + BT_ERR("Encoding proxy filter status failed (err %d)", err); return; } - err = proxy_segment_and_send(client->conn, BLE_MESH_PROXY_CONFIG, buf); + err = bt_mesh_proxy_server_segment_send(client->conn, BLE_MESH_PROXY_CONFIG, buf); if (err) { - BT_ERR("Failed to send proxy cfg message (err %d)", err); + BT_ERR("Failed to send proxy filter status (err %d)", err); } } @@ -342,42 +387,70 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) opcode = net_buf_simple_pull_u8(&buf); switch (opcode) { - case CFG_FILTER_SET: + case BLE_MESH_PROXY_CFG_FILTER_SET: filter_set(client, &buf); send_filter_status(client, &rx, &buf); break; - case CFG_FILTER_ADD: - while (buf.len >= 2) { - uint16_t addr = 0U; - addr = net_buf_simple_pull_be16(&buf); - filter_add(client, addr); + case BLE_MESH_PROXY_CFG_FILTER_ADD: + while (buf.len >= 2) { + uint16_t addr = net_buf_simple_pull_be16(&buf); + filter_add(client, addr, rx.ctx.addr == addr); } send_filter_status(client, &rx, &buf); +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_proxy_server_solicitation(client, rx.sub); +#endif /* CONFIG_BLE_MESH_DF_SRV */ break; - case CFG_FILTER_REMOVE: - while (buf.len >= 2) { - uint16_t addr = 0U; - addr = net_buf_simple_pull_be16(&buf); + case BLE_MESH_PROXY_CFG_FILTER_REMOVE: + while (buf.len >= 2) { + uint16_t addr = net_buf_simple_pull_be16(&buf); filter_remove(client, addr); } send_filter_status(client, &rx, &buf); break; + +#if CONFIG_BLE_MESH_DF_SRV + case BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL: + if (buf.len < 1) { + BT_WARN("Invalid Directed Proxy Control (len %d)", buf.len); + break; + } + + if (rx.sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { + bt_mesh_directed_proxy_server_directed_proxy_ctrl_recv(client, &rx, &buf); + } + break; +#endif /* CONFIG_BLE_MESH_DF_SRV */ + default: BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); break; } } -static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub) +static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub) { - NET_BUF_SIMPLE_DEFINE(buf, 23); + NET_BUF_SIMPLE_DEFINE(buf, 28); net_buf_simple_reserve(&buf, 1); - bt_mesh_beacon_create(sub, &buf); - return proxy_segment_and_send(conn, BLE_MESH_PROXY_BEACON, &buf); +#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); + } else +#endif + { + bt_mesh_secure_beacon_create(sub, &buf); + } + + return bt_mesh_proxy_server_segment_send(client->conn, BLE_MESH_PROXY_BEACON, &buf); } static void proxy_send_beacons(struct k_work *work) @@ -387,12 +460,56 @@ static void proxy_send_beacons(struct k_work *work) client = CONTAINER_OF(work, struct bt_mesh_proxy_client, send_beacons); + /* Upon connection, the Proxy Server shall evaluate Proxy Privacy parameter + * for the connection and the Proxy Server shall retain the value of the + * Proxy Privacy parameter for the lifetime of the connection. The Proxy + * Server shall send a mesh beacon for each known subnet to the Proxy Client. + * + * When either the GATT Proxy state or the Node Identity state is enabled, + * the Proxy Privacy parameter for the connection shall be Disabled. + * + * When both the GATT Proxy state and the Node Identity state are disabled, + * and either the Private GATT Proxy state or the Private Node Identity state + * is enabled, the Proxy Privacy parameter for the connection shall be Enabled. + */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - if (sub->net_idx != BLE_MESH_KEY_UNUSED) { - beacon_send(client->conn, sub); +#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); + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ + } + +#if 0 + if (sub->net_idx != BLE_MESH_KEY_UNUSED) { + if (sub->proxy_privacy == BLE_MESH_PROXY_PRIVACY_DISABLED) { + beacon_send(client->conn, sub); + } else if (sub->proxy_privacy == BLE_MESH_PROXY_PRIVACY_ENABLED) { +#if CONFIG_BLE_MESH_PRB_SRV + /* TODO: Send Mesh Private Beacon */ +#endif + } + } +#endif } } @@ -413,7 +530,7 @@ void bt_mesh_proxy_server_beacon_send(struct bt_mesh_subnet *sub) for (i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn) { - beacon_send(clients[i].conn, sub); + beacon_send(&clients[i], sub); } } } @@ -437,8 +554,6 @@ int bt_mesh_proxy_identity_enable(void) { int i, count = 0; - BT_DBG("%s", __func__); - if (!bt_mesh_is_provisioned()) { return -EAGAIN; } @@ -465,12 +580,74 @@ int bt_mesh_proxy_identity_enable(void) return 0; } +#if CONFIG_BLE_MESH_PRB_SRV +void bt_mesh_proxy_server_private_identity_start(struct bt_mesh_subnet *sub) +{ + sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING; + sub->node_id_start = k_uptime_get_32(); + + /* Prioritize the recently enabled subnet */ + next_idx = sub - bt_mesh.sub; +} + +void bt_mesh_proxy_server_private_identity_stop(struct bt_mesh_subnet *sub) +{ + sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED; + sub->node_id_start = 0U; +} + +bool bt_mesh_proxy_server_is_node_id_enable(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + /* If the Node Identity state of the node for any subnet + * is 0x01 (i.e. running), return true. + */ + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx != BLE_MESH_KEY_UNUSED && + sub->node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { + return true; + } + } + + return false; +} + +static bool is_exist_private_node_id_enable(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + /* If the value of the Node Identity state of the node + * for any subnet is 0x01,If exist return true. + */ + struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; + + if (sub->net_idx != BLE_MESH_KEY_UNUSED && + sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { + return true; + } + } + + return false; +} + +void disable_all_private_node_identity(void) +{ + 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); + } + } +} +#endif /* CONFIG_BLE_MESH_PRB_SRV */ #endif /* GATT_PROXY */ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) { switch (client->msg_type) { -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER case BLE_MESH_PROXY_NET_PDU: BT_DBG("Mesh Network PDU"); bt_mesh_net_recv(&client->buf, 0, BLE_MESH_NET_IF_PROXY); @@ -484,7 +661,7 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) proxy_cfg(client); break; #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT case BLE_MESH_PROXY_PROV: BT_DBG("Mesh Provisioning PDU"); bt_mesh_pb_gatt_recv(client->conn, &client->buf); @@ -496,6 +673,31 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) } net_buf_simple_reset(&client->buf); + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + if (client->msg_type < BLE_MESH_PROXY_PROV && + client->proxy_msg_recv == false) { + client->proxy_msg_recv = true; + /** + * @Spec: P626 + * When a new connection is established between a Proxy Client and the Directed Proxy Server, and the + * first message received from the Proxy Client is a successfully processed DIRECTED_PROXY_CONTROL + * message, then the Directed Proxy Server shall set the Proxy_Client_Type parameter to Directed Proxy Client, + * shall set the Use_Directed parameter to Disable for all subnets known to the Directed Proxy Server + * except the subnet identified by the received message; + * otherwise, the Directed Proxy Server shall set the Proxy_Client_Type parameter to Proxy Client. + * + * If the first message received is DIRECTED_PROXY_CONTROL, proxy_client_type will be set to Directed Proxy Client, + * But if device didn't receive DIRECTED_PROXY_CONTROL message and all received is normal proxy message, That + * client type will be always in UNSET state, because we set client type in handle function of DIRECTED_PROXY_CONTROL. + * + * So the flowing code was used to avoid that situation. + */ + if (client->proxy_client_type == BLE_MESH_PROXY_CLI_TYPE_UNSET) { + client->proxy_client_type = BLE_MESH_PROXY_CLI_TYPE_PROXY_CLIENT; + } + } +#endif } #define ATTR_IS_PROV(attr) (attr->user_data != NULL) @@ -508,6 +710,7 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, const uint8_t *data = buf; if (!client) { + BT_ERR("No Proxy Client found"); return -ENOTCONN; } @@ -516,7 +719,7 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, return -EINVAL; } - if (ATTR_IS_PROV(attr) != (PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { + if (ATTR_IS_PROV(attr) != (BLE_MESH_PROXY_PDU_TYPE(data) == BLE_MESH_PROXY_PROV)) { BT_WARN("Proxy PDU type doesn't match GATT service"); return -EINVAL; } @@ -526,51 +729,51 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, return -EINVAL; } - switch (PDU_SAR(data)) { - case SAR_COMPLETE: + switch (BLE_MESH_PROXY_PDU_SAR(data)) { + case BLE_MESH_PROXY_SAR_COMP: if (client->buf.len) { BT_WARN("Complete PDU while a pending incomplete one"); return -EINVAL; } - client->msg_type = PDU_TYPE(data); + client->msg_type = BLE_MESH_PROXY_PDU_TYPE(data); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); proxy_complete_pdu(client); break; - case SAR_FIRST: + case BLE_MESH_PROXY_SAR_FIRST: if (client->buf.len) { BT_WARN("First PDU while a pending incomplete one"); return -EINVAL; } - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - client->msg_type = PDU_TYPE(data); + k_delayed_work_submit(&client->sar_timer, BLE_MESH_PROXY_SAR_TIMEOUT); + client->msg_type = BLE_MESH_PROXY_PDU_TYPE(data); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); break; - case SAR_CONT: + case BLE_MESH_PROXY_SAR_CONT: if (!client->buf.len) { BT_WARN("Continuation with no prior data"); return -EINVAL; } - if (client->msg_type != PDU_TYPE(data)) { + if (client->msg_type != BLE_MESH_PROXY_PDU_TYPE(data)) { BT_WARN("Unexpected message type in continuation"); return -EINVAL; } - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); + k_delayed_work_submit(&client->sar_timer, BLE_MESH_PROXY_SAR_TIMEOUT); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); break; - case SAR_LAST: + case BLE_MESH_PROXY_SAR_LAST: if (!client->buf.len) { BT_WARN("Last SAR PDU with no prior data"); return -EINVAL; } - if (client->msg_type != PDU_TYPE(data)) { + if (client->msg_type != BLE_MESH_PROXY_PDU_TYPE(data)) { BT_WARN("Unexpected message type in last SAR PDU"); return -EINVAL; } @@ -598,6 +801,14 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) /* Since we use ADV_OPT_ONE_TIME */ proxy_adv_enabled = false; +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX + /* Before re-enabling advertising, stop advertising + * the Service Data associated with the Private + * Network Identity type. + */ + bt_mesh_proxy_server_stop_solic_adv_priv_net_id(); +#endif + /* Try to re-enable advertising in case it's possible */ if (conn_count < BLE_MESH_MAX_CONN) { bt_mesh_adv_update(); @@ -616,8 +827,8 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) } client->conn = bt_mesh_conn_ref(conn); - client->filter_type = NONE; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + client->filter_type = SRV_NONE; +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER (void)memset(client->filter, 0, sizeof(client->filter)); if (proxy_server_connect_cb) { @@ -645,10 +856,18 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) } #endif if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && - client->filter_type == PROV) { - bt_mesh_pb_gatt_close(conn); + client->filter_type == SRV_PROV) { + bt_mesh_pb_gatt_close(conn, reason); } +#if CONFIG_BLE_MESH_PROXY_PRIVACY + client->proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED; +#endif + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV + k_delayed_work_cancel(&rand_upd_timer); +#endif + k_delayed_work_cancel(&client->sar_timer); bt_mesh_conn_unref(client->conn); client->conn = NULL; @@ -657,6 +876,17 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) } bt_mesh_adv_update(); + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_DF_SRV + if (i == ARRAY_SIZE(clients)) { + BT_WARN("Proxy disconnected, but no connection found"); + return; + } + + if (bt_mesh_directed_proxy_server_update_dep_node(NULL, &clients[i], 0)) { + BT_ERR("Proxy disconnected, failed to update dependent node"); + } +#endif /* CONFIG_BLE_MESH_DF_SRV */ } struct net_buf_simple *bt_mesh_proxy_server_get_buf(void) @@ -668,7 +898,7 @@ struct net_buf_simple *bt_mesh_proxy_server_get_buf(void) return buf; } -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT static ssize_t prov_ccc_write(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, const void *buf, uint16_t len, @@ -696,8 +926,8 @@ static ssize_t prov_ccc_write(struct bt_mesh_conn *conn, return 0; } - if (client->filter_type == NONE) { - client->filter_type = PROV; + if (client->filter_type == SRV_NONE) { + client->filter_type = SRV_PROV; bt_mesh_pb_gatt_open(conn); } @@ -739,8 +969,6 @@ int bt_mesh_proxy_server_prov_enable(void) { int i; - BT_DBG("%s", __func__); - if (gatt_svc == MESH_GATT_PROV) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -757,7 +985,7 @@ int bt_mesh_proxy_server_prov_enable(void) for (i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn) { - clients[i].filter_type = PROV; + clients[i].filter_type = SRV_PROV; } } @@ -769,8 +997,6 @@ int bt_mesh_proxy_server_prov_disable(bool disconnect) { int i; - BT_DBG("%s", __func__); - if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -787,15 +1013,15 @@ int bt_mesh_proxy_server_prov_disable(bool disconnect) for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; - if (!client->conn || client->filter_type != PROV) { + if (!client->conn || client->filter_type != SRV_PROV) { continue; } if (disconnect) { bt_mesh_gatts_disconnect(client->conn, 0x13); } else { - bt_mesh_pb_gatt_close(client->conn); - client->filter_type = NONE; + bt_mesh_pb_gatt_close(client->conn, CLOSE_REASON_SUCCESS); + client->filter_type = SRV_NONE; } } @@ -803,10 +1029,9 @@ int bt_mesh_proxy_server_prov_disable(bool disconnect) return 0; } - #endif /* CONFIG_BLE_MESH_PB_GATT */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER static ssize_t proxy_ccc_write(struct bt_mesh_conn *conn, const struct bt_mesh_gatt_attr *attr, const void *buf, uint16_t len, @@ -834,10 +1059,34 @@ static ssize_t proxy_ccc_write(struct bt_mesh_conn *conn, return 0; } - if (client->filter_type == NONE) { - client->filter_type = WHITELIST; - k_work_submit(&client->send_beacons); + /* Spec section 6.7 + * Upon connection, the Proxy Server shall evaluate Proxy Privacy parameter (for GATT Proxy bearer see + * Section 7.2.2.2.6) for the connection and the Proxy Server shall retain the value of the Proxy Privacy + * parameter for the lifetime of the connection. The Proxy Server shall send a mesh beacon for each known + * subnet to the Proxy Client + */ +#if CONFIG_BLE_MESH_PRB_SRV + if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED || + bt_mesh_proxy_server_is_node_id_enable()) { + client->proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED; + } else if (bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED || + is_exist_private_node_id_enable()) { + client->proxy_privacy = BLE_MESH_PROXY_PRIVACY_ENABLED; } +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + + if (client->filter_type == SRV_NONE) { + client->filter_type = SRV_WHITELIST; + k_delayed_work_submit(&client->send_beacons, K_MSEC(15)); + } + + if (client->proxy_client_type == 0) { + client->proxy_client_type = BLE_MESH_PROXY_CLI_TYPE_UNSET; + } + +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_proxy_server_connected(client); +#endif /* CONFIG_BLE_MESH_DF_SRV */ return len; } @@ -877,8 +1126,6 @@ int bt_mesh_proxy_server_gatt_enable(void) { int i; - BT_DBG("%s", __func__); - if (gatt_svc == MESH_GATT_PROXY) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -894,7 +1141,7 @@ int bt_mesh_proxy_server_gatt_enable(void) for (i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn) { - clients[i].filter_type = WHITELIST; + clients[i].filter_type = SRV_WHITELIST; } } @@ -905,14 +1152,12 @@ void bt_mesh_proxy_server_gatt_disconnect(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; - if (client->conn && (client->filter_type == WHITELIST || - client->filter_type == BLACKLIST)) { - client->filter_type = NONE; + if (client->conn && (client->filter_type == SRV_WHITELIST || + client->filter_type == SRV_BLACKLIST)) { + client->filter_type = SRV_NONE; bt_mesh_gatts_disconnect(client->conn, 0x13); } } @@ -920,8 +1165,6 @@ void bt_mesh_proxy_server_gatt_disconnect(void) int bt_mesh_proxy_server_gatt_disable(void) { - BT_DBG("%s", __func__); - if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -942,14 +1185,15 @@ int bt_mesh_proxy_server_gatt_disable(void) void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr) { - struct bt_mesh_proxy_client *client = - CONTAINER_OF(buf, struct bt_mesh_proxy_client, buf); + struct bt_mesh_proxy_client *client = CONTAINER_OF(buf, + struct bt_mesh_proxy_client, + buf); BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - if (client->filter_type == WHITELIST) { - filter_add(client, addr); - } else if (client->filter_type == BLACKLIST) { + if (client->filter_type == SRV_WHITELIST) { + filter_add(client, addr, true); + } else if (client->filter_type == SRV_BLACKLIST) { filter_remove(client, addr); } } @@ -961,9 +1205,9 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - if (client->filter_type == BLACKLIST) { + if (client->filter_type == SRV_BLACKLIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { + if (client->filter[i].addr == addr) { return false; } } @@ -975,9 +1219,9 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, return true; } - if (client->filter_type == WHITELIST) { + if (client->filter_type == SRV_WHITELIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { + if (client->filter[i].addr == addr) { return true; } } @@ -1024,13 +1268,13 @@ static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { BT_DBG("%u bytes: %s", len, bt_hex(data, len)); -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (gatt_svc == MESH_GATT_PROXY) { return bt_mesh_gatts_notify(conn, &proxy_attrs[4], data, len); } #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT if (gatt_svc == MESH_GATT_PROV) { return bt_mesh_gatts_notify(conn, &prov_attrs[4], data, len); } @@ -1039,8 +1283,8 @@ static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) return 0; } -static int proxy_segment_and_send(struct bt_mesh_conn *conn, uint8_t type, - struct net_buf_simple *msg) +int bt_mesh_proxy_server_segment_send(struct bt_mesh_conn *conn, uint8_t type, + struct net_buf_simple *msg) { uint16_t mtu = 0U; @@ -1050,22 +1294,22 @@ static int proxy_segment_and_send(struct bt_mesh_conn *conn, uint8_t type, /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu = bt_mesh_gatt_get_mtu(conn) - 3; if (mtu > msg->len) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_COMP, type)); return proxy_send(conn, msg->data, msg->len); } - net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_FIRST, type)); proxy_send(conn, msg->data, mtu); net_buf_simple_pull(msg, mtu); while (msg->len) { if (msg->len + 1 < mtu) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_LAST, type)); proxy_send(conn, msg->data, msg->len); break; } - net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_CONT, type)); proxy_send(conn, msg->data, mtu); net_buf_simple_pull(msg, mtu); } @@ -1083,15 +1327,15 @@ int bt_mesh_proxy_server_send(struct bt_mesh_conn *conn, uint8_t type, return -ENOTCONN; } - if ((client->filter_type == PROV) != (type == BLE_MESH_PROXY_PROV)) { + if ((client->filter_type == SRV_PROV) != (type == BLE_MESH_PROXY_PROV)) { BT_ERR("Invalid PDU type for Proxy Client"); return -EINVAL; } - return proxy_segment_and_send(conn, type, msg); + return bt_mesh_proxy_server_segment_send(conn, type, msg); } -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT static uint8_t prov_svc_data[20] = { 0x27, 0x18, }; static const struct bt_mesh_adv_data prov_ad[] = { @@ -1101,17 +1345,21 @@ static const struct bt_mesh_adv_data prov_ad[] = { }; #endif /* PB_GATT */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER -#define ID_TYPE_NET 0x00 -#define ID_TYPE_NODE 0x01 +#define NET_ID_LEN 11 +#define NODE_ID_LEN 19 +#define PRIVATE_NET_ID_LEN 19 +#define PRIVATE_NODE_ID_LEN 19 +#define PROXY_ADV_MAX_LEN 19 -#define NODE_ID_LEN 19 -#define NET_ID_LEN 11 +#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_NODE_ID_TIMEOUT) -#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_NODE_ID_TIMEOUT) - -static uint8_t proxy_svc_data[NODE_ID_LEN] = { 0x28, 0x18, }; +/* Note: + * The "proxy_svc_data" should be large enough to hold the maximum + * payload of the Node ID/Net ID/Private Node ID/Private Net ID. + */ +static uint8_t proxy_svc_data[PROXY_ADV_MAX_LEN] = { 0x28, 0x18, }; static const struct bt_mesh_adv_data node_id_ad[] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_FLAGS, (BLE_MESH_AD_GENERAL | BLE_MESH_AD_NO_BREDR)), @@ -1125,6 +1373,20 @@ 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 +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), + BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, proxy_svc_data, PRIVATE_NODE_ID_LEN), +}; + +static const struct bt_mesh_adv_data private_net_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), + BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, proxy_svc_data, PRIVATE_NET_ID_LEN), +}; +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + static size_t gatt_proxy_adv_create(struct bt_mesh_adv_data *proxy_sd) { const char *name = device_name; @@ -1152,9 +1414,7 @@ static int node_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; - BT_DBG("%s", __func__); - - proxy_svc_data[2] = ID_TYPE_NODE; + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NODE_ID; err = bt_mesh_rand(proxy_svc_data + 11, 8); if (err) { @@ -1191,9 +1451,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub) size_t proxy_sd_len = 0U; int err = 0; - BT_DBG("%s", __func__); - - proxy_svc_data[2] = ID_TYPE_NET; + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NET_ID; BT_DBG("Advertising with NetId %s", bt_hex(sub->keys[sub->kr_flag].net_id, 8)); @@ -1213,6 +1471,132 @@ static int net_id_adv(struct bt_mesh_subnet *sub) return 0; } +#if CONFIG_BLE_MESH_PRB_SRV +void bt_mesh_proxy_server_update_net_id_rand(void) +{ + k_delayed_work_submit(&rand_upd_timer, RAND_UPDATE_INTERVAL); +} + +void bt_mesh_proxy_server_update_net_id_rand_stop(void) +{ + k_delayed_work_cancel(&rand_upd_timer); +} + +static void random_update_timeout(struct k_work *work) +{ + int err = 0; + + err = bt_mesh_rand(net_id_random, 8); + if (err) { + BT_ERR("Generate random value failed"); + return; + } + + k_delayed_work_submit(&rand_upd_timer, RAND_UPDATE_INTERVAL); +} + +static int private_node_id_adv(struct bt_mesh_subnet *sub) +{ + struct bt_mesh_adv_data proxy_sd = {0}; + size_t proxy_sd_len = 0U; + uint8_t tmp[16] = {0}; + int err = 0; + + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NODE_ID; + + err = bt_mesh_rand(proxy_svc_data + 11, 8); + if (err) { + return err; + } + + memset(tmp, 0, 5); + tmp[5] = 0x03; + memcpy(tmp + 6, proxy_svc_data + 11, 8); + sys_put_be16(bt_mesh_primary_addr(), tmp + 14); + + err = bt_mesh_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp); + if (err) { + return err; + } + + memcpy(proxy_svc_data + 3, tmp + 8, 8); + proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); + + err = bt_le_adv_start(&fast_adv_param, private_node_id_ad, + ARRAY_SIZE(private_node_id_ad), &proxy_sd, proxy_sd_len); + if (err) { + BT_WARN("Failed to advertise with Private Node ID (err %d)", err); + return err; + } + + proxy_adv_enabled = true; + + 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 || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) +static int private_net_id_adv(struct bt_mesh_subnet *sub) +{ + struct bt_mesh_adv_data proxy_sd = {0}; + size_t proxy_sd_len = 0U; + uint8_t tmp[16] = {0}; + int err = 0; + + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NET_ID; + + /* TODO: + * The Private Network Identity advertisements shall use a resolvable private + * address or a non-resolvable private address in the AdvA field of the connectable + * advertising PDU. The address used for the AdvA field shall be regenerated + * whenever the Random field is regenerated. + */ + /* The Random field should be updated every 10 minutes. */ + memcpy(proxy_svc_data + 11, net_id_random, 8); + memcpy(tmp, sub->keys[sub->kr_flag].net_id, 8); + memcpy(tmp + 8, net_id_random, 8); + + err = bt_mesh_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp); + if (err) { + return err; + } + + memcpy(proxy_svc_data + 3, tmp + 8, 8); /* Hash */ + + proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); + + err = bt_le_adv_start(&fast_adv_param, private_net_id_ad, + ARRAY_SIZE(private_net_id_ad), &proxy_sd, proxy_sd_len); + if (err) { + BT_WARN("Failed to advertise with Private Net ID (err %d)", err); + return err; + } + + proxy_adv_enabled = true; + + return 0; +} +#endif /* (CONFIG_BLE_MESH_PRB_SRV || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) */ + static bool advertise_subnet(struct bt_mesh_subnet *sub) { if (sub->net_idx == BLE_MESH_KEY_UNUSED) { @@ -1220,7 +1604,12 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub) } return (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING || - bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED); + bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED +#if CONFIG_BLE_MESH_PRB_SRV + || sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING || + bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED +#endif + ); } static struct bt_mesh_subnet *next_sub(void) @@ -1236,8 +1625,7 @@ static struct bt_mesh_subnet *next_sub(void) } } - /** - * If among [next_idx, ARRAY_SIZE(bt_mesh.sub)], there is no subnet + /* If among [next_idx, ARRAY_SIZE(bt_mesh.sub)], there is no subnet * to advertise, then try to start advertising from Primary subnet. */ for (i = 0; i < next_idx; i++) { @@ -1270,11 +1658,10 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) { int32_t remaining = K_FOREVER; int subnet_count = 0; - - BT_DBG("%s", __func__); + uint32_t active = 0U; if (conn_count == BLE_MESH_MAX_CONN) { - BT_WARN("Connectable advertising deferred (max connections)"); + BT_WARN("Connectable advertising deferred (max connections %d)", conn_count); return remaining; } @@ -1284,25 +1671,50 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) } if (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { - uint32_t active = k_uptime_get_32() - sub->node_id_start; + active = k_uptime_get_32() - sub->node_id_start; if (active < NODE_ID_TIMEOUT) { remaining = NODE_ID_TIMEOUT - active; - BT_DBG("Node ID active for %u ms, %d ms remaining", - active, remaining); + BT_DBG("Node ID active for %u ms, %d ms remaining", active, remaining); node_id_adv(sub); } else { bt_mesh_proxy_server_identity_stop(sub); BT_DBG("Node ID stopped"); } } +#if CONFIG_BLE_MESH_PRB_SRV + else if (sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { + active = k_uptime_get_32() - sub->node_id_start; - if (sub->node_id == BLE_MESH_NODE_IDENTITY_STOPPED) { - net_id_adv(sub); + if (active < NODE_ID_TIMEOUT) { + remaining = NODE_ID_TIMEOUT - active; + BT_DBG("Private Node ID active for %u ms, %d ms remaining", active, remaining); + private_node_id_adv(sub); + } else { + bt_mesh_proxy_server_private_identity_stop(sub); + BT_DBG("Private Node ID stopped"); + } + } +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + + if (sub->node_id == BLE_MESH_NODE_IDENTITY_STOPPED +#if CONFIG_BLE_MESH_PRB_SRV + && sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED +#endif + ) { + if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { + net_id_adv(sub); + } +#if CONFIG_BLE_MESH_PRB_SRV + else if (bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED) { + private_net_id_adv(sub); + } +#endif } subnet_count = sub_count(); BT_DBG("sub_count %u", subnet_count); + if (subnet_count > 1) { int32_t max_timeout = 0; @@ -1325,20 +1737,24 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) } #endif /* GATT_PROXY */ -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) { - const struct bt_mesh_prov *prov = bt_mesh_prov_get(); const char *name = device_name; size_t name_len = strlen(name); size_t prov_sd_len = 0U; size_t sd_space = 31U; - memcpy(prov_svc_data + 2, prov->uuid, 16); - sys_put_be16(prov->oob_info, prov_svc_data + 18); + if (bt_mesh_prov_get() == NULL) { + BT_ERR("No provisioning context provided"); + return 0; + } - if (prov->uri) { - size_t uri_len = strlen(prov->uri); + memcpy(prov_svc_data + 2, bt_mesh_prov_get()->uuid, 16); + sys_put_be16(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); if (uri_len > 29) { /* There's no way to shorten an URI */ @@ -1346,7 +1762,7 @@ static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) } else { prov_sd[0].type = BLE_MESH_DATA_URI; prov_sd[0].data_len = uri_len; - prov_sd[0].data = (const uint8_t *)prov->uri; + prov_sd[0].data = (const uint8_t *)bt_mesh_prov_get()->uri; sd_space -= 2 + uri_len; prov_sd_len++; } @@ -1371,15 +1787,40 @@ static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) } #endif /* CONFIG_BLE_MESH_PB_GATT */ +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX +static int32_t solic_adv_private_net_id(void) +{ + uint16_t net_idx = BLE_MESH_KEY_UNUSED; + struct bt_mesh_subnet *sub = NULL; + int32_t remaining = 0; + + remaining = bt_mesh_proxy_server_get_solic_adv_remaining(); + if (remaining == 0) { + return 0; + } + + net_idx = bt_mesh_proxy_server_get_solic_adv_net_idx(); + if (net_idx == BLE_MESH_KEY_UNUSED) { + return 0; + } + + sub = bt_mesh_subnet_get(net_idx); + if (sub == NULL) { + return 0; + } + + private_net_id_adv(sub); + return remaining; +} +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + int32_t bt_mesh_proxy_server_adv_start(void) { - BT_DBG("%s", __func__); - if (gatt_svc == MESH_GATT_NONE) { return K_FOREVER; } -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT if (prov_fast_adv) { prov_start_time = k_uptime_get_32(); } @@ -1410,8 +1851,21 @@ int32_t bt_mesh_proxy_server_adv_start(void) } #endif /* PB_GATT */ -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (bt_mesh_is_provisioned()) { +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX + /* When the server starts advertising with Private Network Identity + * as a result of the reception of a Solicitation PDU, the server + * shall only advertise the subnet corresponding to the network key + * that is used to authenticate the Solicitation PDU; otherwise, the + * server shall interleave the advertising of each of its subnets. + */ + int32_t remaining = solic_adv_private_net_id(); + if (remaining) { + return remaining; + } +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + return gatt_proxy_advertise(next_sub()); } #endif /* GATT_PROXY */ @@ -1446,11 +1900,11 @@ int bt_mesh_proxy_server_init(void) { int i; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_register(&proxy_svc); #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_register(&prov_svc); #endif @@ -1458,14 +1912,21 @@ int bt_mesh_proxy_server_init(void) for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; - client->buf.size = CLIENT_BUF_SIZE; - client->buf.__buf = client_buf_data + (i * CLIENT_BUF_SIZE); + client->buf.size = BLE_MESH_PROXY_BUF_SIZE; + client->buf.__buf = client_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); #if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) - k_work_init(&client->send_beacons, proxy_send_beacons); + k_delayed_work_init(&client->send_beacons, proxy_send_beacons); #endif k_delayed_work_init(&client->sar_timer, proxy_sar_timeout); } +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV + if (k_delayed_work_init(&rand_upd_timer, random_update_timeout)) { + BT_ERR("Failed to create a random update timer"); + return -EIO; + } +#endif + bt_mesh_gatts_conn_cb_register(&conn_callbacks); strncpy(device_name, "ESP-BLE-MESH", DEVICE_NAME_SIZE); @@ -1480,21 +1941,28 @@ int bt_mesh_proxy_server_deinit(void) proxy_adv_enabled = false; gatt_svc = MESH_GATT_NONE; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_deregister(&proxy_svc); next_idx = 0; #endif -#if defined(CONFIG_BLE_MESH_PB_GATT) +#if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_deregister(&prov_svc); #endif for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + k_delayed_work_free(&client->send_beacons); +#endif k_delayed_work_free(&client->sar_timer); memset(client, 0, sizeof(struct bt_mesh_proxy_client)); } +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV + k_delayed_work_free(&rand_upd_timer); +#endif + memset(client_buf_data, 0, sizeof(client_buf_data)); memset(device_name, 0, sizeof(device_name)); @@ -1505,4 +1973,5 @@ int bt_mesh_proxy_server_deinit(void) } #endif /* CONFIG_BLE_MESH_DEINIT */ -#endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +#endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER */ diff --git a/components/bt/esp_ble_mesh/core/proxy_server.h b/components/bt/esp_ble_mesh/core/proxy_server.h index 0de6888460..5ae0a08126 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.h +++ b/components/bt/esp_ble_mesh/core/proxy_server.h @@ -7,8 +7,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef _PROXY_H_ -#define _PROXY_H_ +#ifndef _PROXY_SERVER_H_ +#define _PROXY_SERVER_H_ #include "net.h" #include "mesh/adapter.h" @@ -17,11 +17,6 @@ extern "C" { #endif -#define BLE_MESH_PROXY_NET_PDU 0x00 -#define BLE_MESH_PROXY_BEACON 0x01 -#define BLE_MESH_PROXY_CONFIG 0x02 -#define BLE_MESH_PROXY_PROV 0x03 - #if CONFIG_BLE_MESH_PROXY /** * Device Name Characteristic: @@ -38,11 +33,48 @@ extern "C" { #define DEVICE_NAME_SIZE (BLE_MESH_GAP_ADV_MAX_LEN - 2) #endif +struct bt_mesh_proxy_client { + struct bt_mesh_conn *conn; + + enum __attribute__((packed)) { + SRV_NONE, + SRV_WHITELIST, + SRV_BLACKLIST, + SRV_PROV, + } filter_type; + + uint8_t msg_type; + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + struct { + uint16_t addr; + bool proxy_client; /* Indicate if the address is the element address of Proxy Client. */ + } filter[CONFIG_BLE_MESH_PROXY_FILTER_SIZE]; + struct k_delayed_work send_beacons; + + uint8_t proxy_client_type; + uint8_t proxy_msg_recv : 1; /* Indicate if proxy server has received a message from proxy client */ + +#if CONFIG_BLE_MESH_PROXY_PRIVACY + uint8_t proxy_privacy; +#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + + struct k_delayed_work sar_timer; + + struct net_buf_simple buf; +}; + typedef void (*proxy_server_connect_cb_t)(uint8_t conn_handle); typedef void (*proxy_server_disconnect_cb_t)(uint8_t conn_handle, uint8_t reason); int bt_mesh_set_device_name(const char *name); +const char *bt_mesh_get_device_name(void); + +int bt_mesh_proxy_server_segment_send(struct bt_mesh_conn *conn, uint8_t type, + struct net_buf_simple *msg); + int bt_mesh_proxy_server_send(struct bt_mesh_conn *conn, uint8_t type, struct net_buf_simple *msg); @@ -64,6 +96,22 @@ struct net_buf_simple *bt_mesh_proxy_server_get_buf(void); int32_t bt_mesh_proxy_server_adv_start(void); void bt_mesh_proxy_server_adv_stop(void); +void bt_mesh_proxy_server_update_net_id_rand(void); +void bt_mesh_proxy_server_update_net_id_rand_stop(void); + +#if CONFIG_BLE_MESH_PRB_SRV +void bt_mesh_proxy_server_private_identity_start(struct bt_mesh_subnet *sub); +void bt_mesh_proxy_server_private_identity_stop(struct bt_mesh_subnet *sub); + +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); + +void bt_mesh_prb_pnid_adv_local_set(bool start); +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + void bt_mesh_proxy_server_identity_start(struct bt_mesh_subnet *sub); void bt_mesh_proxy_server_identity_stop(struct bt_mesh_subnet *sub); @@ -73,8 +121,11 @@ void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr); int bt_mesh_proxy_server_init(void); int bt_mesh_proxy_server_deinit(void); +bool bt_mesh_proxy_server_find_client_by_addr(uint16_t addr); +uint8_t bt_mesh_proxy_server_get_all_client_type(void); + #ifdef __cplusplus } #endif -#endif /* _PROXY_H_ */ +#endif /* _PROXY_SERVER_H_ */ diff --git a/components/bt/esp_ble_mesh/core/pvnr_mgmt.c b/components/bt/esp_ble_mesh/core/pvnr_mgmt.c index da3530d745..55d18ad51e 100644 --- a/components/bt/esp_ble_mesh/core/pvnr_mgmt.c +++ b/components/bt/esp_ble_mesh/core/pvnr_mgmt.c @@ -10,6 +10,7 @@ #include "mesh.h" #include "crypto.h" #include "adv.h" +#include "rpl.h" #include "access.h" #include "settings.h" #include "friend.h" @@ -17,9 +18,12 @@ #include "foundation.h" #include "mesh/common.h" #include "proxy_client.h" +#include "prov_common.h" #include "prov_pvnr.h" #include "pvnr_mgmt.h" +#include "mesh_v1.1/utils.h" + #if CONFIG_BLE_MESH_PROVISIONER static struct bt_mesh_node *mesh_nodes[CONFIG_BLE_MESH_MAX_PROV_NODES]; @@ -66,14 +70,10 @@ int bt_mesh_provisioner_init(void) */ int bt_mesh_provisioner_net_create(void) { - const struct bt_mesh_prov *prov = NULL; struct bt_mesh_subnet *sub = NULL; uint8_t p_key[16] = {0}; - BT_DBG("%s", __func__); - - prov = bt_mesh_provisioner_get_prov_info(); - if (!prov) { + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; } @@ -99,7 +99,7 @@ int bt_mesh_provisioner_net_create(void) return -ENOMEM; } - sub->kr_flag = BLE_MESH_KEY_REFRESH(prov->flags); + sub->kr_flag = BLE_MESH_KEY_REFRESH(bt_mesh_prov_get()->flags); if (sub->kr_flag) { if (bt_mesh_net_keys_create(&sub->keys[1], p_key)) { BT_ERR("Failed to generate net-related keys"); @@ -119,6 +119,10 @@ int bt_mesh_provisioner_net_create(void) sub->net_idx = BLE_MESH_KEY_PRIMARY; sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_forwarding_sub_init(sub); +#endif + bt_mesh.p_sub[0] = sub; /* Dynamically added appkey & netkey will use these key_idx */ @@ -131,9 +135,9 @@ int bt_mesh_provisioner_net_create(void) bt_mesh_store_p_subnet(bt_mesh.p_sub[0]); } - bt_mesh.iv_index = prov->iv_index; + bt_mesh.iv_index = bt_mesh_prov_get()->iv_index; bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS, - BLE_MESH_IV_UPDATE(prov->flags)); + BLE_MESH_IV_UPDATE(bt_mesh_prov_get()->flags)); /* Set minimum required hours, since the 96-hour minimum requirement * doesn't apply straight after provisioning (since we can't know how @@ -311,12 +315,10 @@ int bt_mesh_provisioner_provision(const bt_mesh_addr_t *addr, const uint8_t uuid uint16_t oob_info, uint16_t unicast_addr, uint8_t element_num, uint16_t net_idx, uint8_t flags, uint32_t iv_index, - const uint8_t dev_key[16], uint16_t *index) + const uint8_t dev_key[16], uint16_t *index, bool nppi) { struct bt_mesh_node node = {0}; - BT_DBG("%s", __func__); - if (!addr || !uuid || !dev_key || !index) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -327,6 +329,11 @@ int bt_mesh_provisioner_provision(const bt_mesh_addr_t *addr, const uint8_t uuid BT_INFO("UUID %s", bt_hex(uuid, 16)); BT_INFO("DevKey %s", bt_hex(dev_key, 16)); + if (nppi == true) { + /* For NPPI, remove the node from database firstly. */ + bt_mesh_provisioner_remove_node(uuid); + } + memcpy(node.addr, addr->val, BLE_MESH_ADDR_LEN); node.addr_type = addr->type; memcpy(node.dev_uuid, uuid, 16); @@ -367,6 +374,9 @@ static int provisioner_remove_node(uint16_t index, bool erase) for (i = 0; i < node->element_num; i++) { bt_mesh_tx_reset_single(node->unicast_addr + i); } + for (i = 0; i < node->element_num; i++) { + bt_mesh_rpl_reset_single(node->unicast_addr + i, erase); + } if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_remove_lpn(node->unicast_addr); @@ -392,8 +402,6 @@ static struct bt_mesh_node *provisioner_find_node_with_uuid(const uint8_t uuid[1 { int i; - BT_DBG("%s", __func__); - if (uuid == NULL) { BT_ERR("Invalid device uuid"); return NULL; @@ -445,8 +453,6 @@ static struct bt_mesh_node *provisioner_find_node_with_addr(uint16_t addr, uint1 struct bt_mesh_node *node = NULL; int i; - BT_DBG("%s", __func__); - if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { BT_ERR("Invalid unicast address 0x%04x", addr); return NULL; @@ -711,37 +717,14 @@ const uint8_t *bt_mesh_provisioner_net_key_get(uint16_t net_idx) struct bt_mesh_subnet *sub = NULL; int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { sub = bt_mesh.p_sub[i]; if (sub && sub->net_idx == net_idx) { if (sub->kr_flag) { return sub->keys[1].net; - } else { - return sub->keys[0].net; } - } - } - return NULL; -} - -struct bt_mesh_subnet *bt_mesh_provisioner_subnet_get(uint16_t net_idx) -{ - struct bt_mesh_subnet *sub = NULL; - int i; - - BT_DBG("%s", __func__); - - if (net_idx == BLE_MESH_KEY_ANY) { - return bt_mesh.p_sub[0]; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { - sub = bt_mesh.p_sub[i]; - if (sub && sub->net_idx == net_idx) { - return sub; + return sub->keys[0].net; } } @@ -753,8 +736,6 @@ bool bt_mesh_provisioner_check_msg_dst(uint16_t dst) struct bt_mesh_node *node = NULL; int i; - BT_DBG("%s", __func__); - if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { return true; } @@ -770,25 +751,23 @@ bool bt_mesh_provisioner_check_msg_dst(uint16_t dst) return false; } -const uint8_t *bt_mesh_provisioner_dev_key_get(uint16_t dst) +const uint8_t *bt_mesh_provisioner_dev_key_get(uint16_t addr) { /* Device key is only used to encrypt configuration messages. - * Configuration model shall only be supported by the primary - * element which uses the primary unicast address. - */ - struct bt_mesh_node *node = NULL; + * Configuration model shall only be supported by the primary + * element which uses the primary unicast address. + */ int i; - BT_DBG("%s", __func__); - - if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { - BT_ERR("Invalid unicast address 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + BT_ERR("Invalid unicast address 0x%04x", addr); return NULL; } for (i = 0; i < ARRAY_SIZE(mesh_nodes); i++) { - node = mesh_nodes[i]; - if (node && node->unicast_addr == dst) { + struct bt_mesh_node *node = mesh_nodes[i]; + + if (node && node->unicast_addr == addr) { return node->dev_key; } } @@ -796,24 +775,6 @@ const uint8_t *bt_mesh_provisioner_dev_key_get(uint16_t dst) return NULL; } -struct bt_mesh_app_key *bt_mesh_provisioner_app_key_find(uint16_t app_idx) -{ - struct bt_mesh_app_key *key = NULL; - int i; - - BT_DBG("%s", __func__); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { - key = bt_mesh.p_app_keys[i]; - if (key && key->net_idx != BLE_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return key; - } - } - - return NULL; -} - static int provisioner_check_app_key(const uint8_t app_key[16], uint16_t *app_idx) { struct bt_mesh_app_key *key = NULL; @@ -1054,9 +1015,9 @@ int bt_mesh_provisioner_local_app_key_update(const uint8_t app_key[16], return -ENODEV; } - key = bt_mesh_provisioner_app_key_find(app_idx); + key = bt_mesh_app_key_get(app_idx); if (key == NULL) { - BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); + BT_ERR("AppKey 0x%04x not found", app_idx); return -ENODEV; } @@ -1084,8 +1045,6 @@ const uint8_t *bt_mesh_provisioner_local_app_key_get(uint16_t net_idx, uint16_t struct bt_mesh_app_key *key = NULL; int i; - BT_DBG("%s", __func__); - if (provisioner_check_net_idx(net_idx, false)) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); return NULL; @@ -1135,8 +1094,6 @@ static void model_pub_clear(struct bt_mesh_model *model, bool store) if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && store) { bt_mesh_store_mod_pub(model); } - - return; } static void model_unbind(struct bt_mesh_model *model, uint16_t app_idx, bool store) @@ -1179,8 +1136,6 @@ int bt_mesh_provisioner_local_app_key_del(uint16_t net_idx, uint16_t app_idx, bo struct bt_mesh_app_key *key = NULL; int i; - BT_DBG("%s", __func__); - if (provisioner_check_net_idx(net_idx, false)) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); return -ENODEV; @@ -1290,6 +1245,10 @@ int bt_mesh_provisioner_local_net_key_add(const uint8_t net_key[16], uint16_t *n sub->kr_flag = false; sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_forwarding_sub_init(sub); +#endif + bt_mesh.p_sub[add] = sub; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { @@ -1312,9 +1271,9 @@ int bt_mesh_provisioner_local_net_key_update(const uint8_t net_key[16], uint16_t BT_INFO("NetKey %s, net_idx 0x%03x", bt_hex(net_key, 16), net_idx); - sub = bt_mesh_provisioner_subnet_get(net_idx); + sub = bt_mesh_subnet_get(net_idx); if (sub == NULL) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("NetKey 0x%04x not found", net_idx); return -ENODEV; } @@ -1331,7 +1290,7 @@ int bt_mesh_provisioner_local_net_key_update(const uint8_t net_key[16], uint16_t sub->kr_flag = false; sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; - err = bt_mesh_net_beacon_update(sub); + err = bt_mesh_net_secure_beacon_update(sub); if (err) { BT_ERR("Failed to update secure beacon"); return -EIO; @@ -1344,38 +1303,11 @@ int bt_mesh_provisioner_local_net_key_update(const uint8_t net_key[16], uint16_t return 0; } -const uint8_t *bt_mesh_provisioner_local_net_key_get(uint16_t net_idx) -{ - struct bt_mesh_subnet *sub = NULL; - int i; - - BT_DBG("%s", __func__); - - if (provisioner_check_net_idx(net_idx, false)) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { - sub = bt_mesh.p_sub[i]; - if (sub && sub->net_idx == net_idx) { - if (sub->kr_flag) { - return sub->keys[1].net; - } - return sub->keys[0].net; - } - } - - return NULL; -} - int bt_mesh_provisioner_local_net_key_del(uint16_t net_idx, bool store) { struct bt_mesh_subnet *sub = NULL; int i, j; - BT_DBG("%s", __func__); - if (provisioner_check_net_idx(net_idx, false)) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); return -ENODEV; @@ -1457,42 +1389,6 @@ int bt_mesh_provisioner_bind_local_model_app_idx(uint16_t elem_addr, uint16_t mo return -ENOMEM; } -int bt_mesh_print_local_composition_data(void) -{ - const struct bt_mesh_comp *comp = NULL; - struct bt_mesh_model *model = NULL; - struct bt_mesh_elem *elem = NULL; - int i, j; - - comp = bt_mesh_comp_get(); - if (!comp) { - BT_ERR("Invalid composition data"); - return -EINVAL; - } - - BT_INFO("************************************************"); - BT_INFO("* cid: 0x%04x pid: 0x%04x vid: 0x%04x *", comp->cid, comp->pid, comp->vid); - BT_INFO("* Element Number: 0x%02x *", comp->elem_count); - for (i = 0; i < comp->elem_count; i++) { - elem = &comp->elem[i]; - BT_INFO("* Element %d: 0x%04x *", i, elem->addr); - BT_INFO("* Loc: 0x%04x NumS: 0x%02x NumV: 0x%02x *", elem->loc, elem->model_count, elem->vnd_model_count); - for (j = 0; j < elem->model_count; j++) { - model = &elem->models[j]; - BT_INFO("* sig_model %d: id - 0x%04x *", j, model->id); - } - for (j = 0; j < elem->vnd_model_count; j++) { - model = &elem->vnd_models[j]; - BT_INFO("* vnd_model %d: id - 0x%04x, cid - 0x%04x *", j, model->vnd.id, model->vnd.company); - } - } - BT_INFO("************************************************"); - - ((void) model); - - return 0; -} - #if CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK int bt_mesh_provisioner_store_node_info(struct bt_mesh_node *node) { diff --git a/components/bt/esp_ble_mesh/core/pvnr_mgmt.h b/components/bt/esp_ble_mesh/core/pvnr_mgmt.h index dbfd7601f4..20fdc6d130 100644 --- a/components/bt/esp_ble_mesh/core/pvnr_mgmt.h +++ b/components/bt/esp_ble_mesh/core/pvnr_mgmt.h @@ -37,7 +37,7 @@ struct bt_mesh_node { char name[BLE_MESH_NODE_NAME_SIZE + 1]; /* Node name */ uint16_t comp_length; /* Length of Composition Data */ uint8_t *comp_data; /* Value of Composition Data */ -} __packed; +} __attribute__((packed)); int bt_mesh_provisioner_init(void); @@ -57,7 +57,7 @@ int bt_mesh_provisioner_provision(const bt_mesh_addr_t *addr, const uint8_t uuid uint16_t oob_info, uint16_t unicast_addr, uint8_t element_num, uint16_t net_idx, uint8_t flags, uint32_t iv_index, - const uint8_t dev_key[16], uint16_t *index); + const uint8_t dev_key[16], uint16_t *index, bool nppi); int bt_mesh_provisioner_remove_node(const uint8_t uuid[16]); @@ -89,13 +89,9 @@ int bt_mesh_provisioner_store_node_comp_data(uint16_t addr, const uint8_t *data, const uint8_t *bt_mesh_provisioner_net_key_get(uint16_t net_idx); -struct bt_mesh_subnet *bt_mesh_provisioner_subnet_get(uint16_t net_idx); - bool bt_mesh_provisioner_check_msg_dst(uint16_t dst); -const uint8_t *bt_mesh_provisioner_dev_key_get(uint16_t dst); - -struct bt_mesh_app_key *bt_mesh_provisioner_app_key_find(uint16_t app_idx); +const uint8_t *bt_mesh_provisioner_dev_key_get(uint16_t addr); int bt_mesh_provisioner_local_app_key_add(const uint8_t app_key[16], uint16_t net_idx, uint16_t *app_idx); @@ -111,8 +107,6 @@ int bt_mesh_provisioner_local_net_key_add(const uint8_t net_key[16], uint16_t *n int bt_mesh_provisioner_local_net_key_update(const uint8_t net_key[16], uint16_t net_idx); -const uint8_t *bt_mesh_provisioner_local_net_key_get(uint16_t net_idx); - int bt_mesh_provisioner_local_net_key_del(uint16_t net_idx, bool store); /* Provisioner bind local client model with proper appkey index */ @@ -133,9 +127,6 @@ void bt_mesh_provisioner_heartbeat(uint16_t hb_src, uint16_t hb_dst, uint8_t init_ttl, uint8_t rx_ttl, uint8_t hops, uint16_t feat, int8_t rssi); -/* Provisioner print own element information */ -int bt_mesh_print_local_composition_data(void); - int bt_mesh_provisioner_store_node_info(struct bt_mesh_node *node); #ifdef __cplusplus diff --git a/components/bt/esp_ble_mesh/core/rpl.c b/components/bt/esp_ble_mesh/core/rpl.c new file mode 100644 index 0000000000..cbf763bd01 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/rpl.c @@ -0,0 +1,141 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "mesh/config.h" +#include "mesh/trace.h" +#include "mesh.h" +#include "settings.h" + +void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) +{ + rpl->src = rx->ctx.addr; + rpl->seq = rx->seq; + rpl->old_iv = rx->old_iv; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_rpl(rpl); + } +} + +/* Check the Replay Protection List for a replay attempt. If non-NULL match + * parameter is given the RPL slot is returned but it is not immediately + * updated (needed for segmented messages), whereas if a NULL match is given + * the RPL is immediately updated (used for unsegmented messages). + */ +static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) +{ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + + /* Empty slot */ + if (rpl->src == BLE_MESH_ADDR_UNASSIGNED) { + if (match) { + *match = rpl; + } else { + bt_mesh_update_rpl(rpl, rx); + } + + return false; + } + + /* Existing slot for given address */ + if (rpl->src == rx->ctx.addr) { + if (rx->old_iv && !rpl->old_iv) { + return true; + } + + if ((!rx->old_iv && rpl->old_iv) || + rpl->seq < rx->seq) { + if (match) { + *match = rpl; + } else { + bt_mesh_update_rpl(rpl, rx); + } + + return false; + } + + return true; + } + } + + BT_ERR("RPL is full!"); + return true; +} + +bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) +{ + /* Don't bother checking messages from ourselves */ + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + return false; + } + + /* The RPL is used only for the local node */ + if (!rx->local_match) { + return false; + } + + 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 + * any other ones (which are valid) as old. + */ + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + + if (rpl->src) { + if (rpl->old_iv) { + (void)memset(rpl, 0, sizeof(*rpl)); + } else { + rpl->old_iv = true; + } + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_rpl(rpl); + } + } + } +} + +void bt_mesh_rpl_reset_single(uint16_t src, bool erase) +{ + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { + if (src == bt_mesh.rpl[i].src) { + memset(&bt_mesh.rpl[i], 0, sizeof(struct bt_mesh_rpl)); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && erase) { + bt_mesh_clear_rpl_single(src); + } + } + } +} + +void bt_mesh_rpl_reset(bool erase) +{ + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && erase) { + bt_mesh_clear_rpl(); + } +} diff --git a/components/bt/esp_ble_mesh/core/rpl.h b/components/bt/esp_ble_mesh/core/rpl.h new file mode 100644 index 0000000000..ae4e49f734 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/rpl.h @@ -0,0 +1,35 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _RPL_H_ +#define _RPL_H_ + +#include "net.h" + +#ifdef __cplusplus +extern "C" { +#endif + +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); + +void bt_mesh_rpl_reset(bool erase); + +#ifdef __cplusplus +} +#endif + +#endif /* _RPL_H_ */ diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index 8bfbcf8fea..e1b43dd2f6 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "btc_ble_mesh_ble.h" @@ -26,25 +27,144 @@ #include "prov_pvnr.h" #include "mesh/adapter.h" +#include "mesh_v1.1/utils.h" + /* Scan Window and Interval are equal for continuous scanning */ #define SCAN_INTERVAL 0x20 #define SCAN_WINDOW 0x20 -#define PROV_SVC_DATA_LEN 0x12 -#define PROXY_SVC_DATA_LEN_NET_ID 0x09 -#define PROXY_SVC_DATA_LEN_NODE_ID 0x11 +#define PROV_SVC_DATA_LEN 0x12 +#define PROXY_SVC_DATA_LEN_NET_ID 0x09 +#define PROXY_SVC_DATA_LEN_NODE_ID 0x11 +#define PROXY_SVC_DATA_LEN_PRIVATE_NET_ID 0x11 +#define PROXY_SVC_DATA_LEN_PRIVATE_NODE_ID 0x11 -#if CONFIG_BLE_MESH_PROVISIONER +#if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) static const bt_mesh_addr_t *unprov_dev_addr; +static uint8_t current_adv_type; + +static struct { + uint8_t start_idx; + uint8_t end_idx; + uint8_t pair_num; + struct { + uint8_t uuid[16]; + uint8_t adv_type; + uint8_t addr[6]; + } info[BLE_MESH_STORE_UNPROV_INFO_MAX_NUM]; +} unprov_dev_info_fifo; + +int bt_mesh_unprov_dev_fifo_dequeue(uint8_t *uuid, uint8_t *addr) +{ + uint8_t idx = 0; + + if (unprov_dev_info_fifo.pair_num == 0) { + return 0; + } + + idx = unprov_dev_info_fifo.start_idx; + + if (uuid) { + memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); + } + + if (addr) { + memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); + } + + idx = (idx + 1) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; + unprov_dev_info_fifo.start_idx = idx; + + unprov_dev_info_fifo.pair_num--; + return 0; +} + +int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], + uint8_t *adv_type, uint8_t query_type) +{ + uint8_t idx = 0; + uint8_t cnt = 0; + + if (uuid == NULL || addr == NULL) { + BT_WARN("No available information to query"); + return -1; + } + + while (cnt < unprov_dev_info_fifo.pair_num) { + idx = (cnt + unprov_dev_info_fifo.start_idx) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; + if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_UUID) { + if (!memcmp(unprov_dev_info_fifo.info[idx].addr, addr, 6)) { + if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { + return 0; + } else { + memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; + } + } + } else { + if (!memcmp(unprov_dev_info_fifo.info[idx].uuid, uuid, 16)) { + if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { + return 0; + } else { + memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; + } + } + } + cnt++; + } + + if (cnt == unprov_dev_info_fifo.pair_num) { + BT_WARN("Didn't find info for %d", query_type); + return -1; + } + + return 0; + +} + +int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uint8_t adv_type) +{ + uint8_t idx = 0; + + if (uuid == NULL || addr == NULL) { + BT_ERR("Invalid argument %s", __func__); + return -EINVAL; + } + + if (unprov_dev_info_fifo.pair_num == BLE_MESH_STORE_UNPROV_INFO_MAX_NUM) { + bt_mesh_unprov_dev_fifo_dequeue(NULL, NULL); + } + + idx = unprov_dev_info_fifo.end_idx; + + memcpy(unprov_dev_info_fifo.info[idx].uuid, uuid, 16); + memcpy(unprov_dev_info_fifo.info[idx].addr, addr, 6); + unprov_dev_info_fifo.info[idx].adv_type = adv_type; + + idx = (idx + 1) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; + unprov_dev_info_fifo.end_idx = idx; + unprov_dev_info_fifo.pair_num++; + return 0; +} const bt_mesh_addr_t *bt_mesh_get_unprov_dev_addr(void) { return unprov_dev_addr; } -#endif /* CONFIG_BLE_MESH_PROVISIONER */ + +uint8_t bt_mesh_get_adv_type(void) +{ + return current_adv_type; +} + +#endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX static bool adv_flags_valid(struct net_buf_simple *buf) { uint8_t flags = 0U; @@ -76,20 +196,40 @@ static bool adv_service_uuid_valid(struct net_buf_simple *buf, uint16_t *uuid) BT_DBG("Received adv pkt with service UUID: %d", *uuid); if (*uuid != BLE_MESH_UUID_MESH_PROV_VAL && - *uuid != BLE_MESH_UUID_MESH_PROXY_VAL) { + *uuid != BLE_MESH_UUID_MESH_PROXY_VAL && + *uuid != BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL) { return false; } + /** + * @brief In remote provisioning. + * A Node could handle the unprovisioned beacon. + * CASE: MESH/SR/RPR/SCN/BV-01-C + */ +#if CONFIG_BLE_MESH_RPR_SRV if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && - bt_mesh_is_provisioner_en() == false) { + !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { return false; } +#else + if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && + (bt_mesh_is_provisioner_en() == false || + !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT))) { + return false; + } +#endif + if (*uuid == BLE_MESH_UUID_MESH_PROXY_VAL && !IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)) { return false; } + if (*uuid == BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL && + !IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX)) { + return false; + } + return true; } @@ -122,12 +262,23 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Prov Service Data"); bt_mesh_provisioner_prov_adv_recv(buf, addr, rssi); } + + if (IS_ENABLED(CONFIG_BLE_MESH_RPR_SRV) && + bt_mesh_is_provisioned()) { + const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); + } break; #endif #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT case BLE_MESH_UUID_MESH_PROXY_VAL: if (buf->len != PROXY_SVC_DATA_LEN_NET_ID && buf->len != PROXY_SVC_DATA_LEN_NODE_ID) { + /* PROXY_SVC_DATA_LEN_NODE_ID, + * PROXY_SVC_DATA_LEN_PRIVATE_NET_ID and + * PROXY_SVC_DATA_LEN_PRIVATE_NODE_ID are equal to 0x11 + */ BT_WARN("Invalid Mesh Proxy Service Data length %d", buf->len); return; } @@ -135,13 +286,25 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Proxy Service Data"); bt_mesh_proxy_client_gatt_adv_recv(buf, addr, rssi); break; +#endif +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX + case BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL: + if (buf->len != (1 + BLE_MESH_NET_HDR_LEN + 8)) { + BT_WARN("Invalid Mesh Proxy Solic Service Data length %d", buf->len); + return; + } + + BT_DBG("Start to handle Mesh Proxy Solic Service Data"); + bt_mesh_proxy_server_solic_recv(buf, addr, rssi); + break; #endif default: break; } } #endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN static bool ble_scan_en; @@ -180,15 +343,35 @@ static void inline callback_ble_adv_pkt(const bt_mesh_addr_t *addr, } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ +#if CONFIG_BLE_MESH_RPR_SRV +static bool rpr_ext_scan_handle_adv_pkt(const bt_mesh_addr_t *addr, + uint8_t data[], uint16_t length) +{ + struct net_buf_simple buf = {0}; + bool rpr_adv = false; + + if (bt_mesh_is_provisioned() == false) { + return false; + } + + net_buf_simple_init_with_data(&buf, data, length); + bt_mesh_rpr_srv_extended_scan(&buf, addr, &rpr_adv); + + return rpr_adv; +} +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, int8_t rssi, uint8_t adv_type, - struct net_buf_simple *buf) + struct net_buf_simple *buf, + uint8_t scan_rsp_len) { #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX uint16_t uuid = 0U; #endif -#if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN +#if (CONFIG_BLE_MESH_RPR_SRV || CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) uint8_t *adv_data = buf->data; uint16_t adv_len = buf->len; #endif @@ -202,8 +385,9 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, BT_DBG("scan, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); -#if CONFIG_BLE_MESH_PROVISIONER +#if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) unprov_dev_addr = addr; + current_adv_type = adv_type; #endif while (buf->len > 1) { @@ -257,7 +441,8 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, bt_mesh_beacon_recv(buf, rssi); break; #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX case BLE_MESH_DATA_FLAGS: if (!adv_flags_valid(buf)) { BT_DBG("Adv Flags mismatch, ignore this adv pkt"); @@ -270,6 +455,14 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, case BLE_MESH_DATA_UUID16_ALL: if (!adv_service_uuid_valid(buf, &uuid)) { BT_DBG("Adv Service UUID mismatch, ignore this adv pkt"); +#if CONFIG_BLE_MESH_RPR_SRV + if (rpr_ext_scan_handle_adv_pkt(addr, adv_data, adv_len)) { + /* If handled as extended scan report successfully, then not + * notify to the application layer as normal BLE adv packet. + */ + return; + } +#endif #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(addr, adv_type, adv_data, adv_len, rssi); #endif @@ -281,6 +474,14 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, break; #endif default: +#if CONFIG_BLE_MESH_RPR_SRV + if (rpr_ext_scan_handle_adv_pkt(addr, adv_data, adv_len)) { + /* If handled as extended scan report successfully, then not + * notify to the application layer as normal BLE adv packet. + */ + return; + } +#endif #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(addr, adv_type, adv_data, adv_len, rssi); #endif @@ -290,6 +491,14 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, net_buf_simple_restore(buf, &state); net_buf_simple_pull(buf, len); } +#if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN + if (scan_rsp_len != 0) { + /** + * scan response is only visible for remote provisioning extend scan. + */ + rpr_ext_scan_handle_adv_pkt(addr, adv_data + adv_len, scan_rsp_len); + } +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ } int bt_mesh_scan_enable(void) @@ -297,7 +506,11 @@ int bt_mesh_scan_enable(void) int err = 0; struct bt_mesh_scan_param scan_param = { +#if CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN + .type = BLE_MESH_SCAN_ACTIVE, +#else .type = BLE_MESH_SCAN_PASSIVE, +#endif #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, #else @@ -308,8 +521,6 @@ int bt_mesh_scan_enable(void) .scan_fil_policy = BLE_MESH_SP_ADV_ALL, }; - BT_DBG("%s", __func__); - err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { BT_ERR("starting scan failed (err %d)", err); @@ -323,8 +534,6 @@ int bt_mesh_scan_disable(void) { int err = 0; - BT_DBG("%s", __func__); - err = bt_le_scan_stop(); if (err && err != -EALREADY) { BT_ERR("stopping scan failed (err %d)", err); @@ -351,8 +560,6 @@ int bt_mesh_scan_with_wl_enable(void) .scan_fil_policy = BLE_MESH_SP_ADV_WL, }; - BT_DBG("%s", __func__); - err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { BT_ERR("starting scan failed (err %d)", err); diff --git a/components/bt/esp_ble_mesh/core/scan.h b/components/bt/esp_ble_mesh/core/scan.h index 5b6937f84d..b7d0555c83 100644 --- a/components/bt/esp_ble_mesh/core/scan.h +++ b/components/bt/esp_ble_mesh/core/scan.h @@ -16,7 +16,18 @@ extern "C" { #endif +#define BLE_MESH_STORE_UNPROV_INFO_MAX_NUM 10 +#define BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_ADDR 0 +#define BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_UUID BIT(0) +#define BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS BIT(1) + const bt_mesh_addr_t *bt_mesh_get_unprov_dev_addr(void); +uint8_t bt_mesh_get_adv_type(void); + +int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uint8_t adv_type); + +int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], + uint8_t *adv_type, uint8_t query_type); int bt_mesh_scan_enable(void); diff --git a/components/bt/esp_ble_mesh/core/storage/settings.c b/components/bt/esp_ble_mesh/core/storage/settings.c index ee18e3c6b1..34a40d2d30 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.c +++ b/components/bt/esp_ble_mesh/core/storage/settings.c @@ -22,6 +22,8 @@ #include "pvnr_mgmt.h" #include "prov_pvnr.h" +#include "mesh_v1.1/utils.h" + /* BLE Mesh NVS Key and corresponding data struct. * Note: The length of nvs key must be <= 15. * "xxxx" (2 octet) means the rpl_src, net_idx, app_idx, model_key, etc. @@ -47,6 +49,7 @@ * key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication * key: "mesh/vaddr" -> write/read to set/get all virtual addresses * key: "mesh/va/xxxx" -> write/read to set/get the "xxxx" virtual address + * key: "mesh/dkca" -> write/read to set/get Device Key Candidate */ #if CONFIG_BLE_MESH_SETTINGS @@ -70,12 +73,12 @@ static void store_pending(struct k_work *work); struct net_val { uint16_t primary_addr; uint8_t dev_key[16]; -} __packed; +} __attribute__((packed)); /* Sequence number storage */ struct seq_val { uint8_t val[3]; -} __packed; +} __attribute__((packed)); /* Heartbeat Publication storage */ struct hb_pub_val { @@ -103,7 +106,7 @@ struct iv_val { uint32_t iv_index; uint8_t iv_update:1, iv_duration:7; -} __packed; +} __attribute__((packed)); /* Replay Protection List storage */ struct rpl_val { @@ -116,14 +119,14 @@ struct net_key_val { uint8_t kr_flag:1, kr_phase:7; uint8_t val[2][16]; -} __packed; +} __attribute__((packed)); /* AppKey storage information */ struct app_key_val { uint16_t net_idx; bool updated; uint8_t val[2][16]; -} __packed; +} __attribute__((packed)); struct mod_pub_val { uint16_t addr; @@ -133,6 +136,9 @@ struct mod_pub_val { uint8_t period; uint8_t period_div:4, cred:1; +#if CONFIG_BLE_MESH_DF_SRV + uint8_t directed_pub_policy; /* Directed publish policy */ +#endif /* CONFIG_BLE_MESH_DF_SRV */ }; /* Virtual Address information */ @@ -140,7 +146,7 @@ struct va_val { uint16_t ref; uint16_t addr; uint8_t uuid[16]; -} __packed; +} __attribute__((packed)); /* We need this so we don't overwrite app-hardcoded values in case FCB * contains a history of changes but then has a NULL at the end. @@ -166,7 +172,7 @@ struct node_info { uint8_t flags; uint32_t iv_index; uint8_t dev_key[16]; -} __packed; +} __attribute__((packed)); static bt_mesh_mutex_t settings_lock; @@ -199,8 +205,6 @@ static int role_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)bt_mesh.flags, sizeof(bt_mesh.flags), &exist); if (err) { BT_ERR("Failed to load mesh device role"); @@ -227,8 +231,6 @@ static int net_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&net, sizeof(net), &exist); if (err) { BT_ERR("Failed to load node net info"); @@ -250,14 +252,32 @@ static int net_set(const char *name) return 0; } +static int dkca_set(const char *name) +{ + bool exist = false; + int err = 0; + + err = bt_mesh_load_core_settings(name, bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca), &exist); + if (err) { + BT_ERR("Failed to load DevKey Candidate"); + return 0; + } + + if (exist == false) { + return 0; + } + + BT_INFO("Restored DevKey Candidate %s", bt_hex(bt_mesh.dev_key_ca, 16)); + + return 0; +} + static int iv_set(const char *name) { struct iv_val iv = {0}; bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&iv, sizeof(iv), &exist); if (err) { BT_ERR("Failed to load iv_index"); @@ -286,8 +306,6 @@ static int seq_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&seq, sizeof(seq), &exist); if (err) { BT_ERR("Failed to load sequence number"); @@ -354,8 +372,6 @@ static int rpl_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -405,6 +421,19 @@ free: return err; } +static struct bt_mesh_subnet *subnet_exist(uint16_t net_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { + if (bt_mesh.sub[i].net_idx == net_idx) { + return &bt_mesh.sub[i]; + } + } + + return NULL; +} + static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) { int i; @@ -419,6 +448,20 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) return NULL; } +static struct bt_mesh_app_key *appkey_exist(uint16_t app_idx) +{ + int i; + + for (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]; + } + } + + return NULL; +} + static int net_key_set(const char *name) { struct net_buf_simple *buf = NULL; @@ -430,8 +473,6 @@ static int net_key_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -453,7 +494,7 @@ static int net_key_set(const char *name) continue; } - sub = bt_mesh_subnet_get(net_idx); + sub = subnet_exist(net_idx); if (!sub) { sub = subnet_alloc(net_idx); if (!sub) { @@ -490,8 +531,6 @@ static int app_key_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -513,13 +552,13 @@ static int app_key_set(const char *name) continue; } - sub = bt_mesh_subnet_get(key.net_idx); + sub = subnet_exist(key.net_idx); if (!sub) { BT_ERR("Failed to find subnet 0x%03x", key.net_idx); continue; } - app = bt_mesh_app_key_find(app_idx); + app = appkey_exist(app_idx); if (!app) { app = bt_mesh_app_key_alloc(app_idx); if (!app) { @@ -554,8 +593,6 @@ static int hb_pub_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - if (!hb_pub) { BT_ERR("Invalid heartbeat publication"); return -EINVAL; @@ -600,8 +637,6 @@ static int cfg_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - if (!cfg) { BT_ERR("Invalid configuration"); stored_cfg.valid = false; @@ -689,7 +724,7 @@ static int model_set_pub(bool vnd, struct bt_mesh_model *model, uint16_t model_k if (!model->pub) { BT_INFO("Not support publication, model_id 0x%04x, cid 0x%04x", - vnd ? model->vnd.id : model->id, vnd ? model->vnd.company : 0xFFFF); + vnd ? model->vnd.id : model->id, vnd ? model->vnd.company : 0xFFFF); return 0; } @@ -719,6 +754,11 @@ static int model_set_pub(bool vnd, struct bt_mesh_model *model, uint16_t model_k model->pub->retransmit = pub.retransmit; model->pub->count = 0U; +#if CONFIG_BLE_MESH_DF_SRV + model->pub->directed_pub_policy = pub.directed_pub_policy; /* Directed publish policy */ + bt_mesh_power_up_create_path_origin_fsm(model); +#endif /* CONFIG_BLE_MESH_DF_SRV */ + BT_INFO("Restored Model Publication, address 0x%04x, app_idx 0x%03x", pub.addr, pub.key); return 0; @@ -732,8 +772,6 @@ static int model_set(bool vnd, const char *name) size_t length = 0U; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -785,8 +823,6 @@ static int va_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -840,8 +876,6 @@ static int p_prov_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&val, sizeof(val), &exist); if (err) { BT_ERR("Failed to load next address allocation"); @@ -866,8 +900,6 @@ static int p_net_idx_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&net_idx, sizeof(net_idx), &exist); if (err) { BT_ERR("Failed to load next NetKeyIndex alloc"); @@ -891,8 +923,6 @@ static int p_app_idx_set(const char *name) bool exist = false; int err = 0; - BT_DBG("%s", __func__); - err = bt_mesh_load_core_settings(name, (uint8_t *)&app_idx, sizeof(app_idx), &exist); if (err) { BT_ERR("Failed to load next AppKeyIndex alloc"); @@ -910,6 +940,20 @@ static int p_app_idx_set(const char *name) return 0; } +static struct bt_mesh_subnet *p_subnet_exist(uint16_t net_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { + if (bt_mesh.p_sub[i] && + bt_mesh.p_sub[i]->net_idx == net_idx) { + return bt_mesh.p_sub[i]; + } + } + + return NULL; +} + static struct bt_mesh_subnet *p_subnet_alloc(void) { int i; @@ -929,6 +973,21 @@ static struct bt_mesh_subnet *p_subnet_alloc(void) return NULL; } +static struct bt_mesh_app_key *p_appkey_exist(uint16_t app_idx) +{ + int i; + + for (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]; + } + } + + return NULL; +} + static struct bt_mesh_app_key *p_appkey_alloc(void) { int i; @@ -959,8 +1018,6 @@ static int p_net_key_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -982,7 +1039,7 @@ static int p_net_key_set(const char *name) continue; } - sub = bt_mesh_provisioner_subnet_get(net_idx); + sub = p_subnet_exist(net_idx); if (!sub) { sub = p_subnet_alloc(); if (!sub) { @@ -1019,8 +1076,6 @@ static int p_app_key_set(const char *name) int err = 0; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1042,13 +1097,13 @@ static int p_app_key_set(const char *name) continue; } - sub = bt_mesh_provisioner_subnet_get(key.net_idx); + sub = p_subnet_exist(key.net_idx); if (!sub) { BT_ERR("Failed to find subnet 0x%03x", key.net_idx); continue; } - app = bt_mesh_provisioner_app_key_find(app_idx); + app = p_appkey_exist(app_idx); if (!app) { app = p_appkey_alloc(); if (!app) { @@ -1217,6 +1272,7 @@ const struct bt_mesh_setting { } settings[] = { { "mesh/role", role_set }, /* For Node & Provisioner */ { "mesh/net", net_set }, /* For Node */ + { "mesh/dkca", dkca_set }, /* For Node */ { "mesh/iv", iv_set }, /* For Node & Provisioner */ { "mesh/seq", seq_set }, /* For Node & Provisioner */ { "mesh/rpl", rpl_set }, /* For Node & Provisioner */ @@ -1258,8 +1314,6 @@ int settings_core_load(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(settings); i++) { if ((!strcmp(settings[i].name, "mesh/net") || !strcmp(settings[i].name, "mesh/netkey") || @@ -1333,7 +1387,12 @@ static int subnet_init(struct bt_mesh_subnet *sub) } /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); + bt_mesh_net_secure_beacon_update(sub); + +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_directed_forwarding_sub_init(sub); + bt_mesh_recovery_directed_forwarding_table(sub); +#endif return 0; } @@ -1357,7 +1416,7 @@ int settings_core_commit(void) int err = 0; int i; -#if defined(CONFIG_BLE_MESH_NODE) +#if CONFIG_BLE_MESH_NODE if (bt_mesh_is_node()) { if (bt_mesh.sub[0].net_idx == BLE_MESH_KEY_UNUSED) { /* Nothing to do since we're not yet provisioned */ @@ -1385,7 +1444,7 @@ int settings_core_commit(void) } #endif /* CONFIG_BLE_MESH_NODE */ -#if defined(CONFIG_BLE_MESH_PROVISIONER) +#if CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner()) { if (bt_mesh.p_sub[0] == NULL || bt_mesh.p_sub[0]->net_idx == BLE_MESH_KEY_UNUSED) { @@ -1417,16 +1476,16 @@ int settings_core_commit(void) bt_mesh_model_foreach(commit_model, NULL); } -#if defined(CONFIG_BLE_MESH_NODE) +#if CONFIG_BLE_MESH_NODE if (bt_mesh_is_node()) { struct bt_mesh_hb_pub *hb_pub = NULL; struct bt_mesh_cfg_srv *cfg = NULL; hb_pub = bt_mesh_hb_pub_get(); if (hb_pub && hb_pub->dst != BLE_MESH_ADDR_UNASSIGNED && - hb_pub->count && hb_pub->period) { + hb_pub->count && hb_pub->period) { BT_DBG("Starting heartbeat publication"); - k_work_submit(&hb_pub->timer.work); + k_delayed_work_submit(&hb_pub->timer, K_NO_WAIT); } cfg = bt_mesh_cfg_get(); @@ -1568,7 +1627,7 @@ static void store_pending_seq(void) void bt_mesh_store_seq(void) { if (CONFIG_BLE_MESH_SEQ_STORE_RATE && - (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)) { + (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)) { return; } @@ -1603,8 +1662,6 @@ static void store_rpl(struct bt_mesh_rpl *entry) if (err) { BT_ERR("Failed to add 0x%04x to mesh/rpl", entry->src); } - - return; } static void clear_rpl(void) @@ -1615,8 +1672,6 @@ static void clear_rpl(void) uint16_t src = 0U; int i; - BT_DBG("%s", __func__); - buf = bt_mesh_get_core_settings_item("mesh/rpl"); if (!buf) { bt_mesh_erase_core_settings("mesh/rpl"); @@ -1640,15 +1695,12 @@ static void clear_rpl(void) bt_mesh_erase_core_settings("mesh/rpl"); bt_mesh_free_buf(buf); - return; } static void store_pending_rpl(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; @@ -1726,8 +1778,6 @@ static void clear_app_key(uint16_t app_idx) if (err) { BT_ERR("Failed to remove 0x%03x from mesh/appkey", app_idx); } - - return; } static void clear_net_key(uint16_t net_idx) @@ -1745,7 +1795,9 @@ static void clear_net_key(uint16_t net_idx) BT_ERR("Failed to remove 0x%03x from mesh/netkey", net_idx); } - return; +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_clear_directed_forwarding_table_data(net_idx); +#endif } static void store_net_key(struct bt_mesh_subnet *sub) @@ -1773,8 +1825,6 @@ static void store_net_key(struct bt_mesh_subnet *sub) if (err) { BT_ERR("Failed to add 0x%03x to mesh/netkey", sub->net_idx); } - - return; } static void store_app_key(struct bt_mesh_app_key *app) @@ -1799,8 +1849,6 @@ static void store_app_key(struct bt_mesh_app_key *app) if (err) { BT_ERR("Failed to add 0x%03x to mesh/appkey", app->app_idx); } - - return; } static void store_pending_keys(void) @@ -1823,7 +1871,7 @@ static void store_pending_keys(void) } else { if (update->app_key) { struct bt_mesh_app_key *key = NULL; - key = bt_mesh_app_key_find(update->key_idx); + key = bt_mesh_app_key_get(update->key_idx); if (key) { store_app_key(key); } else { @@ -1864,8 +1912,6 @@ static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) BT_ERR("Failed to add bound key to %s, model_key 0x%04x", vnd ? "mesh/vnd" : "mesh/sig", model_key); } - - return; } static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) @@ -1888,8 +1934,6 @@ static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) BT_ERR("Failed to add subscription to %s, model_key 0x%04x", vnd ? "mesh/vnd" : "mesh/sig", model_key); } - - return; } static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) @@ -1915,6 +1959,10 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) pub.period_div = model->pub->period_div; pub.cred = model->pub->cred; +#if CONFIG_BLE_MESH_DF_SRV + pub.directed_pub_policy = model->pub->directed_pub_policy; /**< Directed publish policy */ +#endif + err = bt_mesh_save_core_settings(name, (const uint8_t *)&pub, sizeof(pub)); if (err) { BT_ERR("Failed to store %s", name); @@ -1926,8 +1974,6 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) BT_ERR("Failed to add publication to %s, model_key 0x%04x", vnd ? "mesh/vnd" : "mesh/sig", model_key); } - - return; } static void store_pending_mod(struct bt_mesh_model *model, @@ -2041,7 +2087,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s virtual address %s", - IS_VA_DEL(lab) ? "delete" : "store", name); + IS_VA_DEL(lab) ? "delete" : "store", name); return; } @@ -2052,7 +2098,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s 0x%04x in mesh/vaddr", - IS_VA_DEL(lab) ? "delete" : "store", i); + IS_VA_DEL(lab) ? "delete" : "store", i); return; } @@ -2062,8 +2108,6 @@ static void store_pending_va(void) static void store_pending(struct k_work *work) { - BT_DBG("%s", __func__); - if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_RPL_PENDING)) { if (bt_mesh_is_provisioned() || bt_mesh_is_provisioner_en()) { store_pending_rpl(); @@ -2301,6 +2345,25 @@ void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) schedule_store(BLE_MESH_KEYS_PENDING); } +void bt_mesh_clear_rpl_single(uint16_t src) +{ + char name[16] = {'\0'}; + int err = 0; + + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { + BT_ERR("Invalid src 0x%04x", src); + return; + } + + sprintf(name, "mesh/rpl/%04x", src); + bt_mesh_erase_core_settings(name); + + err = bt_mesh_remove_core_settings_item("mesh/rpl", src); + if (err) { + BT_ERR("Failed to remove 0x%04x from mesh/rpl", src); + } +} + void bt_mesh_clear_rpl(void) { schedule_store(BLE_MESH_RPL_PENDING); @@ -2329,6 +2392,16 @@ void bt_mesh_store_label(void) schedule_store(BLE_MESH_VA_PENDING); } +void bt_mesh_store_dkca(void) +{ + bt_mesh_save_core_settings("mesh/dkca", bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca)); +} + +void bt_mesh_clear_dkca(void) +{ + bt_mesh_erase_core_settings("mesh/dkca"); +} + #if CONFIG_BLE_MESH_PROVISIONER /** * key: "mesh/p_prov" -> write/read to set/get prov_ctx.curr_addr @@ -2495,25 +2568,6 @@ void bt_mesh_clear_p_app_key(uint16_t app_idx) } } -void bt_mesh_clear_rpl_single(uint16_t src) -{ - char name[16] = {'\0'}; - int err = 0; - - if (!BLE_MESH_ADDR_IS_UNICAST(src)) { - BT_ERR("Invalid src 0x%04x", src); - return; - } - - sprintf(name, "mesh/rpl/%04x", src); - bt_mesh_erase_core_settings(name); - - err = bt_mesh_remove_core_settings_item("mesh/rpl", src); - if (err) { - BT_ERR("Failed to remove 0x%04x from mesh/rpl", src); - } -} - void bt_mesh_store_node_info(struct bt_mesh_node *node) { struct node_info val = {0}; diff --git a/components/bt/esp_ble_mesh/core/storage/settings.h b/components/bt/esp_ble_mesh/core/storage/settings.h index ebf29132ac..255eb2c343 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.h +++ b/components/bt/esp_ble_mesh/core/storage/settings.h @@ -39,8 +39,12 @@ void bt_mesh_clear_role(void); void bt_mesh_clear_net(void); void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); void bt_mesh_clear_app_key(struct bt_mesh_app_key *key); +void bt_mesh_clear_rpl_single(uint16_t src); void bt_mesh_clear_rpl(void); +void bt_mesh_store_dkca(void); +void bt_mesh_clear_dkca(void); + #if CONFIG_BLE_MESH_PROVISIONER void bt_mesh_store_prov_info(uint16_t primary_addr, uint16_t alloc_addr); void bt_mesh_clear_prov_info(void); @@ -52,7 +56,6 @@ void bt_mesh_store_p_subnet(struct bt_mesh_subnet *sub); void bt_mesh_store_p_app_key(struct bt_mesh_app_key *key); void bt_mesh_clear_p_subnet(uint16_t net_idx); void bt_mesh_clear_p_app_key(uint16_t app_idx); -void bt_mesh_clear_rpl_single(uint16_t src); void bt_mesh_store_node_info(struct bt_mesh_node *node); void bt_mesh_clear_node_info(uint16_t unicast_addr); void bt_mesh_store_node_name(struct bt_mesh_node *node); diff --git a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c index 155937a076..ca3ac144ef 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c @@ -432,7 +432,7 @@ struct net_buf_simple *bt_mesh_get_uid_settings_item(const char *key) /* API used to check if the settings item exists */ -static bool is_settings_item_exist(struct net_buf_simple *buf, const uint16_t val) +bool bt_mesh_is_settings_item_exist(struct net_buf_simple *buf, const uint16_t val) { struct net_buf_simple_state state = {0}; size_t length = 0U; @@ -469,7 +469,7 @@ static int settings_add_item(bt_mesh_nvs_handle_t handle, const char *key, const buf = settings_get_item(handle, key); /* Check if val already exists */ - if (is_settings_item_exist(buf, val) == true) { + if (bt_mesh_is_settings_item_exist(buf, val) == true) { BT_DBG("0x%04x already exists", val); bt_mesh_free_buf(buf); return 0; @@ -533,7 +533,7 @@ static int settings_remove_item(bt_mesh_nvs_handle_t handle, const char *key, co buf = settings_get_item(handle, key); /* Check if val does exist */ - if (is_settings_item_exist(buf, val) == false) { + if (bt_mesh_is_settings_item_exist(buf, val) == false) { BT_DBG("0x%04x not exists", val); bt_mesh_free_buf(buf); return 0; diff --git a/components/bt/esp_ble_mesh/core/storage/settings_nvs.h b/components/bt/esp_ble_mesh/core/storage/settings_nvs.h index 566cbea0cc..6aecce418f 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_nvs.h +++ b/components/bt/esp_ble_mesh/core/storage/settings_nvs.h @@ -57,6 +57,8 @@ int bt_mesh_remove_settings_item(bt_mesh_nvs_handle_t handle, const char *key, c int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val); int bt_mesh_remove_uid_settings_item(const char *key, const uint16_t val); +bool bt_mesh_is_settings_item_exist(struct net_buf_simple *buf, const uint16_t val); + int bt_mesh_settings_erase_key(bt_mesh_nvs_handle_t handle, const char *key); int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle); diff --git a/components/bt/esp_ble_mesh/core/storage/settings_uid.c b/components/bt/esp_ble_mesh/core/storage/settings_uid.c index 81d9ffa61f..511709f1ec 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_uid.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_uid.c @@ -9,6 +9,7 @@ #include #include "mesh.h" +#include "rpl.h" #include "mesh/main.h" #include "mesh/common.h" #include "settings_nvs.h" @@ -354,8 +355,9 @@ static int settings_close(uint8_t index, bool erase) bt_mesh_provisioner_prov_reset(erase); bt_mesh_provisioner_main_reset(erase); bt_mesh_net_reset(); - bt_mesh_rx_reset(erase); + bt_mesh_rx_reset(); bt_mesh_tx_reset(); + bt_mesh_rpl_reset(erase); bt_mesh_settings_reset(erase); if (erase == true) { diff --git a/components/bt/esp_ble_mesh/core/test.c b/components/bt/esp_ble_mesh/core/test.c index 233716ed4a..3d3cc3bbd9 100644 --- a/components/bt/esp_ble_mesh/core/test.c +++ b/components/bt/esp_ble_mesh/core/test.c @@ -18,8 +18,11 @@ #include "access.h" #include "foundation.h" #include "mesh/main.h" +#include "transport.h" +#include "proxy_common.h" +#include "proxy_server.h" -#if defined(CONFIG_BLE_MESH_SELF_TEST) +#if CONFIG_BLE_MESH_SELF_TEST int bt_mesh_test(void) { @@ -39,7 +42,7 @@ int bt_mesh_device_auto_enter_network(struct bt_mesh_device_network_info *info) int err = 0; if (info == NULL || !BLE_MESH_ADDR_IS_UNICAST(info->unicast_addr) || - !BLE_MESH_ADDR_IS_GROUP(info->group_addr)) { + !BLE_MESH_ADDR_IS_GROUP(info->group_addr)) { return -EINVAL; } @@ -158,9 +161,9 @@ int bt_mesh_test_start_scanning(bool wl_en) if (wl_en) { return bt_mesh_scan_with_wl_enable(); - } else { - return bt_mesh_scan_enable(); } + + return bt_mesh_scan_enable(); } int bt_mesh_test_stop_scanning(void) @@ -169,4 +172,21 @@ int bt_mesh_test_stop_scanning(void) } #endif /* CONFIG_BLE_MESH_TEST_USE_WHITE_LIST */ +bt_mesh_test_net_pdu_cb_t net_pdu_test_cb; + +void bt_mesh_test_register_net_pdu_cb(bt_mesh_test_net_pdu_cb_t cb) +{ + net_pdu_test_cb = cb; +} + +void bt_mesh_test_set_seq(uint32_t seq) +{ + if (seq > 0xFFFFFF) { + BT_ERR("Invalid SEQ 0x%08x", seq); + return; + } + + bt_mesh.seq = seq; +} + #endif /* CONFIG_BLE_MESH_SELF_TEST */ diff --git a/components/bt/esp_ble_mesh/core/test.h b/components/bt/esp_ble_mesh/core/test.h index 4d4e96f2fb..23ef6a8427 100644 --- a/components/bt/esp_ble_mesh/core/test.h +++ b/components/bt/esp_ble_mesh/core/test.h @@ -10,14 +10,14 @@ #ifndef _BLE_MESH_TEST_H_ #define _BLE_MESH_TEST_H_ +#include "net.h" +#include "proxy_client.h" #include "mesh/adapter.h" #ifdef __cplusplus extern "C" { #endif -int bt_mesh_test(void); - struct bt_mesh_device_network_info { uint8_t net_key[16]; uint16_t net_idx; @@ -45,6 +45,14 @@ int bt_mesh_test_start_scanning(bool wl_en); int bt_mesh_test_stop_scanning(void); +typedef void (* bt_mesh_test_net_pdu_cb_t)(const uint8_t *data, uint16_t length); + +extern bt_mesh_test_net_pdu_cb_t net_pdu_test_cb; + +void bt_mesh_test_register_net_pdu_cb(bt_mesh_test_net_pdu_cb_t cb); + +void bt_mesh_test_set_seq(uint32_t seq); + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index dbf5543e6b..b3428216e6 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -14,15 +14,19 @@ #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 "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 @@ -74,12 +78,15 @@ static struct seg_tx { struct net_buf *seg[CONFIG_BLE_MESH_TX_SEG_MAX]; uint64_t seq_auth; uint16_t dst; + uint8_t xmit; /* Segment transmit */ uint8_t seg_n:5, /* Last segment index */ new_key:1; /* New/old key */ uint8_t nack_count; /* Number of unacked segs */ uint8_t ttl; uint8_t seg_pending; /* Number of segments pending */ uint8_t attempts; /* Transmit attempts */ + uint8_t cred; /* Security credentials */ + uint8_t tag; /* Additional metadata */ const struct bt_mesh_send_cb *cb; void *cb_data; struct k_delayed_work retransmit; /* Retransmit timer */ @@ -111,55 +118,27 @@ static uint8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT * static uint16_t hb_sub_dst = BLE_MESH_ADDR_UNASSIGNED; -static bt_mesh_mutex_t tx_seg_lock; -static bt_mesh_mutex_t rx_seg_lock; +static bt_mesh_mutex_t seg_tx_lock; +static bt_mesh_mutex_t seg_rx_lock; -static inline void bt_mesh_tx_seg_mutex_new(void) +static inline void bt_mesh_seg_tx_lock(void) { - if (!tx_seg_lock.mutex) { - bt_mesh_mutex_create(&tx_seg_lock); - } + bt_mesh_mutex_lock(&seg_tx_lock); } -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_tx_seg_mutex_free(void) +static inline void bt_mesh_seg_tx_unlock(void) { - bt_mesh_mutex_free(&tx_seg_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_tx_seg_lock(void) -{ - bt_mesh_mutex_lock(&tx_seg_lock); + bt_mesh_mutex_unlock(&seg_tx_lock); } -static inline void bt_mesh_tx_seg_unlock(void) +static inline void bt_mesh_seg_rx_lock(void) { - bt_mesh_mutex_unlock(&tx_seg_lock); + bt_mesh_mutex_lock(&seg_rx_lock); } -static inline void bt_mesh_rx_seg_mutex_new(void) +static inline void bt_mesh_seg_rx_unlock(void) { - if (!rx_seg_lock.mutex) { - bt_mesh_mutex_create(&rx_seg_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_rx_seg_mutex_free(void) -{ - bt_mesh_mutex_free(&rx_seg_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_rx_seg_lock(void) -{ - bt_mesh_mutex_lock(&rx_seg_lock); -} - -static inline void bt_mesh_rx_seg_unlock(void) -{ - bt_mesh_mutex_unlock(&rx_seg_lock); + bt_mesh_mutex_unlock(&seg_rx_lock); } uint8_t bt_mesh_get_seg_retrans_num(void) @@ -187,14 +166,15 @@ void bt_mesh_set_hb_sub_dst(uint16_t addr) } 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 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, tx->xmit, BUF_TIMEOUT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); if (!buf) { BT_ERR("Out of network buffers"); return -ENOBUFS; @@ -202,7 +182,9 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); - if (tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + 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)); @@ -218,15 +200,15 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, BT_ERR("Not enough space in Friend Queue"); net_buf_unref(buf); return -ENOBUFS; - } else { - BT_WARN("No space in Friend Queue"); - goto send; } + + 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)) { + BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ @@ -240,6 +222,15 @@ 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; @@ -267,7 +258,7 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; - bt_mesh_tx_seg_lock(); + bt_mesh_seg_tx_lock(); k_delayed_work_cancel(&tx->retransmit); @@ -287,10 +278,10 @@ static void seg_tx_reset(struct seg_tx *tx) tx->nack_count = 0U; - bt_mesh_tx_seg_unlock(); + bt_mesh_seg_tx_unlock(); if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { - BT_DBG("Proceding with pending IV Update"); + BT_DBG("Proceeding with pending IV Update"); /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ @@ -370,11 +361,11 @@ static void seg_tx_send_unacked(struct seg_tx *tx) { int i, err = 0; - bt_mesh_tx_seg_lock(); + bt_mesh_seg_tx_lock(); if (!(tx->attempts--)) { BT_WARN("Ran out of retransmit attempts"); - bt_mesh_tx_seg_unlock(); + bt_mesh_seg_tx_unlock(); seg_tx_complete(tx, -ETIMEDOUT); return; } @@ -395,19 +386,25 @@ static void seg_tx_send_unacked(struct seg_tx *tx) tx->seg_pending++; - BT_DBG("resending %u/%u", i, tx->seg_n); + BT_INFO("Resending %u/%u, cred 0x%02x", i, tx->seg_n, tx->cred); + /* TODO: + * 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("Sending segment failed"); - bt_mesh_tx_seg_unlock(); + bt_mesh_seg_tx_unlock(); seg_tx_complete(tx, -EIO); return; } } - bt_mesh_tx_seg_unlock(); + bt_mesh_seg_tx_unlock(); } static void seg_retransmit(struct k_work *work) @@ -418,27 +415,19 @@ static void seg_retransmit(struct k_work *work) } 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 struct bt_mesh_send_cb *cb, void *cb_data, + const uint8_t *ctl_op) { - uint8_t seg_hdr = 0U, seg_o = 0U; - uint16_t seq_zero = 0U; struct seg_tx *tx = NULL; + uint16_t seq_zero = 0U; + uint8_t seg_hdr = 0U; + uint8_t seg_o = 0U; int 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); - if (sdu->len < 1) { - BT_ERR("Zero-length SDU not allowed"); - return -EINVAL; - } - - if (sdu->len > BLE_MESH_TX_SDU_MAX) { - BT_ERR("Not enough segment buffers for length %u", sdu->len); - return -EMSGSIZE; - } - for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (!seg_tx[i].nack_count) { tx = &seg_tx[i]; @@ -451,21 +440,32 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, return -EBUSY; } - if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + if (ctl_op) { + seg_hdr = TRANS_CTL_HDR(*ctl_op, 1); + } else if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { seg_hdr = SEG_HDR(0, 0); } else { seg_hdr = SEG_HDR(1, net_tx->aid); } - seg_o = 0U; tx->dst = net_tx->ctx->addr; - tx->seg_n = (sdu->len - 1) / BLE_MESH_APP_SEG_SDU_MAX; + /* 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 { + tx->seg_n = 0; + } tx->nack_count = tx->seg_n + 1; tx->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq); tx->sub = net_tx->sub; tx->new_key = net_tx->sub->kr_flag; tx->attempts = SEG_RETRANSMIT_ATTEMPTS; tx->seg_pending = 0; + tx->cred = net_tx->ctx->send_cred; + tx->tag = net_tx->ctx->send_tag; tx->cb = cb; tx->cb_data = cb_data; @@ -480,10 +480,10 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, BT_DBG("SeqZero 0x%04x", seq_zero); 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_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); @@ -495,8 +495,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, uint16_t len = 0U; int err = 0; - seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, net_tx->xmit, - BUF_TIMEOUT); + seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); if (!seg) { BT_ERR("Out of segment buffers"); seg_tx_reset(tx); @@ -507,13 +506,11 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, net_buf_add_u8(seg, seg_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, (((seq_zero & 0x3f) << 2) | (seg_o >> 3))); net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx->seg_n); - len = MIN(sdu->len, BLE_MESH_APP_SEG_SDU_MAX); - net_buf_add_mem(seg, sdu->data, len); - net_buf_simple_pull(sdu, len); + 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; @@ -528,7 +525,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, &tx->seq_auth, tx->seg_n + 1, &seg->b) && - BLE_MESH_ADDR_IS_UNICAST(net_tx->ctx->addr)) { + BLE_MESH_ADDR_IS_UNICAST(net_tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ @@ -546,10 +543,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, seg_o ? &seg_sent_cb : &first_sent_cb, tx); if (err) { - BT_ERR("Sending segment failed"); + BT_ERR("Sending segment 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 */ @@ -570,17 +575,31 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, return 0; } -struct bt_mesh_app_key *bt_mesh_app_key_find(uint16_t app_idx) +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) { - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != BLE_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return key; + 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; @@ -590,43 +609,43 @@ 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, role = 0U; + uint8_t *ad = NULL; uint8_t aid = 0U; int err = 0; - if (net_buf_simple_tailroom(msg) < BLE_MESH_MIC_SHORT) { - BT_ERR("Insufficient tailroom for Transport MIC"); + if (msg->len < 1) { + BT_ERR("Zero-length SDU not allowed"); return -EINVAL; } if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { - tx->ctx->send_rel = 1U; + 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)); - role = bt_mesh_get_device_role(tx->ctx->model, tx->ctx->srv_send); - if (role == ROLE_NVAL) { - BT_ERR("Failed to get model role"); - return -EINVAL; - } - - err = bt_mesh_app_key_get(tx->sub, tx->ctx->app_idx, &key, - &aid, role, tx->ctx->addr); + 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 (!tx->ctx->send_rel || net_buf_simple_tailroom(msg) < BLE_MESH_MIC_LONG) { + 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 { @@ -642,82 +661,26 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, return err; } - if (tx->ctx->send_rel) { - err = send_seg(tx, msg, cb, cb_data); - } else { - err = send_unseg(tx, msg, cb, cb_data); + if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { + return send_seg(tx, msg, cb, cb_data, NULL); } - return err; + return send_unseg(tx, msg, cb, cb_data, NULL); } -static void update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) +static void revoke_dev_key(const uint8_t *dev_key) { - rpl->src = rx->ctx.addr; - rpl->seq = rx->seq; - rpl->old_iv = rx->old_iv; + if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { + BT_INFO("Revoke Device Key"); - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } -} + memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); + memset(bt_mesh.dev_key_ca, 0, 16); -/* Check the Replay Protection List for a replay attempt. If non-NULL match - * parameter is given the RPL slot is returned but it is not immediately - * updated (needed for segmented messages), whereas if a NULL match is given - * the RPL is immediately updated (used for unsegmented messages). - */ -bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) -{ - int i; - - /* Don't bother checking messages from ourselves */ - if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { - return false; - } - - /* The RPL is used only for the local node */ - if (!rx->local_match) { - return false; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - - /* Empty slot */ - if (!rpl->src) { - if (match) { - *match = rpl; - } else { - update_rpl(rpl, rx); - } - - return false; - } - - /* Existing slot for given address */ - if (rpl->src == rx->ctx.addr) { - if (rx->old_iv && !rpl->old_iv) { - return true; - } - - if ((!rx->old_iv && rpl->old_iv) || - rpl->seq < rx->seq) { - if (match) { - *match = rpl; - } else { - update_rpl(rpl, rx); - } - - return false; - } else { - return true; - } + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_net(); + bt_mesh_clear_dkca(); } } - - BT_ERR("RPL is full!"); - return true; } static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, @@ -753,7 +716,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, buf->len -= APP_MIC_LEN(aszmic); /* Use bt_mesh_alloc_buf() instead of NET_BUF_SIMPLE_DEFINE to avoid - * causing btu task stackoverflow. + * causing btu task stack overflow. */ sdu = bt_mesh_alloc_buf(CONFIG_BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT); if (!sdu) { @@ -774,6 +737,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } 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, @@ -782,11 +746,14 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, continue; } - BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, + 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)); + revoke_dev_key(dev_key); + rx->ctx.app_idx = BLE_MESH_KEY_DEV; bt_mesh_model_recv(rx, sdu); @@ -828,12 +795,14 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } 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, + 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)); @@ -897,8 +866,8 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, uint16_t seq_zero = 0U; uint8_t obo = 0U; - if (buf->len < 6) { - BT_ERR("Too short ack message (len %u)", buf->len); + if (buf->len != 6) { + BT_ERR("Malformed Segment Ack (len %u)", buf->len); return -EINVAL; } @@ -919,7 +888,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr); if (!tx) { - BT_WARN("No matching TX context for ack"); + BT_INFO("No matching TX context for Seg Ack"); return -EINVAL; } @@ -945,10 +914,10 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { - BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n); - bt_mesh_tx_seg_lock(); + BT_INFO("Seg %u/%u acked", bit - 1, tx->seg_n); + bt_mesh_seg_tx_lock(); seg_tx_done(tx, bit - 1); - bt_mesh_tx_seg_unlock(); + bt_mesh_seg_tx_unlock(); } ack &= ~BIT(bit - 1); @@ -970,8 +939,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, uint8_t init_ttl = 0U, hops = 0U; uint16_t feat = 0U; - if (buf->len < 3) { - BT_ERR("Too short heartbeat message (len %u)", buf->len); + if (buf->len != 3) { + BT_ERR("Malformed heartbeat message (len %u)", buf->len); return -EINVAL; } @@ -1008,7 +977,8 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t 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, + 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)); @@ -1025,6 +995,19 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, 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: @@ -1042,7 +1025,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, } } -#if defined(CONFIG_BLE_MESH_LOW_POWER) +#if CONFIG_BLE_MESH_LOW_POWER if (ctl_op == TRANS_CTL_OP_FRIEND_OFFER) { return bt_mesh_lpn_friend_offer(rx, buf); } @@ -1052,7 +1035,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, return bt_mesh_lpn_friend_clear_cfm(rx, buf); } - if (!rx->friend_cred) { + if (rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED) { BT_WARN("Message from friend with wrong credentials"); return -EINVAL; } @@ -1093,14 +1076,14 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, if (rx->ctl) { return ctl_recv(rx, hdr, buf, seq_auth); - } else { - /* 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); } + + /* 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); } static inline int32_t ack_timeout(struct seg_rx *rx) @@ -1128,154 +1111,50 @@ static inline int32_t ack_timeout(struct seg_rx *rx) return MAX(to, K_MSEC(400)); } -static int ctl_send_unseg(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 *buf = NULL; - - buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit, BUF_TIMEOUT); - if (!buf) { - BT_ERR("Out of transport buffers"); - return -ENOBUFS; - } - - net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); - - net_buf_add_u8(buf, TRANS_CTL_HDR(ctl_op, 0)); - - net_buf_add_mem(buf, data, data_len); - - if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { - 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); - return 0; - } - } - - return bt_mesh_net_send(tx, buf, cb, cb_data); -} - -static int ctl_send_seg(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 seg_tx *tx_seg = NULL; - uint16_t unsent = data_len; - uint16_t seq_zero = 0; - uint8_t seg_o = 0; - int i; - - for (tx_seg = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { - if (!seg_tx[i].nack_count) { - tx_seg = &seg_tx[i]; - break; - } - } - - if (!tx_seg) { - BT_ERR("No multi-segment message contexts available"); - return -EBUSY; - } - - tx_seg->dst = tx->ctx->addr; - tx_seg->seg_n = (data_len - 1) / BLE_MESH_CTL_SEG_SDU_MAX; - tx_seg->nack_count = tx_seg->seg_n + 1; - tx_seg->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq); - tx_seg->sub = tx->sub; - tx_seg->new_key = tx->sub->kr_flag; - tx_seg->attempts = SEG_RETRANSMIT_ATTEMPTS; - tx_seg->seg_pending = 0; - tx_seg->cb = cb; - tx_seg->cb_data = cb_data; - - if (tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { - tx_seg->ttl = bt_mesh_default_ttl_get(); - } else { - tx_seg->ttl = tx->ctx->send_ttl; - } - - seq_zero = tx_seg->seq_auth & TRANS_SEQ_ZERO_MASK; - - BT_DBG("SeqZero 0x%04x", seq_zero); - - for (seg_o = 0; seg_o <= tx_seg->seg_n; seg_o++) { - struct net_buf *seg = NULL; - uint16_t len = 0; - int err = 0; - - seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit, - BUF_TIMEOUT); - if (!seg) { - BT_ERR("Out of segment buffers"); - seg_tx_reset(tx_seg); - return -ENOBUFS; - } - - net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN); - - net_buf_add_u8(seg, TRANS_CTL_HDR(ctl_op, 1)); - net_buf_add_u8(seg, (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->seg_n); - - len = MIN(unsent, BLE_MESH_CTL_SEG_SDU_MAX); - net_buf_add_mem(seg, (uint8_t *)data + (data_len - unsent), len); - unsent -= len; - - tx_seg->seg[seg_o] = net_buf_ref(seg); - - BT_DBG("Sending %u/%u", seg_o, tx_seg->seg_n); - tx_seg->seg_pending++; - - err = bt_mesh_net_send(tx, seg, - seg_o ? &seg_sent_cb : &first_sent_cb, - tx_seg); - if (err) { - BT_ERR("Sending segment failed (err %d)", err); - seg_tx_reset(tx_seg); - return err; - } - } - - return 0; -} - 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 (data_len <= BLE_MESH_SDU_UNSEG_MAX) { - return ctl_send_unseg(tx, ctl_op, data, data_len, - cb, cb_data); - } else { - return ctl_send_seg(tx, ctl_op, data, data_len, - cb, cb_data); + 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 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 bt_mesh_msg_ctx ctx = { - .net_idx = sub->net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = dst, - .send_ttl = ttl, + .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, + .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; @@ -1307,12 +1186,12 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { BT_DBG("rx %p", rx); - bt_mesh_rx_seg_lock(); + bt_mesh_seg_rx_lock(); k_delayed_work_cancel(&rx->ack); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && rx->obo && - rx->block != BLOCK_COMPLETE(rx->seg_n)) { + 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); @@ -1331,7 +1210,7 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset) rx->dst = BLE_MESH_ADDR_UNASSIGNED; } - bt_mesh_rx_seg_unlock(); + bt_mesh_seg_rx_unlock(); } static uint32_t incomplete_timeout(struct seg_rx *rx) @@ -1360,11 +1239,11 @@ static void seg_ack(struct k_work *work) BT_DBG("rx %p", rx); - bt_mesh_rx_seg_lock(); + bt_mesh_seg_rx_lock(); if (k_uptime_get_32() - rx->last > incomplete_timeout(rx)) { BT_WARN("Incomplete timer expired"); - bt_mesh_rx_seg_unlock(); + bt_mesh_seg_rx_unlock(); seg_rx_reset(rx, false); return; } @@ -1373,7 +1252,7 @@ static void seg_ack(struct k_work *work) * after the seg_rx_reset() which may reset rx->sub to NULL. */ if (rx->sub == NULL) { - bt_mesh_rx_seg_unlock(); + bt_mesh_seg_rx_unlock(); return; } @@ -1382,16 +1261,7 @@ static void seg_ack(struct k_work *work) k_delayed_work_submit(&rx->ack, ack_timeout(rx)); - bt_mesh_rx_seg_unlock(); -} - -static inline uint8_t seg_len(bool ctl) -{ - if (ctl) { - return BLE_MESH_CTL_SEG_SDU_MAX; - } else { - return BLE_MESH_APP_SEG_SDU_MAX; - } + bt_mesh_seg_rx_unlock(); } static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) @@ -1408,7 +1278,7 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, struct seg_rx *rx = &seg_rx[i]; if (rx->src != net_rx->ctx.addr || - rx->dst != net_rx->ctx.recv_dst) { + rx->dst != net_rx->ctx.recv_dst) { continue; } @@ -1424,8 +1294,7 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, } if (rx->in_use) { - BT_WARN("Duplicate SDU from src 0x%04x", - net_rx->ctx.addr); + BT_WARN("Duplicate SDU from src 0x%04x", net_rx->ctx.addr); /* Clear out the old context since the sender * has apparently started sending a new SDU. @@ -1551,8 +1420,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, */ *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)))); + ((((net_rx->seq & BIT_MASK(14)) - seq_zero)) & BIT_MASK(13)))); *seg_count = seg_n + 1; @@ -1561,7 +1429,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (rx) { /* Discard old SeqAuth packet */ if (rx->seq_auth > *seq_auth) { - BT_WARN("Ignoring old SeqAuth"); + BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", + rx->src, rx->dst); return -EINVAL; } @@ -1581,7 +1450,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, seq_auth, rx->block, rx->obo); if (rpl) { - update_rpl(rpl, net_rx); + bt_mesh_update_rpl(rpl, net_rx); } return -EALREADY; @@ -1608,11 +1477,11 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, * 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)) { + 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, @@ -1635,7 +1504,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, found_rx: if (BIT(seg_o) & rx->block) { - BT_WARN("Received already received fragment"); + BT_INFO("Received already received fragment"); return -EALREADY; } @@ -1668,14 +1537,14 @@ found_rx: rx->last = k_uptime_get_32(); if (!k_delayed_work_remaining_get(&rx->ack) && - !bt_mesh_lpn_established()) { + !bt_mesh_lpn_established()) { k_delayed_work_submit(&rx->ack, ack_timeout(rx)); } /* 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("Received %u/%u", seg_o, seg_n); + BT_INFO("Seg %u/%u received", seg_o, seg_n); /* Mark segment as received */ rx->block |= BIT(seg_o); @@ -1688,7 +1557,7 @@ found_rx: BT_DBG("Complete SDU"); if (rpl) { - update_rpl(rpl, net_rx); + bt_mesh_update_rpl(rpl, net_rx); } *pdu_type = BLE_MESH_FRIEND_PDU_COMPLETE; @@ -1738,7 +1607,8 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) */ 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->friend_cred)) { + (!bt_mesh_lpn_waiting_update() || + rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { BT_WARN("Ignoring unexpected message in Low Power mode"); return -EAGAIN; } @@ -1794,35 +1664,24 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) return err; } -void bt_mesh_rx_reset(bool erase) +void bt_mesh_rx_reset(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx_reset(&seg_rx[i], true); } - - (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); - - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && erase) { - bt_mesh_clear_rpl(); - } } void bt_mesh_tx_reset(void) { int i; - BT_DBG("%s", __func__); - for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { seg_tx_reset(&seg_tx[i]); } } -#if CONFIG_BLE_MESH_PROVISIONER void bt_mesh_rx_reset_single(uint16_t src) { int i; @@ -1837,16 +1696,6 @@ void bt_mesh_rx_reset_single(uint16_t src) seg_rx_reset(rx, true); } } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - if (src == rpl->src) { - memset(rpl, 0, sizeof(struct bt_mesh_rpl)); - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_clear_rpl_single(src); - } - } - } } void bt_mesh_tx_reset_single(uint16_t dst) @@ -1864,12 +1713,13 @@ void bt_mesh_tx_reset_single(uint16_t dst) } } } -#endif /* CONFIG_BLE_MESH_PROVISIONER */ void bt_mesh_trans_init(void) { int i; + bt_mesh_sar_init(); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); } @@ -1881,8 +1731,8 @@ void bt_mesh_trans_init(void) seg_rx[i].buf.data = seg_rx[i].buf.__buf; } - bt_mesh_tx_seg_mutex_new(); - bt_mesh_rx_seg_mutex_new(); + bt_mesh_mutex_create(&seg_tx_lock); + bt_mesh_mutex_create(&seg_rx_lock); } #if CONFIG_BLE_MESH_DEINIT @@ -1890,8 +1740,9 @@ void bt_mesh_trans_deinit(bool erase) { int i; - bt_mesh_rx_reset(erase); + bt_mesh_rx_reset(); bt_mesh_tx_reset(); + bt_mesh_rpl_reset(erase); for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { k_delayed_work_free(&seg_tx[i].retransmit); @@ -1901,8 +1752,8 @@ void bt_mesh_trans_deinit(bool erase) k_delayed_work_free(&seg_rx[i].ack); } - bt_mesh_tx_seg_mutex_free(); - bt_mesh_rx_seg_mutex_free(); + bt_mesh_mutex_free(&seg_tx_lock); + bt_mesh_mutex_free(&seg_rx_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -1910,20 +1761,21 @@ void bt_mesh_heartbeat_send(void) { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); uint16_t feat = 0U; - struct __packed { + struct __attribute__((packed)) { uint8_t init_ttl; uint16_t feat; } hb; struct bt_mesh_msg_ctx ctx = { - .net_idx = cfg->hb_pub.net_idx, - .app_idx = BLE_MESH_KEY_UNUSED, - .addr = cfg->hb_pub.dst, - .send_ttl = cfg->hb_pub.ttl, + .net_idx = cfg->hb_pub.net_idx, + .app_idx = BLE_MESH_KEY_UNUSED, + .addr = cfg->hb_pub.dst, + .send_ttl = cfg->hb_pub.ttl, + .send_cred = BLE_MESH_FLOODING_CRED, }; struct bt_mesh_net_tx tx = { - .sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx), - .ctx = &ctx, - .src = bt_mesh_model_elem(cfg->model)->addr, + .sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx), + .ctx = &ctx, + .src = bt_mesh_model_elem(cfg->model)->addr, .xmit = bt_mesh_net_transmit_get(), }; @@ -1958,15 +1810,15 @@ void bt_mesh_heartbeat_send(void) NULL, NULL); } -int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint8_t role, uint16_t dst) +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_tx_devkey_get(role, dst); + *key = bt_mesh_dev_key_get(dst); if (!*key) { - BT_ERR("DevKey not found"); + BT_ERR("DevKey of 0x%04x not found", dst); return -EINVAL; } @@ -1979,9 +1831,9 @@ int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, return -EINVAL; } - app_key = bt_mesh_tx_appkey_get(role, app_idx); + app_key = bt_mesh_app_key_get(app_idx); if (!app_key) { - BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); + BT_ERR("AppKey 0x%04x not found", app_idx); return -ENOENT; } diff --git a/components/bt/esp_ble_mesh/core/transport.h b/components/bt/esp_ble_mesh/core/transport.h index 015b51e4df..1feccb9980 100644 --- a/components/bt/esp_ble_mesh/core/transport.h +++ b/components/bt/esp_ble_mesh/core/transport.h @@ -16,39 +16,46 @@ extern "C" { #endif -#define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff +#define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff -#define BLE_MESH_SDU_UNSEG_MAX 11 -#define BLE_MESH_CTL_SEG_SDU_MAX 8 -#define BLE_MESH_APP_SEG_SDU_MAX 12 -#define BLE_MESH_TX_SDU_MAX (CONFIG_BLE_MESH_TX_SEG_MAX * 12) +#define BLE_MESH_SDU_UNSEG_MAX 11 +#define BLE_MESH_CTL_SEG_SDU_MAX 8 +#define BLE_MESH_APP_SEG_SDU_MAX 12 +#define BLE_MESH_TX_SDU_MAX (CONFIG_BLE_MESH_TX_SEG_MAX * 12) -#define TRANS_SEQ_ZERO_MASK ((uint16_t)BIT_MASK(13)) -#define TRANS_CTL_OP_MASK ((uint8_t)BIT_MASK(7)) -#define TRANS_CTL_OP(data) ((data)[0] & TRANS_CTL_OP_MASK) -#define TRANS_CTL_HDR(op, seg) ((op & TRANS_CTL_OP_MASK) | (seg << 7)) +#define TRANS_SEQ_ZERO_MASK ((uint16_t)BIT_MASK(13)) +#define TRANS_CTL_OP_MASK ((uint8_t)BIT_MASK(7)) +#define TRANS_CTL_OP(data) ((data)[0] & TRANS_CTL_OP_MASK) +#define TRANS_CTL_HDR(op, seg) (((op) & TRANS_CTL_OP_MASK) | ((seg) << 7)) -#define TRANS_CTL_OP_ACK 0x00 -#define TRANS_CTL_OP_FRIEND_POLL 0x01 -#define TRANS_CTL_OP_FRIEND_UPDATE 0x02 -#define TRANS_CTL_OP_FRIEND_REQ 0x03 -#define TRANS_CTL_OP_FRIEND_OFFER 0x04 -#define TRANS_CTL_OP_FRIEND_CLEAR 0x05 -#define TRANS_CTL_OP_FRIEND_CLEAR_CFM 0x06 -#define TRANS_CTL_OP_FRIEND_SUB_ADD 0x07 -#define TRANS_CTL_OP_FRIEND_SUB_REM 0x08 -#define TRANS_CTL_OP_FRIEND_SUB_CFM 0x09 -#define TRANS_CTL_OP_HEARTBEAT 0x0a +#define TRANS_CTL_OP_ACK 0x00 +#define TRANS_CTL_OP_FRIEND_POLL 0x01 +#define TRANS_CTL_OP_FRIEND_UPDATE 0x02 +#define TRANS_CTL_OP_FRIEND_REQ 0x03 +#define TRANS_CTL_OP_FRIEND_OFFER 0x04 +#define TRANS_CTL_OP_FRIEND_CLEAR 0x05 +#define TRANS_CTL_OP_FRIEND_CLEAR_CFM 0x06 +#define TRANS_CTL_OP_FRIEND_SUB_ADD 0x07 +#define TRANS_CTL_OP_FRIEND_SUB_REM 0x08 +#define TRANS_CTL_OP_FRIEND_SUB_CFM 0x09 +#define TRANS_CTL_OP_HEARTBEAT 0x0A +#define TRANS_CTL_OP_PATH_REQ 0x0B +#define TRANS_CTL_OP_PATH_REPLY 0x0C +#define TRANS_CTL_OP_PATH_CFM 0x0D +#define TRANS_CTL_OP_PATH_ECHO_REQ 0x0E +#define TRANS_CTL_OP_PATH_ECHO_REPLY 0x0F +#define TRANS_CTL_OP_DEP_NODE_UPDATE 0x10 +#define TRANS_CTL_OP_PATH_REQ_SOLIC 0x11 struct bt_mesh_ctl_friend_poll { uint8_t fsn; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_update { uint8_t flags; uint32_t iv_index; uint8_t md; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_req { uint8_t criteria; @@ -57,7 +64,7 @@ struct bt_mesh_ctl_friend_req { uint16_t prev_addr; uint8_t num_elem; uint16_t lpn_counter; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_offer { uint8_t recv_win; @@ -65,27 +72,27 @@ struct bt_mesh_ctl_friend_offer { uint8_t sub_list_size; int8_t rssi; uint16_t frnd_counter; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_clear { uint16_t lpn_addr; uint16_t lpn_counter; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_clear_confirm { uint16_t lpn_addr; uint16_t lpn_counter; -} __packed; +} __attribute__((packed)); #define BLE_MESH_FRIEND_SUB_MIN_LEN (1 + 2) struct bt_mesh_ctl_friend_sub { uint8_t xact; uint16_t addr_list[5]; -} __packed; +} __attribute__((packed)); struct bt_mesh_ctl_friend_sub_confirm { uint8_t xact; -} __packed; +} __attribute__((packed)); uint8_t bt_mesh_get_seg_retrans_num(void); @@ -93,11 +100,11 @@ int32_t bt_mesh_get_seg_retrans_timeout(uint8_t ttl); void bt_mesh_set_hb_sub_dst(uint16_t addr); -struct bt_mesh_app_key *bt_mesh_app_key_find(uint16_t app_idx); +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); bool bt_mesh_tx_in_progress(void); -void bt_mesh_rx_reset(bool erase); +void bt_mesh_rx_reset(void); void bt_mesh_tx_reset(void); void bt_mesh_rx_reset_single(uint16_t src); void bt_mesh_tx_reset_single(uint16_t dst); @@ -114,12 +121,10 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); void bt_mesh_trans_init(void); void bt_mesh_trans_deinit(bool erase); -bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); - void bt_mesh_heartbeat_send(void); -int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint8_t role, uint16_t dst); +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); #ifdef __cplusplus } 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 724087c059..3b4495fe53 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -14,6 +14,8 @@ #include "mesh/client_common.h" #include "mesh/common.h" +#include "mesh_v1.1/utils.h" + #define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */ static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16_t tx_dst) @@ -28,7 +30,7 @@ static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16 } for (cur = sys_slist_peek_head(list); - cur != NULL; cur = sys_slist_peek_next(cur)) { + cur != NULL; cur = sys_slist_peek_next(cur)) { node = (bt_mesh_client_node_t *)cur; if (node->ctx.addr == tx_dst) { bt_mesh_list_unlock(); @@ -121,7 +123,7 @@ static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst } for (cur = sys_slist_peek_head(list); - cur != NULL; cur = sys_slist_peek_next(cur)) { + cur != NULL; cur = sys_slist_peek_next(cur)) { node = (bt_mesh_client_node_t *)cur; if (node->ctx.addr == tx_dst) { bt_mesh_list_unlock(); @@ -151,12 +153,22 @@ static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_ return 0; } -static int32_t bt_mesh_get_adv_duration(void) +static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) { - uint16_t duration, adv_int; - uint8_t xmit; + uint16_t duration = 0, adv_int = 0; + uint8_t xmit = 0; + + /* Initialize with network transmission */ + xmit = bt_mesh_net_transmit_get(); + + if (bt_mesh_tag_immutable_cred(ctx->send_tag)) { +#if CONFIG_BLE_MESH_DF_SRV + if (ctx->send_cred == BLE_MESH_DIRECTED_CRED) { + xmit = bt_mesh_direct_net_transmit_get(); /* Directed network transmission */ + } +#endif + } - xmit = bt_mesh_net_transmit_get(); /* Network transmit */ adv_int = BLE_MESH_TRANSMIT_INT(xmit); duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); @@ -167,29 +179,31 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, uint32_t opcode, int32_t timeout) { - int32_t seg_retrans_to = 0, duration = 0, time = 0; - uint8_t seg_count = 0, seg_retrans_num = 0; + int32_t seg_rtx_to = 0, duration = 0, time = 0; + uint8_t seg_count = 0, seg_rtx_num = 0; bool need_seg = false; uint8_t mic_size = 0; - if (msg->len > BLE_MESH_SDU_UNSEG_MAX || ctx->send_rel) { + if (msg->len > BLE_MESH_SDU_UNSEG_MAX || + bt_mesh_tag_send_segmented(ctx->send_tag)) { need_seg = true; /* Needs segmentation */ } - mic_size = (need_seg && net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ? + mic_size = (need_seg && ctx->send_szmic == BLE_MESH_SEG_SZMIC_LONG && + net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ? BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT; if (need_seg) { /* Based on the message length, calculate how many segments are needed. * All the messages sent from here are access messages. */ - seg_retrans_num = bt_mesh_get_seg_retrans_num(); - seg_retrans_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl); + seg_rtx_num = bt_mesh_get_seg_retrans_num(); + seg_rtx_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl); seg_count = (msg->len + mic_size - 1) / 12U + 1U; - duration = bt_mesh_get_adv_duration(); + duration = bt_mesh_get_adv_duration(ctx); - /* Currenlty only consider the time consumption of the same segmented + /* Currently only consider the time consumption of the same segmented * messages, but if there are other messages between any two retrans- * missions of the same segmented messages, then the whole time will * be longer. @@ -200,7 +214,7 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, * the attempts reaches ZERO when the dst is a unicast address. */ int32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV); - time = (seg_duration + seg_retrans_to) * seg_retrans_num; + time = (seg_duration + seg_rtx_to) * seg_rtx_num; BT_INFO("Original timeout %dms, calculated timeout %dms", timeout, time); @@ -274,11 +288,6 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, return -EINVAL; } - if (bt_mesh_set_client_model_role(param->model, param->msg_role)) { - BT_ERR("Failed to set client role"); - return -EIO; - } - if (need_ack == false || !BLE_MESH_ADDR_IS_UNICAST(param->ctx.addr)) { /* 1. If this is an unacknowledged message, send it directly. * 2. If this is an acknowledged message, but the destination @@ -311,11 +320,11 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, } memcpy(&node->ctx, ¶m->ctx, sizeof(struct bt_mesh_msg_ctx)); - node->ctx.model = param->model; + node->model = param->model; node->opcode = param->opcode; node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); if (node->op_pending == 0U) { - BT_ERR("Not found the status opcode in op_pair list"); + BT_ERR("Status opcode not found in op_pair list, opcode 0x%08x", param->opcode); bt_mesh_free(node); return -EINVAL; } @@ -348,20 +357,6 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, static bt_mesh_mutex_t client_model_lock; -static inline void bt_mesh_client_model_mutex_new(void) -{ - if (!client_model_lock.mutex) { - bt_mesh_mutex_create(&client_model_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_client_model_mutex_free(void) -{ - bt_mesh_mutex_free(&client_model_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - void bt_mesh_client_model_lock(void) { bt_mesh_mutex_lock(&client_model_lock); @@ -374,7 +369,7 @@ void bt_mesh_client_model_unlock(void) int bt_mesh_client_init(struct bt_mesh_model *model) { - bt_mesh_client_internal_data_t *data = NULL; + bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; if (!model || !model->op) { @@ -388,23 +383,23 @@ int bt_mesh_client_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - data = bt_mesh_calloc(sizeof(bt_mesh_client_internal_data_t)); - if (!data) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - /* Init the client data queue */ - sys_slist_init(&data->queue); - - client->model = model; - client->internal_data = data; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_client_model_mutex_new(); + internal = bt_mesh_calloc(sizeof(bt_mesh_client_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->internal_data = internal; + + bt_mesh_mutex_create(&client_model_lock); return 0; } @@ -434,7 +429,7 @@ int bt_mesh_client_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_client_model_mutex_free(); + bt_mesh_mutex_free(&client_model_lock); return 0; } @@ -445,12 +440,12 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; - if (!node || !node->ctx.model) { + if (!node || !node->model) { BT_ERR("Invalid client list item"); return -EINVAL; } - client = (bt_mesh_client_user_data_t *)node->ctx.model->user_data; + client = (bt_mesh_client_user_data_t *)node->model->user_data; if (!client) { BT_ERR("Invalid client user data"); return -EINVAL; @@ -466,6 +461,7 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) bt_mesh_list_lock(); sys_slist_find_and_remove(&internal->queue, &node->client_node); bt_mesh_list_unlock(); + // Free the node bt_mesh_free(node); @@ -494,27 +490,3 @@ int bt_mesh_client_clear_list(void *data) return 0; } - -int bt_mesh_set_client_model_role(struct bt_mesh_model *model, uint8_t role) -{ - bt_mesh_client_user_data_t *client = NULL; - - if (!model) { - BT_ERR("Invalid client model"); - return -EINVAL; - } - - client = (bt_mesh_client_user_data_t *)model->user_data; - if (!client) { - BT_ERR("Invalid client user data"); - return -EINVAL; - } - - if (role >= ROLE_NVAL) { - BT_ERR("Invalid client role 0x%02x", role); - return -EINVAL; - } - - client->msg_role = role; - return 0; -} diff --git a/components/bt/esp_ble_mesh/models/client/generic_client.c b/components/bt/esp_ble_mesh/models/client/generic_client.c index 1bb1ce131a..af09dc1bef 100644 --- a/components/bt/esp_ble_mesh/models/client/generic_client.c +++ b/components/bt/esp_ble_mesh/models/client/generic_client.c @@ -65,7 +65,7 @@ #define BLE_MESH_GEN_MANU_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) #define BLE_MESH_GEN_MANU_PROPERTY_GET_MSG_LEN (2 + 2 + 4) #define BLE_MESH_GEN_MANU_PROPERTY_SET_MSG_LEN (1 + 3 + 4) -#define BLE_MESH_GEN_CLINET_PROPERTIES_GET_MSG_LEN (1 + 2 + 4) +#define BLE_MESH_GEN_CLIENT_PROPERTIES_GET_MSG_LEN (1 + 2 + 4) #define BLE_MESH_GEN_GET_STATE_MSG_LEN (2 + 2 + 4) @@ -106,40 +106,17 @@ static const bt_mesh_client_op_pair_t gen_op_pair[] = { static bt_mesh_mutex_t generic_client_lock; -static inline void bt_mesh_generic_client_mutex_new(void) -{ - if (!generic_client_lock.mutex) { - bt_mesh_mutex_create(&generic_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_generic_client_mutex_free(void) -{ - bt_mesh_mutex_free(&generic_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_generic_client_lock(void) -{ - bt_mesh_mutex_lock(&generic_client_lock); -} - -static inline void bt_mesh_generic_client_unlock(void) -{ - bt_mesh_mutex_unlock(&generic_client_lock); -} - static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive generic status message timeout"); - bt_mesh_generic_client_lock(); + bt_mesh_mutex_lock(&generic_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -148,15 +125,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_generic_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_GENERIC_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_GENERIC_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_generic_client_unlock(); - - return; + bt_mesh_mutex_unlock(&generic_client_lock); } static void generic_status(struct bt_mesh_model *model, @@ -525,7 +501,7 @@ static void generic_status(struct bt_mesh_model *model, buf->data = val; buf->len = len; - bt_mesh_generic_client_lock(); + bt_mesh_mutex_lock(&generic_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); if (!node) { @@ -579,7 +555,7 @@ static void generic_status(struct bt_mesh_model *model, } } - bt_mesh_generic_client_unlock(); + bt_mesh_mutex_unlock(&generic_client_lock); switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { @@ -629,8 +605,6 @@ static void generic_status(struct bt_mesh_model *model, } bt_mesh_free(val); - - return; } const struct bt_mesh_model_op bt_mesh_gen_onoff_cli_op[] = { @@ -1147,24 +1121,25 @@ static int generic_client_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(generic_internal_data_t)); - if (!internal) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(gen_op_pair); - client->op_pair = gen_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_generic_client_mutex_new(); + internal = bt_mesh_calloc(sizeof(generic_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(gen_op_pair); + client->op_pair = gen_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&generic_client_lock); return 0; } @@ -1194,7 +1169,7 @@ static int generic_client_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_generic_client_mutex_free(); + bt_mesh_mutex_free(&generic_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/client/include/mesh/client_common.h b/components/bt/esp_ble_mesh/models/client/include/mesh/client_common.h index 973c005359..25834a1d6b 100644 --- a/components/bt/esp_ble_mesh/models/client/include/mesh/client_common.h +++ b/components/bt/esp_ble_mesh/models/client/include/mesh/client_common.h @@ -25,7 +25,7 @@ typedef struct { struct bt_mesh_model *model; /** Size of the opcode pair table */ - int op_pair_size; + uint32_t op_pair_size; /** Pointer to the opcode pair table */ const bt_mesh_client_op_pair_t *op_pair; @@ -41,23 +41,29 @@ typedef struct { * * @return None */ - void (*publish_status)(uint32_t opcode, struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); + void (*publish_status)(uint32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); /** Pointer to the internal data of client model */ void *internal_data; + /** Pointer to the vendor data of client model */ + void *vendor_data; + /** Role of the device to which the client model belongs */ - uint8_t msg_role; + uint8_t msg_role __attribute__((deprecated)); } bt_mesh_client_user_data_t; /** Client model internal data context */ -typedef struct { +typedef struct { sys_slist_t queue; } bt_mesh_client_internal_data_t; /** Client model sending message related context */ typedef struct { sys_snode_t client_node; + struct bt_mesh_model *model; /* Pointer to the client model */ struct bt_mesh_msg_ctx ctx; /* Message context */ uint32_t opcode; /* Message opcode */ uint32_t op_pending; /* Expected status message opcode */ @@ -71,7 +77,7 @@ typedef struct { struct bt_mesh_model *model; /* Pointer to the client model */ struct bt_mesh_msg_ctx ctx; /* Message context */ int32_t msg_timeout; /* Time to get corresponding response */ - uint8_t msg_role; /* Role (Node/Provisioner) of the device */ + uint8_t msg_role __attribute__((deprecated)); /* Role (Node/Provisioner) of the device */ const struct bt_mesh_send_cb *cb; /* User defined callback function */ void *cb_data; /* User defined callback value */ } bt_mesh_client_common_param_t; @@ -95,7 +101,8 @@ int bt_mesh_client_deinit(struct bt_mesh_model *model); */ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, bool need_pub); + struct net_buf_simple *buf, + bool need_pub); int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, struct net_buf_simple *msg, bool need_ack, @@ -105,16 +112,6 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node); int bt_mesh_client_clear_list(void *data); -/** - * @brief Set role of the client model for internal use. - * - * @param[in] model: Pointer to the client model - * @param[in] role: Role of the device - * - * @return Zero - success, otherwise - fail - */ -int bt_mesh_set_client_model_role(struct bt_mesh_model *model, uint8_t role); - #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/models/client/lighting_client.c b/components/bt/esp_ble_mesh/models/client/lighting_client.c index b83984ecac..6448a41081 100644 --- a/components/bt/esp_ble_mesh/models/client/lighting_client.c +++ b/components/bt/esp_ble_mesh/models/client/lighting_client.c @@ -113,42 +113,19 @@ static const bt_mesh_client_op_pair_t light_op_pair[] = { { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS }, }; -static bt_mesh_mutex_t light_client_lock; - -static void bt_mesh_light_client_mutex_new(void) -{ - if (!light_client_lock.mutex) { - bt_mesh_mutex_create(&light_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static void bt_mesh_light_client_mutex_free(void) -{ - bt_mesh_mutex_free(&light_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static void bt_mesh_light_client_lock(void) -{ - bt_mesh_mutex_lock(&light_client_lock); -} - -static void bt_mesh_light_client_unlock(void) -{ - bt_mesh_mutex_unlock(&light_client_lock); -} +static bt_mesh_mutex_t lighting_client_lock; static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive light status message timeout"); - bt_mesh_light_client_lock(); + bt_mesh_mutex_lock(&lighting_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -157,15 +134,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_lighting_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_LIGHTING_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_LIGHTING_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_light_client_unlock(); - - return; + bt_mesh_mutex_unlock(&lighting_client_lock); } static void light_status(struct bt_mesh_model *model, @@ -640,7 +616,7 @@ static void light_status(struct bt_mesh_model *model, buf->data = val; buf->len = len; - bt_mesh_light_client_lock(); + bt_mesh_mutex_lock(&lighting_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); if (!node) { @@ -705,7 +681,7 @@ static void light_status(struct bt_mesh_model *model, } } - bt_mesh_light_client_unlock(); + bt_mesh_mutex_unlock(&lighting_client_lock); switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { @@ -719,8 +695,6 @@ static void light_status(struct bt_mesh_model *model, } bt_mesh_free(val); - - return; } const struct bt_mesh_model_op bt_mesh_light_lightness_cli_op[] = { @@ -1337,24 +1311,25 @@ static int lighting_client_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(light_internal_data_t)); - if (!internal) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(light_op_pair); - client->op_pair = light_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_light_client_mutex_new(); + internal = bt_mesh_calloc(sizeof(light_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(light_op_pair); + client->op_pair = light_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&lighting_client_lock); return 0; } @@ -1384,7 +1359,7 @@ static int lighting_client_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_light_client_mutex_free(); + bt_mesh_mutex_free(&lighting_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/client/sensor_client.c b/components/bt/esp_ble_mesh/models/client/sensor_client.c index 882d9ce0a0..fa093ff6fb 100644 --- a/components/bt/esp_ble_mesh/models/client/sensor_client.c +++ b/components/bt/esp_ble_mesh/models/client/sensor_client.c @@ -44,40 +44,17 @@ static const bt_mesh_client_op_pair_t sensor_op_pair[] = { static bt_mesh_mutex_t sensor_client_lock; -static inline void bt_mesh_sensor_client_mutex_new(void) -{ - if (!sensor_client_lock.mutex) { - bt_mesh_mutex_create(&sensor_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_sensor_client_mutex_free(void) -{ - bt_mesh_mutex_free(&sensor_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_sensor_client_lock(void) -{ - bt_mesh_mutex_lock(&sensor_client_lock); -} - -static inline void bt_mesh_sensor_client_unlock(void) -{ - bt_mesh_mutex_unlock(&sensor_client_lock); -} - static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive sensor status message timeout"); - bt_mesh_sensor_client_lock(); + bt_mesh_mutex_lock(&sensor_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -86,15 +63,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_sensor_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_SENSOR_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_SENSOR_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_sensor_client_unlock(); - - return; + bt_mesh_mutex_unlock(&sensor_client_lock); } static void sensor_status(struct bt_mesh_model *model, @@ -253,7 +229,7 @@ static void sensor_status(struct bt_mesh_model *model, buf->data = val; buf->len = len; - bt_mesh_sensor_client_lock(); + bt_mesh_mutex_lock(&sensor_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); if (!node) { @@ -284,7 +260,7 @@ static void sensor_status(struct bt_mesh_model *model, } } - bt_mesh_sensor_client_unlock(); + bt_mesh_mutex_unlock(&sensor_client_lock); switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { @@ -334,8 +310,6 @@ static void sensor_status(struct bt_mesh_model *model, } bt_mesh_free(val); - - return; } const struct bt_mesh_model_op bt_mesh_sensor_cli_op[] = { @@ -587,24 +561,25 @@ static int sensor_client_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(sensor_internal_data_t)); - if (!internal) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(sensor_op_pair); - client->op_pair = sensor_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_sensor_client_mutex_new(); + internal = bt_mesh_calloc(sizeof(sensor_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(sensor_op_pair); + client->op_pair = sensor_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&sensor_client_lock); return 0; } @@ -634,7 +609,7 @@ static int sensor_client_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_sensor_client_mutex_free(); + bt_mesh_mutex_free(&sensor_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/client/time_scene_client.c b/components/bt/esp_ble_mesh/models/client/time_scene_client.c index 1584b5cdbe..8cdc4800ee 100644 --- a/components/bt/esp_ble_mesh/models/client/time_scene_client.c +++ b/components/bt/esp_ble_mesh/models/client/time_scene_client.c @@ -60,40 +60,17 @@ static const bt_mesh_client_op_pair_t time_scene_op_pair[] = { static bt_mesh_mutex_t time_scene_client_lock; -static inline void bt_mesh_time_scene_client_mutex_new(void) -{ - if (!time_scene_client_lock.mutex) { - bt_mesh_mutex_create(&time_scene_client_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_time_scene_client_mutex_free(void) -{ - bt_mesh_mutex_free(&time_scene_client_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - -static inline void bt_mesh_time_scene_client_lock(void) -{ - bt_mesh_mutex_lock(&time_scene_client_lock); -} - -static inline void bt_mesh_time_scene_client_unlock(void) -{ - bt_mesh_mutex_unlock(&time_scene_client_lock); -} - static void timeout_handler(struct k_work *work) { struct k_delayed_work *timer = NULL; bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; struct bt_mesh_msg_ctx ctx = {0}; uint32_t opcode = 0U; BT_WARN("Receive time scene status message timeout"); - bt_mesh_time_scene_client_lock(); + bt_mesh_mutex_lock(&time_scene_client_lock); timer = CONTAINER_OF(work, struct k_delayed_work, work); @@ -102,15 +79,14 @@ static void timeout_handler(struct k_work *work) if (node) { memcpy(&ctx, &node->ctx, sizeof(ctx)); opcode = node->opcode; + model = node->model; bt_mesh_client_free_node(node); bt_mesh_time_scene_client_cb_evt_to_btc( - opcode, BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_TIMEOUT, ctx.model, &ctx, NULL, 0); + opcode, BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_TIMEOUT, model, &ctx, NULL, 0); } } - bt_mesh_time_scene_client_unlock(); - - return; + bt_mesh_mutex_unlock(&time_scene_client_lock); } static void time_scene_status(struct bt_mesh_model *model, @@ -290,7 +266,7 @@ static void time_scene_status(struct bt_mesh_model *model, buf->data = val; buf->len = len; - bt_mesh_time_scene_client_lock(); + bt_mesh_mutex_lock(&time_scene_client_lock); node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); if (!node) { @@ -328,7 +304,7 @@ static void time_scene_status(struct bt_mesh_model *model, } } - bt_mesh_time_scene_client_unlock(); + bt_mesh_mutex_unlock(&time_scene_client_lock); switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { @@ -342,8 +318,6 @@ static void time_scene_status(struct bt_mesh_model *model, } bt_mesh_free(val); - - return; } const struct bt_mesh_model_op bt_mesh_time_cli_op[] = { @@ -643,24 +617,25 @@ static int time_scene_client_init(struct bt_mesh_model *model) return -EINVAL; } - if (!client->internal_data) { - internal = bt_mesh_calloc(sizeof(time_scene_internal_data_t)); - if (!internal) { - BT_ERR("%s, Out of memory", __func__); - return -ENOMEM; - } - - sys_slist_init(&internal->queue); - - client->model = model; - client->op_pair_size = ARRAY_SIZE(time_scene_op_pair); - client->op_pair = time_scene_op_pair; - client->internal_data = internal; - } else { - bt_mesh_client_clear_list(client->internal_data); + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; } - bt_mesh_time_scene_client_mutex_new(); + internal = bt_mesh_calloc(sizeof(time_scene_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(time_scene_op_pair); + client->op_pair = time_scene_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&time_scene_client_lock); return 0; } @@ -690,7 +665,7 @@ static int time_scene_client_deinit(struct bt_mesh_model *model) client->internal_data = NULL; } - bt_mesh_time_scene_client_mutex_free(); + bt_mesh_mutex_free(&time_scene_client_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/common/include/mesh/device_property.h b/components/bt/esp_ble_mesh/models/common/include/mesh/device_property.h index 643387436b..33d75d4bd0 100644 --- a/components/bt/esp_ble_mesh/models/common/include/mesh/device_property.h +++ b/components/bt/esp_ble_mesh/models/common/include/mesh/device_property.h @@ -852,7 +852,7 @@ typedef uint16_t bt_mesh_voltage_t; /* This characteristic aggregates the Electric Current characteristic and instance of * the Time Exponential 8 characteristic. */ -typedef struct __packed average_current { +typedef struct __attribute__((packed)) average_current { bt_mesh_electric_current_t electric_current; bt_mesh_time_exponential_8_t sensing_duration; } bt_mesh_average_current_t; @@ -860,7 +860,7 @@ typedef struct __packed average_current { /* This characteristic aggregates the Voltage characteristic and instance of the Time * Exponential 8 characteristic. */ -typedef struct __packed average_voltage { +typedef struct __attribute__((packed)) average_voltage { bt_mesh_voltage_t voltage; bt_mesh_time_exponential_8_t sensing_duration; } bt_mesh_average_voltage_t; @@ -896,7 +896,7 @@ typedef uint16_t bt_mesh_chromaticity_coordinate_t; /* This characteristic represents a chromaticity coordinate as a tuple with an x and * y coordinate. */ -typedef struct __packed chromaticity_coordinates { +typedef struct __attribute__((packed)) chromaticity_coordinates { bt_mesh_chromaticity_coordinate_t chromaticity_x_coordinate; bt_mesh_chromaticity_coordinate_t chromaticity_y_coordinate; } bt_mesh_chromaticity_coordinates_t; @@ -913,7 +913,7 @@ typedef uint16_t bt_mesh_correlated_color_temperature_t; * consisting of the Correlated Color Temperature characteristic and the Chromatic * Distance From Planckian characteristic. */ -typedef struct __packed chromaticity_in_cct_and_duv_values { +typedef struct __attribute__((packed)) chromaticity_in_cct_and_duv_values { bt_mesh_correlated_color_temperature_t correlated_color_temperature; bt_mesh_chromatic_distance_from_planckian_t chromaticity_distance_from_planckian; } bt_mesh_chromaticity_in_cct_and_duv_values_t; @@ -969,7 +969,7 @@ typedef uint8_t bt_mesh_date_utc_t[3]; /* This characteristic aggregates two instances of the Electric Current characteristic * to represent a range of Electric Current values. */ -typedef struct __packed electric_current_range { +typedef struct __attribute__((packed)) electric_current_range { bt_mesh_electric_current_t minimum_electric_current_value; bt_mesh_electric_current_t maximum_electric_current_value; } bt_mesh_electric_current_range_t; @@ -977,7 +977,7 @@ typedef struct __packed electric_current_range { /* This characteristic aggregates three instances of the Electric Current characteristic * to represent a specification of electric current values. */ -typedef struct __packed electric_current_specification { +typedef struct __attribute__((packed)) electric_current_specification { bt_mesh_electric_current_t minimum_electric_current_value; bt_mesh_electric_current_t typical_electric_current_value; bt_mesh_electric_current_t maximum_electric_current_value; @@ -986,7 +986,7 @@ typedef struct __packed electric_current_specification { /* This characteristic aggregates four instances of the Electric Current characteristic * with a Sensing Duration to represent a set of statistical electric current values. */ -typedef struct __packed electric_current_statistics { +typedef struct __attribute__((packed)) electric_current_statistics { bt_mesh_electric_current_t average_electric_current_value; bt_mesh_electric_current_t standard_electric_current_value; bt_mesh_electric_current_t minimum_electric_current_value; @@ -1013,7 +1013,7 @@ typedef uint8_t bt_mesh_time_decihour_8_t; /* This characteristic aggregates the Energy characteristic, and two instances of * the Time Decihour 8 characteristic, to represent energy use in a period of day. */ -typedef struct __packed energy_in_a_period_of_day { +typedef struct __attribute__((packed)) energy_in_a_period_of_day { bt_mesh_energy_t energy_value; bt_mesh_time_decihour_8_t start_time; bt_mesh_time_decihour_8_t end_time; @@ -1031,7 +1031,7 @@ typedef uint16_t bt_mesh_time_second_16_t; * Time Decihour 8 characteristic and an instance of the Sensing Duration characteristic, * to represent statistical values of events. */ -typedef struct __packed event_statistics { +typedef struct __attribute__((packed)) event_statistics { bt_mesh_count_16_t number_of_events; bt_mesh_time_second_16_t average_event_duration; bt_mesh_time_exponential_8_t time_elapsed_since_last_event; @@ -1106,7 +1106,7 @@ typedef uint16_t bt_mesh_luminous_flux_t; /* This characteristic aggregates two instances of the Luminous Flux characteristic * to represent a luminous flux range. */ -typedef struct __packed luminous_flux_range { +typedef struct __attribute__((packed)) luminous_flux_range { bt_mesh_luminous_flux_t minimum_luminous_flux; bt_mesh_luminous_flux_t maximum_luminous_flux; } bt_mesh_luminous_flux_range_t; @@ -1178,7 +1178,7 @@ typedef uint8_t bt_mesh_power_t[3]; /* This characteristic aggregates three instances of the Power characteristic to * represent a specification of Power values. */ -typedef struct __packed power_specification { +typedef struct __attribute__((packed)) power_specification { bt_mesh_power_t minimum_power_value; bt_mesh_power_t typical_power_value; bt_mesh_power_t maximum_power_value; @@ -1188,7 +1188,7 @@ typedef struct __packed power_specification { * the Electric Current characteristic to represent a relative value in an electric * current range. */ -typedef struct __packed relative_runtime_in_a_current_range { +typedef struct __attribute__((packed)) relative_runtime_in_a_current_range { bt_mesh_percentage_8_t relative_runtime_value; bt_mesh_electric_current_t minimum_current; bt_mesh_electric_current_t maximum_current; @@ -1197,7 +1197,7 @@ typedef struct __packed relative_runtime_in_a_current_range { /* This characteristic aggregates the Percentage 8 characteristic and two instances of * the Generic Level characteristic to represent a runtime in a generic level range. */ -typedef struct __packed relative_runtime_in_a_generic_level_range { +typedef struct __attribute__((packed)) relative_runtime_in_a_generic_level_range { bt_mesh_percentage_8_t relative_value; bt_mesh_generic_level_t minimum_generic_level; bt_mesh_generic_level_t maximum_generic_level; @@ -1206,7 +1206,7 @@ typedef struct __packed relative_runtime_in_a_generic_level_range { /* This characteristic aggregates the Percentage 8 characteristic, and two instances of * the Time Decihour 8 characteristic. */ -typedef struct __packed relative_value_in_a_period_of_day { +typedef struct __attribute__((packed)) relative_value_in_a_period_of_day { bt_mesh_percentage_8_t relative_value; bt_mesh_time_decihour_8_t start_time; bt_mesh_time_decihour_8_t end_time; @@ -1215,7 +1215,7 @@ typedef struct __packed relative_value_in_a_period_of_day { /* This characteristic aggregates the Percentage 8 characteristic, and two instances of * the Temperature characteristic. */ -typedef struct __packed relative_value_in_a_temperature_range { +typedef struct __attribute__((packed)) relative_value_in_a_temperature_range { bt_mesh_percentage_8_t relative_value; bt_mesh_temperature_t minimum_temperature_value; bt_mesh_temperature_t maximum_temperature_value; @@ -1224,7 +1224,7 @@ typedef struct __packed relative_value_in_a_temperature_range { /* This characteristic aggregates the Percentage 8 characteristic and two instances of * the Voltage characteristic to represent a relative value in a voltage range. */ -typedef struct __packed relative_value_in_a_voltage_range { +typedef struct __attribute__((packed)) relative_value_in_a_voltage_range { bt_mesh_percentage_8_t relative_value; bt_mesh_voltage_t minimum_voltage; bt_mesh_voltage_t maximum_voltage; @@ -1233,7 +1233,7 @@ typedef struct __packed relative_value_in_a_voltage_range { /* This characteristic aggregates the Percentage 8 characteristic and two instances of * the Illuminance characteristic to represent a relative value in a illuminance range. */ -typedef struct __packed relative_value_in_an_illuminance_range { +typedef struct __attribute__((packed)) relative_value_in_an_illuminance_range { bt_mesh_percentage_8_t relative_value; bt_mesh_illuminance_t minimum_illuminance; bt_mesh_illuminance_t maximum_illuminance; @@ -1251,7 +1251,7 @@ typedef int8_t bt_mesh_temperature_8_t; * of the Time Decihour 8 characteristic, to represent a temperature value in a period * of day. */ -typedef struct __packed temperature_8_in_a_period_of_day { +typedef struct __attribute__((packed)) temperature_8_in_a_period_of_day { bt_mesh_temperature_8_t temperature; bt_mesh_time_decihour_8_t start_time; bt_mesh_time_decihour_8_t end_time; @@ -1260,7 +1260,7 @@ typedef struct __packed temperature_8_in_a_period_of_day { /* This characteristic aggregates four instances of the Temperature 8 characteristic, * and one instance of the Time Exponential 8 characteristic. */ -typedef struct __packed temperature_8_statistics { +typedef struct __attribute__((packed)) temperature_8_statistics { bt_mesh_temperature_8_t average; bt_mesh_temperature_8_t standard_deviation_value; bt_mesh_temperature_8_t minimum_value; @@ -1271,7 +1271,7 @@ typedef struct __packed temperature_8_statistics { /* This characteristic aggregates two instances of the Temperature characteristic to * represent a temperature range. */ -typedef struct __packed temperature_range { +typedef struct __attribute__((packed)) temperature_range { bt_mesh_temperature_t minimum_temperature; bt_mesh_temperature_t maximum_temperature; } bt_mesh_temperature_range_t; @@ -1279,7 +1279,7 @@ typedef struct __packed temperature_range { /* This characteristic aggregates four instances of the Temperature characteristic, * and one instance of the Time Exponential 8 characteristic. */ -typedef struct __packed temperature_statistics { +typedef struct __attribute__((packed)) temperature_statistics { bt_mesh_temperature_t average_temperature; bt_mesh_temperature_t standard_deviation_temperature; bt_mesh_temperature_t minimum_temperature; @@ -1313,7 +1313,7 @@ typedef uint8_t bt_mesh_time_second_8_t; /* This characteristic aggregates three instances of the Voltage characteristic to * represent a specification of voltage values. */ -typedef struct __packed voltage_specification { +typedef struct __attribute__((packed)) voltage_specification { bt_mesh_voltage_t minimum_voltage_value; bt_mesh_voltage_t typical_voltage_value; bt_mesh_voltage_t maximum_voltage_value; @@ -1323,7 +1323,7 @@ typedef struct __packed voltage_specification { * instance of the Time Exponential 8 characteristic to represent a set of statistical * voltage values over a period of time. */ -typedef struct __packed voltage_statistics { +typedef struct __attribute__((packed)) voltage_statistics { bt_mesh_voltage_t average_voltage_value; bt_mesh_voltage_t standard_deviation_voltage_value; bt_mesh_voltage_t minimum_voltage_value; diff --git a/components/bt/esp_ble_mesh/models/common/include/mesh/model_common.h b/components/bt/esp_ble_mesh/models/common/include/mesh/model_common.h new file mode 100644 index 0000000000..49712504a9 --- /dev/null +++ b/components/bt/esp_ble_mesh/models/common/include/mesh/model_common.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2018 Vikrant More + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MODEL_COMMON_H_ +#define _MODEL_COMMON_H_ + +#include "mesh/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +float bt_mesh_sqrt(float square); + +int32_t bt_mesh_ceil(float num); + +float bt_mesh_log2(float num); + +#ifdef __cplusplus +} +#endif + +#endif /* _MODEL_COMMON_H_ */ diff --git a/components/bt/esp_ble_mesh/models/common/include/mesh/model_opcode.h b/components/bt/esp_ble_mesh/models/common/include/mesh/model_opcode.h index 9ea4f7baf4..70f9716100 100644 --- a/components/bt/esp_ble_mesh/models/common/include/mesh/model_opcode.h +++ b/components/bt/esp_ble_mesh/models/common/include/mesh/model_opcode.h @@ -14,260 +14,273 @@ extern "C" { #endif /* Generic OnOff Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x01) -#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x02) -#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x03) -#define BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x04) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x01) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x02) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x03) +#define BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x04) /* Generic Level Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x05) -#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x06) -#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x07) -#define BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x08) -#define BLE_MESH_MODEL_OP_GEN_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x09) -#define BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0A) -#define BLE_MESH_MODEL_OP_GEN_MOVE_SET BLE_MESH_MODEL_OP_2(0x82, 0x0B) -#define BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0C) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x05) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x06) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x07) +#define BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x08) +#define BLE_MESH_MODEL_OP_GEN_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x09) +#define BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0A) +#define BLE_MESH_MODEL_OP_GEN_MOVE_SET BLE_MESH_MODEL_OP_2(0x82, 0x0B) +#define BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0C) /* Generic Default Transition Time Message Opcode*/ -#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x0D) -#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET BLE_MESH_MODEL_OP_2(0x82, 0x0E) -#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0F) -#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x10) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x0D) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET BLE_MESH_MODEL_OP_2(0x82, 0x0E) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x0F) +#define BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x10) /* Generic Power OnOff Message Opcode*/ -#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET BLE_MESH_MODEL_OP_2(0x82, 0x11) -#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x12) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET BLE_MESH_MODEL_OP_2(0x82, 0x11) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x12) /* Generic Power OnOff Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET BLE_MESH_MODEL_OP_2(0x82, 0x13) -#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x14) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET BLE_MESH_MODEL_OP_2(0x82, 0x13) +#define BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x14) /* Generic Power Level Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x15) -#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x16) -#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x17) -#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x18) -#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x19) -#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1A) -#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x1B) -#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1C) -#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x1D) -#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1E) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET BLE_MESH_MODEL_OP_2(0x82, 0x15) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET BLE_MESH_MODEL_OP_2(0x82, 0x16) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x17) +#define BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x18) +#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x19) +#define BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1A) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x1B) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1C) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x1D) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x1E) /* Generic Power Level Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x1F) -#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x20) -#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x21) -#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x22) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x1F) +#define BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x20) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x21) +#define BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x22) /* Generic Battery Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_BATTERY_GET BLE_MESH_MODEL_OP_2(0x82, 0x23) -#define BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x24) +#define BLE_MESH_MODEL_OP_GEN_BATTERY_GET BLE_MESH_MODEL_OP_2(0x82, 0x23) +#define BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x24) /* Generic Location Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x25) -#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS BLE_MESH_MODEL_OP_1(0x40) -#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x26) -#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x27) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x25) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS BLE_MESH_MODEL_OP_1(0x40) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET BLE_MESH_MODEL_OP_2(0x82, 0x26) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x27) /* Generic Location Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET BLE_MESH_MODEL_OP_1(0x41) -#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK BLE_MESH_MODEL_OP_1(0x42) -#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET BLE_MESH_MODEL_OP_2(0x82, 0x28) -#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x29) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET BLE_MESH_MODEL_OP_1(0x41) +#define BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK BLE_MESH_MODEL_OP_1(0x42) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET BLE_MESH_MODEL_OP_2(0x82, 0x28) +#define BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x29) /* Generic Manufacturer Property Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2A) -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x43) -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2B) -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x44) -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x45) -#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x46) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2A) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x43) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2B) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x44) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x45) +#define BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x46) /* Generic Admin Property Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2C) -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x47) -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2D) -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x48) -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x49) -#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4A) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2C) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x47) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2D) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x48) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x49) +#define BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4A) /* Generic User Property Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2E) -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x4B) -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2F) -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x4C) -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x4D) -#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4E) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x2E) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x4B) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x2F) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x4C) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x4D) +#define BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x4E) /* Generic Client Property Message Opcode */ -#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET BLE_MESH_MODEL_OP_1(0x4F) -#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x50) +#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET BLE_MESH_MODEL_OP_1(0x4F) +#define BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS BLE_MESH_MODEL_OP_1(0x50) /* Sensor Message Opcode */ -#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x30) -#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS BLE_MESH_MODEL_OP_1(0x51) -#define BLE_MESH_MODEL_OP_SENSOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x31) -#define BLE_MESH_MODEL_OP_SENSOR_STATUS BLE_MESH_MODEL_OP_1(0x52) -#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET BLE_MESH_MODEL_OP_2(0x82, 0x32) -#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS BLE_MESH_MODEL_OP_1(0x53) -#define BLE_MESH_MODEL_OP_SENSOR_SERIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x33) -#define BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS BLE_MESH_MODEL_OP_1(0x54) +#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x30) +#define BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS BLE_MESH_MODEL_OP_1(0x51) +#define BLE_MESH_MODEL_OP_SENSOR_GET BLE_MESH_MODEL_OP_2(0x82, 0x31) +#define BLE_MESH_MODEL_OP_SENSOR_STATUS BLE_MESH_MODEL_OP_1(0x52) +#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET BLE_MESH_MODEL_OP_2(0x82, 0x32) +#define BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS BLE_MESH_MODEL_OP_1(0x53) +#define BLE_MESH_MODEL_OP_SENSOR_SERIES_GET BLE_MESH_MODEL_OP_2(0x82, 0x33) +#define BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS BLE_MESH_MODEL_OP_1(0x54) /* Sensor Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET BLE_MESH_MODEL_OP_2(0x82, 0x34) -#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET BLE_MESH_MODEL_OP_1(0x55) -#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK BLE_MESH_MODEL_OP_1(0x56) -#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS BLE_MESH_MODEL_OP_1(0x57) -#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET BLE_MESH_MODEL_OP_2(0x82, 0x35) -#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS BLE_MESH_MODEL_OP_1(0x58) -#define BLE_MESH_MODEL_OP_SENSOR_SETTING_GET BLE_MESH_MODEL_OP_2(0x82, 0x36) -#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET BLE_MESH_MODEL_OP_1(0x59) -#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK BLE_MESH_MODEL_OP_1(0x5A) -#define BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS BLE_MESH_MODEL_OP_1(0x5B) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET BLE_MESH_MODEL_OP_2(0x82, 0x34) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET BLE_MESH_MODEL_OP_1(0x55) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK BLE_MESH_MODEL_OP_1(0x56) +#define BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS BLE_MESH_MODEL_OP_1(0x57) +#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET BLE_MESH_MODEL_OP_2(0x82, 0x35) +#define BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS BLE_MESH_MODEL_OP_1(0x58) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_GET BLE_MESH_MODEL_OP_2(0x82, 0x36) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET BLE_MESH_MODEL_OP_1(0x59) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK BLE_MESH_MODEL_OP_1(0x5A) +#define BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS BLE_MESH_MODEL_OP_1(0x5B) /* Time Message Opcode */ -#define BLE_MESH_MODEL_OP_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x37) -#define BLE_MESH_MODEL_OP_TIME_SET BLE_MESH_MODEL_OP_1(0x5C) -#define BLE_MESH_MODEL_OP_TIME_STATUS BLE_MESH_MODEL_OP_1(0x5D) -#define BLE_MESH_MODEL_OP_TIME_ROLE_GET BLE_MESH_MODEL_OP_2(0x82, 0x38) -#define BLE_MESH_MODEL_OP_TIME_ROLE_SET BLE_MESH_MODEL_OP_2(0x82, 0x39) -#define BLE_MESH_MODEL_OP_TIME_ROLE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3A) -#define BLE_MESH_MODEL_OP_TIME_ZONE_GET BLE_MESH_MODEL_OP_2(0x82, 0x3B) -#define BLE_MESH_MODEL_OP_TIME_ZONE_SET BLE_MESH_MODEL_OP_2(0x82, 0x3C) -#define BLE_MESH_MODEL_OP_TIME_ZONE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3D) -#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET BLE_MESH_MODEL_OP_2(0x82, 0x3E) -#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x3F) -#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x40) +#define BLE_MESH_MODEL_OP_TIME_GET BLE_MESH_MODEL_OP_2(0x82, 0x37) +#define BLE_MESH_MODEL_OP_TIME_SET BLE_MESH_MODEL_OP_1(0x5C) +#define BLE_MESH_MODEL_OP_TIME_STATUS BLE_MESH_MODEL_OP_1(0x5D) +#define BLE_MESH_MODEL_OP_TIME_ROLE_GET BLE_MESH_MODEL_OP_2(0x82, 0x38) +#define BLE_MESH_MODEL_OP_TIME_ROLE_SET BLE_MESH_MODEL_OP_2(0x82, 0x39) +#define BLE_MESH_MODEL_OP_TIME_ROLE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3A) +#define BLE_MESH_MODEL_OP_TIME_ZONE_GET BLE_MESH_MODEL_OP_2(0x82, 0x3B) +#define BLE_MESH_MODEL_OP_TIME_ZONE_SET BLE_MESH_MODEL_OP_2(0x82, 0x3C) +#define BLE_MESH_MODEL_OP_TIME_ZONE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x3D) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET BLE_MESH_MODEL_OP_2(0x82, 0x3E) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET BLE_MESH_MODEL_OP_2(0x82, 0x3F) +#define BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x40) /* Scene Message Opcode */ -#define BLE_MESH_MODEL_OP_SCENE_GET BLE_MESH_MODEL_OP_2(0x82, 0x41) -#define BLE_MESH_MODEL_OP_SCENE_RECALL BLE_MESH_MODEL_OP_2(0x82, 0x42) -#define BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x43) -#define BLE_MESH_MODEL_OP_SCENE_STATUS BLE_MESH_MODEL_OP_1(0x5E) -#define BLE_MESH_MODEL_OP_SCENE_REGISTER_GET BLE_MESH_MODEL_OP_2(0x82, 0x44) -#define BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x45) +#define BLE_MESH_MODEL_OP_SCENE_GET BLE_MESH_MODEL_OP_2(0x82, 0x41) +#define BLE_MESH_MODEL_OP_SCENE_RECALL BLE_MESH_MODEL_OP_2(0x82, 0x42) +#define BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x43) +#define BLE_MESH_MODEL_OP_SCENE_STATUS BLE_MESH_MODEL_OP_1(0x5E) +#define BLE_MESH_MODEL_OP_SCENE_REGISTER_GET BLE_MESH_MODEL_OP_2(0x82, 0x44) +#define BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x45) /* Scene Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_SCENE_STORE BLE_MESH_MODEL_OP_2(0x82, 0x46) -#define BLE_MESH_MODEL_OP_SCENE_STORE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x47) -#define BLE_MESH_MODEL_OP_SCENE_DELETE BLE_MESH_MODEL_OP_2(0x82, 0x9E) -#define BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9F) +#define BLE_MESH_MODEL_OP_SCENE_STORE BLE_MESH_MODEL_OP_2(0x82, 0x46) +#define BLE_MESH_MODEL_OP_SCENE_STORE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x47) +#define BLE_MESH_MODEL_OP_SCENE_DELETE BLE_MESH_MODEL_OP_2(0x82, 0x9E) +#define BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9F) /* Scheduler Message Opcode */ -#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET BLE_MESH_MODEL_OP_2(0x82, 0x48) -#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS BLE_MESH_MODEL_OP_1(0x5F) -#define BLE_MESH_MODEL_OP_SCHEDULER_GET BLE_MESH_MODEL_OP_2(0x82, 0x49) -#define BLE_MESH_MODEL_OP_SCHEDULER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4A) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET BLE_MESH_MODEL_OP_2(0x82, 0x48) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS BLE_MESH_MODEL_OP_1(0x5F) +#define BLE_MESH_MODEL_OP_SCHEDULER_GET BLE_MESH_MODEL_OP_2(0x82, 0x49) +#define BLE_MESH_MODEL_OP_SCHEDULER_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4A) /* Scheduler Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET BLE_MESH_MODEL_OP_1(0x60) -#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK BLE_MESH_MODEL_OP_1(0x61) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET BLE_MESH_MODEL_OP_1(0x60) +#define BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK BLE_MESH_MODEL_OP_1(0x61) /* Light Lightness Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET BLE_MESH_MODEL_OP_2(0x82, 0x4B) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET BLE_MESH_MODEL_OP_2(0x82, 0x4C) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x4D) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4E) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET BLE_MESH_MODEL_OP_2(0x82, 0x4F) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET BLE_MESH_MODEL_OP_2(0x82, 0x50) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x51) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x52) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x53) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x54) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x55) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x56) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x57) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x58) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET BLE_MESH_MODEL_OP_2(0x82, 0x4B) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET BLE_MESH_MODEL_OP_2(0x82, 0x4C) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x4D) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x4E) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET BLE_MESH_MODEL_OP_2(0x82, 0x4F) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET BLE_MESH_MODEL_OP_2(0x82, 0x50) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x51) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x52) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET BLE_MESH_MODEL_OP_2(0x82, 0x53) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x54) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x55) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x56) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x57) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x58) /* Light Lightness Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x59) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5A) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x5B) -#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5C) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x59) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5A) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x5B) +#define BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5C) /* Light CTL Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_CTL_GET BLE_MESH_MODEL_OP_2(0x82, 0x5D) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET BLE_MESH_MODEL_OP_2(0x82, 0x5E) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5F) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x60) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET BLE_MESH_MODEL_OP_2(0x82, 0x61) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x62) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x63) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET BLE_MESH_MODEL_OP_2(0x82, 0x64) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x65) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x66) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x67) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x68) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_GET BLE_MESH_MODEL_OP_2(0x82, 0x5D) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET BLE_MESH_MODEL_OP_2(0x82, 0x5E) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x5F) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x60) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET BLE_MESH_MODEL_OP_2(0x82, 0x61) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x62) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x63) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET BLE_MESH_MODEL_OP_2(0x82, 0x64) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x65) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x66) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x67) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x68) /* Light CTL Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x69) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6A) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6B) -#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6C) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x69) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6A) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6B) +#define BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x6C) /* Light HSL Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_HSL_GET BLE_MESH_MODEL_OP_2(0x82, 0x6D) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET BLE_MESH_MODEL_OP_2(0x82, 0x6E) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6F) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x70) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x71) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET BLE_MESH_MODEL_OP_2(0x82, 0x72) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET BLE_MESH_MODEL_OP_2(0x82, 0x73) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x74) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x75) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET BLE_MESH_MODEL_OP_2(0x82, 0x76) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x77) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x78) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x79) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7A) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x7B) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7C) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x7D) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7E) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_GET BLE_MESH_MODEL_OP_2(0x82, 0x6D) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET BLE_MESH_MODEL_OP_2(0x82, 0x6E) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET BLE_MESH_MODEL_OP_2(0x82, 0x6F) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x70) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x71) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET BLE_MESH_MODEL_OP_2(0x82, 0x72) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET BLE_MESH_MODEL_OP_2(0x82, 0x73) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x74) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x75) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET BLE_MESH_MODEL_OP_2(0x82, 0x76) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x77) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x78) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x79) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7A) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x7B) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7C) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x7D) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x7E) /* Light HSL Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x7F) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x80) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x81) -#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x82) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x7F) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x80) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x81) +#define BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x82) /* Light xyL Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_XYL_GET BLE_MESH_MODEL_OP_2(0x82, 0x83) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET BLE_MESH_MODEL_OP_2(0x82, 0x84) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x85) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x86) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x87) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x88) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x89) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8A) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x8B) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8C) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_GET BLE_MESH_MODEL_OP_2(0x82, 0x83) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET BLE_MESH_MODEL_OP_2(0x82, 0x84) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x85) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x86) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET BLE_MESH_MODEL_OP_2(0x82, 0x87) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x88) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET BLE_MESH_MODEL_OP_2(0x82, 0x89) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8A) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET BLE_MESH_MODEL_OP_2(0x82, 0x8B) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x8C) /* Light xyL Setup Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x8D) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x8E) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x8F) -#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x90) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET BLE_MESH_MODEL_OP_2(0x82, 0x8D) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x8E) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET BLE_MESH_MODEL_OP_2(0x82, 0x8F) +#define BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x90) /* Light Control Message Opcode */ -#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET BLE_MESH_MODEL_OP_2(0x82, 0x91) -#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET BLE_MESH_MODEL_OP_2(0x82, 0x92) -#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x93) -#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x94) -#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET BLE_MESH_MODEL_OP_2(0x82, 0x95) -#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET BLE_MESH_MODEL_OP_2(0x82, 0x96) -#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x97) -#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x98) -#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x99) -#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x9A) -#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9B) -#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x9C) -#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x9D) -#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x62) -#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x63) -#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x64) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET BLE_MESH_MODEL_OP_2(0x82, 0x91) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET BLE_MESH_MODEL_OP_2(0x82, 0x92) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x93) +#define BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x94) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET BLE_MESH_MODEL_OP_2(0x82, 0x95) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET BLE_MESH_MODEL_OP_2(0x82, 0x96) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x97) +#define BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x98) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET BLE_MESH_MODEL_OP_2(0x82, 0x99) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET BLE_MESH_MODEL_OP_2(0x82, 0x9A) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK BLE_MESH_MODEL_OP_2(0x82, 0x9B) +#define BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS BLE_MESH_MODEL_OP_2(0x82, 0x9C) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET BLE_MESH_MODEL_OP_2(0x82, 0x9D) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET BLE_MESH_MODEL_OP_1(0x62) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK BLE_MESH_MODEL_OP_1(0x63) +#define BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS BLE_MESH_MODEL_OP_1(0x64) + +/* Blob Transfer Message Opcode - TBD */ +#define BLE_MESH_BLOB_TRANSFER_GET BLE_MESH_MODEL_OP_2(0x83, 0x00) +#define BLE_MESH_BLOB_TRANSFER_START BLE_MESH_MODEL_OP_2(0x83, 0x01) +#define BLE_MESH_BLOB_TRANSFER_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x02) +#define BLE_MESH_BLOB_TRANSFER_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x03) +#define BLE_MESH_BLOB_BLOCK_GET BLE_MESH_MODEL_OP_2(0x83, 0x05) +#define BLE_MESH_BLOB_BLOCK_START BLE_MESH_MODEL_OP_2(0x83, 0x04) +#define BLE_MESH_BLOB_PARTIAL_BLOCK_REPORT BLE_MESH_MODEL_OP_1(0x65) +#define BLE_MESH_BLOB_BLOCK_STATUS BLE_MESH_MODEL_OP_1(0x67) +#define BLE_MESH_BLOB_CHUNK_TRANSFER BLE_MESH_MODEL_OP_1(0x66) +#define BLE_MESH_BLOB_INFORMATION_GET BLE_MESH_MODEL_OP_2(0x83, 0x06) +#define BLE_MESH_BLOB_INFORMATION_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x07) #ifdef __cplusplus } diff --git a/components/bt/esp_ble_mesh/models/common/model_common.c b/components/bt/esp_ble_mesh/models/common/model_common.c new file mode 100644 index 0000000000..eb54ee1501 --- /dev/null +++ b/components/bt/esp_ble_mesh/models/common/model_common.c @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2018 Vikrant More + * SPDX-FileContributor: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "mesh/types.h" + +#define MINDIFF (2.25e-308) + +float bt_mesh_sqrt(float square) +{ + float root = 0.0, last = 0.0, diff = 0.0; + + root = square / 3.0; + diff = 1; + + if (square <= 0) { + return 0; + } + + do { + last = root; + root = (root + square / root) / 2.0; + diff = root - last; + } while (diff > MINDIFF || diff < -MINDIFF); + + return root; +} + +int32_t bt_mesh_ceil(float num) +{ + int32_t inum = (int32_t)num; + + if (num == (float)inum) { + return inum; + } + + return inum + 1; +} + +float bt_mesh_log2(float num) +{ + return log2f(num); +} diff --git a/components/bt/esp_ble_mesh/models/server/generic_server.c b/components/bt/esp_ble_mesh/models/server/generic_server.c index a10e467b28..747d78b25f 100644 --- a/components/bt/esp_ble_mesh/models/server/generic_server.c +++ b/components/bt/esp_ble_mesh/models/server/generic_server.c @@ -21,20 +21,6 @@ static bt_mesh_mutex_t generic_server_lock; -static inline void bt_mesh_generic_server_mutex_new(void) -{ - if (!generic_server_lock.mutex) { - bt_mesh_mutex_create(&generic_server_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_generic_server_mutex_free(void) -{ - bt_mesh_mutex_free(&generic_server_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - void bt_mesh_generic_server_lock(void) { bt_mesh_mutex_lock(&generic_server_lock); @@ -88,7 +74,6 @@ static void send_gen_onoff_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_onoff_get(struct bt_mesh_model *model, @@ -104,13 +89,12 @@ static void gen_onoff_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } send_gen_onoff_status(model, ctx, false); - return; } void gen_onoff_publish(struct bt_mesh_model *model) @@ -121,7 +105,6 @@ void gen_onoff_publish(struct bt_mesh_model *model) } send_gen_onoff_status(model, NULL, true); - return; } static void gen_onoff_set(struct bt_mesh_model *model, @@ -158,8 +141,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, .onoff_set.trans_time = trans_time, .onoff_set.delay = delay, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -185,8 +168,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_onoff_set.onoff = srv->state.onoff, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { send_gen_onoff_status(model, ctx, false); @@ -198,8 +181,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -216,7 +199,6 @@ static void gen_onoff_set(struct bt_mesh_model *model, bt_mesh_generic_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } /* Generic Level Server message handlers */ @@ -269,7 +251,6 @@ static void send_gen_level_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_level_get(struct bt_mesh_model *model, @@ -285,13 +266,12 @@ static void gen_level_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } send_gen_level_status(model, ctx, false); - return; } void gen_level_publish(struct bt_mesh_model *model) @@ -302,7 +282,6 @@ void gen_level_publish(struct bt_mesh_model *model) } send_gen_level_status(model, NULL, true); - return; } static void gen_level_set(struct bt_mesh_model *model, @@ -336,8 +315,8 @@ static void gen_level_set(struct bt_mesh_model *model, .level_set.trans_time = trans_time, .level_set.delay = delay, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -367,8 +346,8 @@ static void gen_level_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_level_set.level = srv->state.level, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) { send_gen_level_status(model, ctx, false); @@ -380,8 +359,8 @@ static void gen_level_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -398,7 +377,6 @@ static void gen_level_set(struct bt_mesh_model *model, bt_mesh_generic_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void gen_delta_set(struct bt_mesh_model *model, @@ -432,8 +410,8 @@ static void gen_delta_set(struct bt_mesh_model *model, .delta_set.trans_time = trans_time, .delta_set.delay = delay, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -488,8 +466,8 @@ static void gen_delta_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_delta_set.level = srv->state.level, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) { send_gen_level_status(model, ctx, false); @@ -501,8 +479,8 @@ static void gen_delta_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -519,7 +497,6 @@ static void gen_delta_set(struct bt_mesh_model *model, bt_mesh_generic_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void gen_move_set(struct bt_mesh_model *model, @@ -554,8 +531,8 @@ static void gen_move_set(struct bt_mesh_model *model, .move_set.trans_time = trans_time, .move_set.delay = delay, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -593,8 +570,8 @@ static void gen_move_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_move_set.level = srv->state.level, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) { send_gen_level_status(model, ctx, false); @@ -607,8 +584,8 @@ static void gen_move_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } if (delta) { @@ -639,13 +616,12 @@ static void gen_move_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_move_set.level = srv->state.level, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); return; } bt_mesh_server_start_transition(&srv->transition); - return; } /* Generic Default Transition Time Server message handlers */ @@ -684,7 +660,6 @@ static void send_gen_def_trans_time_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_def_trans_time_get(struct bt_mesh_model *model, @@ -700,13 +675,12 @@ static void gen_def_trans_time_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } send_gen_def_trans_time_status(model, ctx, false); - return; } static void gen_def_trans_time_set(struct bt_mesh_model *model, @@ -732,8 +706,8 @@ static void gen_def_trans_time_set(struct bt_mesh_model *model, bt_mesh_gen_server_recv_set_msg_t set = { .def_trans_time_set.trans_time = trans_time, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -744,15 +718,13 @@ static void gen_def_trans_time_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_def_trans_time_set.trans_time = trans_time, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET) { send_gen_def_trans_time_status(model, ctx, false); } send_gen_def_trans_time_status(model, NULL, true); - - return; } /* Generic Power OnOff Server message handlers */ @@ -807,7 +779,6 @@ static void send_gen_onpowerup_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_onpowerup_get(struct bt_mesh_model *model, @@ -823,13 +794,12 @@ static void gen_onpowerup_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } send_gen_onpowerup_status(model, ctx, false); - return; } /* Generic Power OnOff Setup Server message handlers */ @@ -863,7 +833,6 @@ void gen_onpowerup_publish(struct bt_mesh_model *model) } send_gen_onpowerup_status(model, NULL, true); - return; } static void gen_onpowerup_set(struct bt_mesh_model *model, @@ -889,8 +858,8 @@ static void gen_onpowerup_set(struct bt_mesh_model *model, bt_mesh_gen_server_recv_set_msg_t set = { .onpowerup_set.onpowerup = onpowerup, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -901,15 +870,13 @@ static void gen_onpowerup_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_onpowerup_set.onpowerup = onpowerup, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET) { send_gen_onpowerup_status(model, ctx, false); } send_gen_onpowerup_status(model, NULL, true); - - return; } /* Generic Power Level Server message handlers */ @@ -991,7 +958,6 @@ static void send_gen_power_level_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_power_level_get(struct bt_mesh_model *model, @@ -1008,8 +974,8 @@ static void gen_power_level_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1032,7 +998,6 @@ static void gen_power_level_get(struct bt_mesh_model *model, } send_gen_power_level_status(model, ctx, false, opcode); - return; } void gen_power_level_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -1065,7 +1030,6 @@ void gen_power_level_publish(struct bt_mesh_model *model, uint16_t opcode) } send_gen_power_level_status(model, NULL, true, opcode); - return; } static void gen_power_level_set(struct bt_mesh_model *model, @@ -1099,8 +1063,8 @@ static void gen_power_level_set(struct bt_mesh_model *model, .power_level_set.trans_time = trans_time, .power_level_set.delay = delay, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1136,8 +1100,8 @@ static void gen_power_level_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_power_level_set.power = srv->state->power_actual, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) { send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS); @@ -1149,8 +1113,8 @@ static void gen_power_level_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -1175,7 +1139,6 @@ static void gen_power_level_set(struct bt_mesh_model *model, bt_mesh_generic_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } /* Generic Power Level Setup Server message handlers */ @@ -1198,8 +1161,8 @@ static void gen_power_default_set(struct bt_mesh_model *model, bt_mesh_gen_server_recv_set_msg_t set = { .power_default_set.power = power, /* Just callback the actual received value */ }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1218,15 +1181,13 @@ static void gen_power_default_set(struct bt_mesh_model *model, bt_mesh_gen_server_state_change_t change = { .gen_power_default_set.power = power, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET) { send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS); } send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS); - - return; } static void gen_power_range_set(struct bt_mesh_model *model, @@ -1256,8 +1217,8 @@ static void gen_power_range_set(struct bt_mesh_model *model, .power_range_set.range_min = range_min, .power_range_set.range_max = range_max, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1281,15 +1242,13 @@ static void gen_power_range_set(struct bt_mesh_model *model, .gen_power_range_set.range_min = srv->state->power_range_min, .gen_power_range_set.range_max = srv->state->power_range_max, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET) { send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS); } send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS); - - return; } /* Generic Battery Server message handlers */ @@ -1307,8 +1266,8 @@ static void gen_battery_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1317,7 +1276,6 @@ static void gen_battery_get(struct bt_mesh_model *model, net_buf_simple_add_le32(&msg, srv->state.battery_flags << 24 | srv->state.time_to_charge); BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL)); - return; } /* Generic Location Server message handlers */ @@ -1392,7 +1350,6 @@ static void send_gen_location_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_location_get(struct bt_mesh_model *model, @@ -1409,8 +1366,8 @@ static void gen_location_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1427,7 +1384,6 @@ static void gen_location_get(struct bt_mesh_model *model, } send_gen_location_status(model, ctx, false, opcode); - return; } /* Generic Location Setup Server message handlers */ @@ -1458,8 +1414,8 @@ static void gen_location_set(struct bt_mesh_model *model, .loc_global_set.longitude = longitude, .loc_global_set.altitude = altitude, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1478,8 +1434,8 @@ static void gen_location_set(struct bt_mesh_model *model, .gen_loc_global_set.longitude = srv->state->global_longitude, .gen_loc_global_set.altitude = srv->state->global_altitude, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); break; } case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: @@ -1500,8 +1456,8 @@ static void gen_location_set(struct bt_mesh_model *model, .loc_local_set.floor_number = floor, .loc_local_set.uncertainty = uncertainty, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1526,8 +1482,8 @@ static void gen_location_set(struct bt_mesh_model *model, .gen_loc_local_set.floor_number = srv->state->floor_number, .gen_loc_local_set.uncertainty = srv->state->uncertainty, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); break; } default: @@ -1540,8 +1496,6 @@ static void gen_location_set(struct bt_mesh_model *model, send_gen_location_status(model, ctx, false, opcode); } send_gen_location_status(model, NULL, true, opcode); - - return; } /* Generic User Property Server message handlers */ @@ -1617,7 +1571,6 @@ static void send_gen_user_prop_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_user_prop_get(struct bt_mesh_model *model, @@ -1634,7 +1587,7 @@ static void gen_user_prop_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { /** - * Also we can use __packed for esp_ble_mesh_gen_user_property_get_t, + * Also we can use __attribute__((packed)) for esp_ble_mesh_gen_user_property_get_t, * and directly callback with buf->data & buf->len. */ bt_mesh_gen_server_recv_get_msg_t get = {0}; @@ -1645,8 +1598,8 @@ static void gen_user_prop_get(struct bt_mesh_model *model, param = (const uint8_t *)&get; len = sizeof(get); } - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, param, len); return; } @@ -1662,7 +1615,7 @@ static void gen_user_prop_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS); for (i = 0U; i < srv->property_count; i++) { if (srv->properties[i].admin_access != ADMIN_NOT_USER_PROP && - srv->properties[i].manu_access != MANU_NOT_USER_PROP) { + srv->properties[i].manu_access != MANU_NOT_USER_PROP) { net_buf_simple_add_le16(msg, srv->properties[i].id); } } @@ -1703,14 +1656,14 @@ static void gen_user_prop_set(struct bt_mesh_model *model, .user_property_set.id = property_id, .user_property_set.value = buf, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } property = gen_get_user_property(model, property_id); if (property == NULL || property->user_access == USER_ACCESS_PROHIBIT || - property->user_access == USER_ACCESS_READ) { + property->user_access == USER_ACCESS_READ) { if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) { send_gen_user_prop_status(model, ctx, property_id, false); } @@ -1737,15 +1690,13 @@ static void gen_user_prop_set(struct bt_mesh_model *model, .gen_user_prop_set.id = property_id, .gen_user_prop_set.value = property->val, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) { send_gen_user_prop_status(model, ctx, property_id, false); } send_gen_user_prop_status(model, ctx, property_id, true); - - return; } /* Generic Admin Property Server message handlers */ @@ -1816,7 +1767,6 @@ static void send_gen_admin_prop_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_admin_prop_get(struct bt_mesh_model *model, @@ -1840,8 +1790,8 @@ static void gen_admin_prop_get(struct bt_mesh_model *model, param = (const uint8_t *)&get; len = sizeof(get); } - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, param, len); return; } @@ -1901,8 +1851,8 @@ static void gen_admin_prop_set(struct bt_mesh_model *model, .admin_property_set.access = access, .admin_property_set.value = buf, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1925,15 +1875,13 @@ static void gen_admin_prop_set(struct bt_mesh_model *model, .gen_admin_prop_set.access = property->admin_access, .gen_admin_prop_set.value = property->val, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET) { send_gen_admin_prop_status(model, ctx, property_id, false); } send_gen_admin_prop_status(model, ctx, property_id, true); - - return; } /* Generic Manufacturer Property Server message handlers */ @@ -2001,7 +1949,6 @@ static void send_gen_manu_prop_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void gen_manu_prop_get(struct bt_mesh_model *model, @@ -2025,8 +1972,8 @@ static void gen_manu_prop_get(struct bt_mesh_model *model, param = (const uint8_t *)&get; len = sizeof(get); } - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, param, len); return; } @@ -2085,8 +2032,8 @@ static void gen_manu_prop_set(struct bt_mesh_model *model, .manu_property_set.id = property_id, .manu_property_set.access = access, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2105,15 +2052,13 @@ static void gen_manu_prop_set(struct bt_mesh_model *model, .gen_manu_prop_set.id = property_id, .gen_manu_prop_set.access = property->manu_access, }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET) { send_gen_manu_prop_status(model, ctx, property_id, false); } send_gen_manu_prop_status(model, ctx, property_id, true); - - return; } /* Generic Client Property Server message handlers */ @@ -2130,9 +2075,9 @@ static int search_prop_id_index(const uint16_t *array, uint8_t array_idx, uint16 if (array_idx == 0U) { if (*array >= id) { return array - start; - } else { - return -1; } + + return -1; } index = array_idx / 2; @@ -2140,11 +2085,13 @@ static int search_prop_id_index(const uint16_t *array, uint8_t array_idx, uint16 if (temp == id) { return array + index - start; - } else if (temp > id) { - return search_prop_id_index(array, index, id); - } else { - return search_prop_id_index(array + index + 1, array_idx - 1 - index, id); } + + if (temp > id) { + return search_prop_id_index(array, index, id); + } + + return search_prop_id_index(array + index + 1, array_idx - 1 - index, id); } static void gen_client_prop_get(struct bt_mesh_model *model, @@ -2167,14 +2114,14 @@ static void gen_client_prop_get(struct bt_mesh_model *model, bt_mesh_gen_server_recv_get_msg_t get = { .client_properties_get.id = net_buf_simple_pull_le16(buf), }; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); return; } /* The sequence shall be in an ascending order of Property ID values and shall * start with a smallest Property ID that is greater than or equal to the value - * of the Generic Client Property field of the Generic Client Properities Get + * of the Generic Client Property field of the Generic Client Properties Get * message that it is responding to. */ @@ -2205,8 +2152,8 @@ static void gen_client_prop_get(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, sdu, NULL, NULL)); + bt_mesh_free_buf(sdu); - return; } /* message handlers (End) */ @@ -2332,9 +2279,11 @@ static inline int property_id_compare(const void *p1, const void *p2) if (*(uint16_t *)p1 < * (uint16_t *)p2) { return -1; } + if (*(uint16_t *)p1 > *(uint16_t *)p2) { return 1; } + return 0; } @@ -2475,7 +2424,7 @@ static int generic_server_init(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_generic_server_mutex_new(); + bt_mesh_mutex_create(&generic_server_lock); return 0; } @@ -2683,7 +2632,7 @@ static int generic_server_deinit(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_generic_server_mutex_free(); + bt_mesh_mutex_free(&generic_server_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/server/include/mesh/sensor_server.h b/components/bt/esp_ble_mesh/models/server/include/mesh/sensor_server.h index 797b45d717..a9fe77eff3 100644 --- a/components/bt/esp_ble_mesh/models/server/include/mesh/sensor_server.h +++ b/components/bt/esp_ble_mesh/models/server/include/mesh/sensor_server.h @@ -158,7 +158,7 @@ struct bt_mesh_sensor_state { /* 1. Multiple instances of the Sensor states may be present within the * same model, provided that each instance has a unique value of the * Sensor Property ID to allow the instances to be differentiated. - * 2. Note: The number of sensors within a multisensor is limited by the + * 2. Note: The number of sensors within a multi-sensor is limited by the * size of the message payload for the Sensor Descriptor Status message. * A single Sensor Descriptor may be sent using a single Unsegmented * Access message. Using Segmentation and Reassembly (SAR), up to 38 diff --git a/components/bt/esp_ble_mesh/models/server/include/mesh/time_scene_server.h b/components/bt/esp_ble_mesh/models/server/include/mesh/time_scene_server.h index a351dd4fef..7f23cdde0c 100644 --- a/components/bt/esp_ble_mesh/models/server/include/mesh/time_scene_server.h +++ b/components/bt/esp_ble_mesh/models/server/include/mesh/time_scene_server.h @@ -63,7 +63,7 @@ extern "C" { #define TIME_NONE 0x00 #define TIME_AUTHORITY 0x01 #define TIME_RELAY 0x02 -#define TIME_CLINET 0x03 +#define TIME_CLIENT 0x03 #define SCENE_SUCCESS 0x00 #define SCENE_REG_FULL 0x01 diff --git a/components/bt/esp_ble_mesh/models/server/lighting_server.c b/components/bt/esp_ble_mesh/models/server/lighting_server.c index 5717755116..6df51458a4 100644 --- a/components/bt/esp_ble_mesh/models/server/lighting_server.c +++ b/components/bt/esp_ble_mesh/models/server/lighting_server.c @@ -21,20 +21,6 @@ static bt_mesh_mutex_t light_server_lock; -static inline void bt_mesh_light_server_mutex_new(void) -{ - if (!light_server_lock.mutex) { - bt_mesh_mutex_create(&light_server_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_light_server_mutex_free(void) -{ - bt_mesh_mutex_free(&light_server_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - void bt_mesh_light_server_lock(void) { bt_mesh_mutex_lock(&light_server_lock); @@ -137,7 +123,6 @@ static void send_light_lightness_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_lightness_get(struct bt_mesh_model *model, @@ -154,8 +139,8 @@ static void light_lightness_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -181,7 +166,6 @@ static void light_lightness_get(struct bt_mesh_model *model, } send_light_lightness_status(model, ctx, false, opcode); - return; } void light_lightness_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -214,7 +198,6 @@ void light_lightness_publish(struct bt_mesh_model *model, uint16_t opcode) } send_light_lightness_status(model, NULL, true, opcode); - return; } static void light_lightness_set(struct bt_mesh_model *model, @@ -248,8 +231,8 @@ static void light_lightness_set(struct bt_mesh_model *model, .lightness_set.trans_time = trans_time, .lightness_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -286,8 +269,8 @@ static void light_lightness_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lightness_set.lightness = srv->state->lightness_actual, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET) { send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS); @@ -299,8 +282,8 @@ static void light_lightness_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->actual_transition.timer.work._reserved) { - memcpy(srv->actual_transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->actual_transition.timer.work.user_data) { + memcpy(srv->actual_transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -326,7 +309,6 @@ static void light_lightness_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->actual_transition); - return; } static void light_lightness_linear_set(struct bt_mesh_model *model, @@ -360,8 +342,8 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, .lightness_linear_set.trans_time = trans_time, .lightness_linear_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -391,8 +373,8 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lightness_linear_set.lightness = srv->state->lightness_actual, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET) { send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS); @@ -404,8 +386,8 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->linear_transition.timer.work._reserved) { - memcpy(srv->linear_transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->linear_transition.timer.work.user_data) { + memcpy(srv->linear_transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -422,7 +404,6 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->linear_transition); - return; } static void light_lightness_default_set(struct bt_mesh_model *model, @@ -444,8 +425,8 @@ static void light_lightness_default_set(struct bt_mesh_model *model, bt_mesh_light_server_recv_set_msg_t set = { .lightness_default_set.lightness = lightness, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -455,16 +436,14 @@ static void light_lightness_default_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lightness_default_set.lightness = lightness, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET) { send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS); } send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS); - - return; } static void light_lightness_range_set(struct bt_mesh_model *model, @@ -494,8 +473,8 @@ static void light_lightness_range_set(struct bt_mesh_model *model, .lightness_range_set.range_min = range_min, .lightness_range_set.range_max = range_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -533,15 +512,13 @@ static void light_lightness_range_set(struct bt_mesh_model *model, .lightness_range_set.range_min = srv->state->lightness_range_min, .lightness_range_set.range_max = srv->state->lightness_range_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET) { send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS); } send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS); - - return; } /* Light CTL Server/Temperature Server/Setup Server message handlers */ @@ -638,7 +615,6 @@ static void send_light_ctl_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_ctl_get(struct bt_mesh_model *model, @@ -679,8 +655,8 @@ static void light_ctl_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -703,7 +679,6 @@ static void light_ctl_get(struct bt_mesh_model *model, } send_light_ctl_status(model, ctx, false, opcode); - return; } void light_ctl_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -744,7 +719,6 @@ void light_ctl_publish(struct bt_mesh_model *model, uint16_t opcode) } send_light_ctl_status(model, NULL, true, opcode); - return; } static void light_ctl_set(struct bt_mesh_model *model, @@ -788,8 +762,8 @@ static void light_ctl_set(struct bt_mesh_model *model, .ctl_set.trans_time = trans_time, .ctl_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -809,8 +783,8 @@ static void light_ctl_set(struct bt_mesh_model *model, srv->state->target_lightness = lightness; if (srv->state->temperature_range_min && - srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && - temperature < srv->state->temperature_range_min) { + srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && + temperature < srv->state->temperature_range_min) { temperature = srv->state->temperature_range_min; } else if (srv->state->temperature_range_max && srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN && @@ -821,8 +795,8 @@ static void light_ctl_set(struct bt_mesh_model *model, srv->state->target_delta_uv = delta_uv; if (srv->state->target_lightness != srv->state->lightness || - srv->state->target_temperature != srv->state->temperature || - srv->state->target_delta_uv != srv->state->delta_uv) { + srv->state->target_temperature != srv->state->temperature || + srv->state->target_delta_uv != srv->state->delta_uv) { light_ctl_tt_values(srv, trans_time, delay); } else { bt_mesh_light_server_state_change_t change = { @@ -830,8 +804,8 @@ static void light_ctl_set(struct bt_mesh_model *model, .ctl_set.temperature = srv->state->temperature, .ctl_set.delta_uv = srv->state->delta_uv, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_SET) { send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS); @@ -843,8 +817,8 @@ static void light_ctl_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -863,7 +837,6 @@ static void light_ctl_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void light_ctl_default_set(struct bt_mesh_model *model, @@ -895,14 +868,14 @@ static void light_ctl_default_set(struct bt_mesh_model *model, .ctl_default_set.temperature = temperature, .ctl_default_set.delta_uv = delta_uv, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } if (srv->state->temperature_range_min && - srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && - temperature < srv->state->temperature_range_min) { + srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && + temperature < srv->state->temperature_range_min) { temperature = srv->state->temperature_range_min; } else if (srv->state->temperature_range_max && srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN && @@ -919,15 +892,13 @@ static void light_ctl_default_set(struct bt_mesh_model *model, .ctl_default_set.temperature = srv->state->temperature_default, .ctl_default_set.delta_uv = srv->state->delta_uv_default, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET) { send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS); } send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS); - - return; } static void light_ctl_temp_range_set(struct bt_mesh_model *model, @@ -960,8 +931,8 @@ static void light_ctl_temp_range_set(struct bt_mesh_model *model, .ctl_temp_range_set.range_min = min, .ctl_temp_range_set.range_max = max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -985,15 +956,13 @@ static void light_ctl_temp_range_set(struct bt_mesh_model *model, .ctl_temp_range_set.range_min = srv->state->temperature_range_min, .ctl_temp_range_set.range_max = srv->state->temperature_range_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET) { send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS); } send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS); - - return; } static void light_ctl_temp_set(struct bt_mesh_model *model, @@ -1035,8 +1004,8 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, .ctl_temp_set.trans_time = trans_time, .ctl_temp_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1055,8 +1024,8 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now); if (srv->state->temperature_range_min && - srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && - temperature < srv->state->temperature_range_min) { + srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN && + temperature < srv->state->temperature_range_min) { temperature = srv->state->temperature_range_min; } else if (srv->state->temperature_range_max && srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN && @@ -1074,8 +1043,8 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, .ctl_temp_set.temperature = srv->state->temperature, .ctl_temp_set.delta_uv = srv->state->delta_uv, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET) { send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS); @@ -1087,8 +1056,8 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -1106,7 +1075,6 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } /* Light HSL Server/Hue Server/Saturation Server/Setup Server message handlers */ @@ -1224,7 +1192,6 @@ static void send_light_hsl_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_hsl_get(struct bt_mesh_model *model, @@ -1274,8 +1241,8 @@ static void light_hsl_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1304,7 +1271,6 @@ static void light_hsl_get(struct bt_mesh_model *model, } send_light_hsl_status(model, ctx, false, opcode); - return; } void light_hsl_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -1353,7 +1319,6 @@ void light_hsl_publish(struct bt_mesh_model *model, uint16_t opcode) } send_light_hsl_status(model, NULL, true, opcode); - return; } static void light_hsl_set(struct bt_mesh_model *model, @@ -1391,8 +1356,8 @@ static void light_hsl_set(struct bt_mesh_model *model, .hsl_set.trans_time = trans_time, .hsl_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1438,8 +1403,8 @@ static void light_hsl_set(struct bt_mesh_model *model, .hsl_set.hue = srv->state->hue, .hsl_set.saturation = srv->state->saturation, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SET) { send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS); @@ -1451,8 +1416,8 @@ static void light_hsl_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -1471,7 +1436,6 @@ static void light_hsl_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void light_hsl_default_set(struct bt_mesh_model *model, @@ -1497,8 +1461,8 @@ static void light_hsl_default_set(struct bt_mesh_model *model, .hsl_default_set.hue = hue, .hsl_default_set.saturation = saturation, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1523,15 +1487,13 @@ static void light_hsl_default_set(struct bt_mesh_model *model, .hsl_default_set.hue = srv->state->hue_default, .hsl_default_set.saturation = srv->state->saturation_default, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET) { send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS); } send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS); - - return; } static void light_hsl_range_set(struct bt_mesh_model *model, @@ -1571,8 +1533,8 @@ static void light_hsl_range_set(struct bt_mesh_model *model, .hsl_range_set.sat_range_min = saturation_min, .hsl_range_set.sat_range_max = saturation_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1588,15 +1550,13 @@ static void light_hsl_range_set(struct bt_mesh_model *model, .hsl_range_set.sat_range_min = srv->state->saturation_range_min, .hsl_range_set.sat_range_max = srv->state->saturation_range_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET) { send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS); } send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS); - - return; } static void light_hsl_hue_set(struct bt_mesh_model *model, @@ -1630,8 +1590,8 @@ static void light_hsl_hue_set(struct bt_mesh_model *model, .hsl_hue_set.trans_time = trans_time, .hsl_hue_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1666,8 +1626,8 @@ static void light_hsl_hue_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .hsl_hue_set.hue = srv->state->hue, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET) { send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS); @@ -1679,8 +1639,8 @@ static void light_hsl_hue_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -1697,7 +1657,6 @@ static void light_hsl_hue_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void light_hsl_sat_set(struct bt_mesh_model *model, @@ -1731,8 +1690,8 @@ static void light_hsl_sat_set(struct bt_mesh_model *model, .hsl_saturation_set.trans_time = trans_time, .hsl_saturation_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1767,8 +1726,8 @@ static void light_hsl_sat_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .hsl_saturation_set.saturation = srv->state->saturation, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET) { send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS); @@ -1780,8 +1739,8 @@ static void light_hsl_sat_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -1798,7 +1757,6 @@ static void light_hsl_sat_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } /* Light xyL Server/Setup Server message handlers */ @@ -1896,7 +1854,6 @@ static void send_light_xyl_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_xyl_get(struct bt_mesh_model *model, @@ -1913,8 +1870,8 @@ static void light_xyl_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1937,7 +1894,6 @@ static void light_xyl_get(struct bt_mesh_model *model, } send_light_xyl_status(model, ctx, false, opcode); - return; } void light_xyl_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -1970,7 +1926,6 @@ void light_xyl_publish(struct bt_mesh_model *model, uint16_t opcode) } send_light_xyl_status(model, NULL, true, opcode); - return; } static void light_xyl_set(struct bt_mesh_model *model, @@ -2008,8 +1963,8 @@ static void light_xyl_set(struct bt_mesh_model *model, .xyl_set.trans_time = trans_time, .xyl_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2046,8 +2001,8 @@ static void light_xyl_set(struct bt_mesh_model *model, * be started and is considered complete. */ if (srv->state->target_lightness != srv->state->lightness || - srv->state->target_x != srv->state->x || - srv->state->target_y != srv->state->y) { + srv->state->target_x != srv->state->x || + srv->state->target_y != srv->state->y) { light_xyl_tt_values(srv, trans_time, delay); } else { bt_mesh_light_server_state_change_t change = { @@ -2055,8 +2010,8 @@ static void light_xyl_set(struct bt_mesh_model *model, .xyl_set.x = srv->state->x, .xyl_set.y = srv->state->y, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_SET) { send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS); @@ -2068,8 +2023,8 @@ static void light_xyl_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -2088,7 +2043,6 @@ static void light_xyl_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void light_xyl_default_set(struct bt_mesh_model *model, @@ -2114,8 +2068,8 @@ static void light_xyl_default_set(struct bt_mesh_model *model, .xyl_default_set.x = x, .xyl_default_set.y = y, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2140,15 +2094,13 @@ static void light_xyl_default_set(struct bt_mesh_model *model, .xyl_default_set.x = srv->state->x_default, .xyl_default_set.y = srv->state->y_default, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET) { send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS); } send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS); - - return; } static void light_xyl_range_set(struct bt_mesh_model *model, @@ -2188,8 +2140,8 @@ static void light_xyl_range_set(struct bt_mesh_model *model, .xyl_range_set.y_range_min = y_min, .xyl_range_set.y_range_max = y_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2205,15 +2157,13 @@ static void light_xyl_range_set(struct bt_mesh_model *model, .xyl_range_set.y_range_min = srv->state->y_range_min, .xyl_range_set.y_range_max = srv->state->y_range_max, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET) { send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS); } send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS); - - return; } /* Light LC Server/Setup Server message handlers */ @@ -2273,7 +2223,6 @@ static void send_light_lc_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_lc_get(struct bt_mesh_model *model, @@ -2290,8 +2239,8 @@ static void light_lc_get(struct bt_mesh_model *model, /* Callback the received message to the application layer */ if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -2311,7 +2260,6 @@ static void light_lc_get(struct bt_mesh_model *model, } send_light_lc_status(model, ctx, false, opcode); - return; } void light_lc_publish(struct bt_mesh_model *model, uint16_t opcode) @@ -2324,7 +2272,6 @@ void light_lc_publish(struct bt_mesh_model *model, uint16_t opcode) } send_light_lc_status(model, NULL, true, opcode); - return; } static void light_lc_mode_set(struct bt_mesh_model *model, @@ -2350,8 +2297,8 @@ static void light_lc_mode_set(struct bt_mesh_model *model, bt_mesh_light_server_recv_set_msg_t set = { .lc_mode_set.mode = mode, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2360,15 +2307,13 @@ static void light_lc_mode_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lc_mode_set.mode = srv->lc->state.mode, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET) { send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS); } send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS); - - return; } static void light_lc_om_set(struct bt_mesh_model *model, @@ -2394,8 +2339,8 @@ static void light_lc_om_set(struct bt_mesh_model *model, bt_mesh_light_server_recv_set_msg_t set = { .lc_om_set.mode = om, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2404,15 +2349,13 @@ static void light_lc_om_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lc_om_set.mode = srv->lc->state.occupancy_mode, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET) { send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS); } send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS); - - return; } static void light_lc_light_onoff_set(struct bt_mesh_model *model, @@ -2446,8 +2389,8 @@ static void light_lc_light_onoff_set(struct bt_mesh_model *model, .lc_light_onoff_set.trans_time = trans_time, .lc_light_onoff_set.delay = delay, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2473,8 +2416,8 @@ static void light_lc_light_onoff_set(struct bt_mesh_model *model, bt_mesh_light_server_state_change_t change = { .lc_light_onoff_set.onoff = srv->lc->state.light_onoff, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET) { send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS); @@ -2486,8 +2429,8 @@ static void light_lc_light_onoff_set(struct bt_mesh_model *model, } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -2504,7 +2447,6 @@ static void light_lc_light_onoff_set(struct bt_mesh_model *model, bt_mesh_light_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void light_lc_sensor_status(struct bt_mesh_model *model, @@ -2550,8 +2492,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, bt_mesh_light_server_recv_status_msg_t status = { .sensor_status.data = buf, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_STATUS_MSG, model, ctx, (const uint8_t *)&status, sizeof(status)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_STATUS_MSG, + model, ctx, (const uint8_t *)&status, sizeof(status)); return; } @@ -2578,8 +2520,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, srv->lc->state.occupancy = BLE_MESH_STATE_ON; change.sensor_status.state.occupancy = srv->lc->state.occupancy; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } break; } @@ -2593,8 +2535,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, srv->lc->state.occupancy = BLE_MESH_STATE_ON; change.sensor_status.state.occupancy = srv->lc->state.occupancy; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } break; } @@ -2608,8 +2550,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, srv->lc->state.occupancy = BLE_MESH_STATE_ON; change.sensor_status.state.occupancy = srv->lc->state.occupancy; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } break; } @@ -2624,8 +2566,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, srv->lc->prop_state.time_occupancy_delay - val; change.sensor_status.state.set_occupancy_to_1_delay = srv->lc->prop_state.set_occupancy_to_1_delay; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } break; } @@ -2645,8 +2587,8 @@ static void light_lc_sensor_status(struct bt_mesh_model *model, srv->lc->state.ambient_luxlevel = (msb << 16) | lsb; change.sensor_status.state.ambient_luxlevel = srv->lc->state.ambient_luxlevel; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); break; } default: @@ -2766,7 +2708,6 @@ static void send_light_lc_prop_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void light_lc_prop_get(struct bt_mesh_model *model, @@ -2792,13 +2733,12 @@ static void light_lc_prop_get(struct bt_mesh_model *model, bt_mesh_light_server_recv_get_msg_t get = { .lc_property_get.id = net_buf_simple_pull_le16(buf), }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); return; } send_light_lc_prop_status(model, ctx, prop_id, false); - return; } static void light_lc_prop_set(struct bt_mesh_model *model, @@ -2825,8 +2765,8 @@ static void light_lc_prop_set(struct bt_mesh_model *model, .lc_property_set.id = net_buf_simple_pull_le16(buf), .lc_property_set.value = buf, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -2849,15 +2789,13 @@ static void light_lc_prop_set(struct bt_mesh_model *model, .lc_property_set.id = prop_id, .lc_property_set.value = buf, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET) { send_light_lc_prop_status(model, ctx, prop_id, false); } send_light_lc_prop_status(model, ctx, prop_id, true); - - return; } /* message handlers (End) */ @@ -3155,7 +3093,7 @@ static int light_server_init(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_light_server_mutex_new(); + bt_mesh_mutex_create(&light_server_lock); return 0; } @@ -3238,8 +3176,8 @@ static int light_hsl_srv_init(struct bt_mesh_model *model) * the corresponding Light HSL Setup Server model shall also be present. * The model requires three elements: the main element and the Hue element * and the Saturation element. The Hue element contains the corresponding - * Light HSL Hue Server model, and the Saturation element contains the corr- - * esponding Light HSL Saturation Server model. + * Light HSL Hue Server model, and the Saturation element contains the + * corresponding Light HSL Saturation Server model. */ struct bt_mesh_elem *element = bt_mesh_model_elem(model); if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV) == NULL) { @@ -3449,7 +3387,7 @@ static int light_server_deinit(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_light_server_mutex_free(); + bt_mesh_mutex_free(&light_server_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/models/server/sensor_server.c b/components/bt/esp_ble_mesh/models/server/sensor_server.c index 0d3797cc7e..b920283ec6 100644 --- a/components/bt/esp_ble_mesh/models/server/sensor_server.c +++ b/components/bt/esp_ble_mesh/models/server/sensor_server.c @@ -50,6 +50,7 @@ static void send_sensor_descriptor_status(struct bt_mesh_model *model, BT_WARN("Too large sensor descriptor status"); break; } + net_buf_simple_add_le16(msg, state->sensor_property_id); net_buf_simple_add_le32(msg, (state->descriptor.sample_function << 24) | (state->descriptor.negative_tolerance << 12) | @@ -62,7 +63,7 @@ static void send_sensor_descriptor_status(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { total_len += SENSOR_DESCRIPTOR_LEN; if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) { /* Add this in case the message is too long */ @@ -71,8 +72,8 @@ static void send_sensor_descriptor_status(struct bt_mesh_model *model, } net_buf_simple_add_le16(msg, state->sensor_property_id); net_buf_simple_add_le32(msg, (state->descriptor.sample_function << 24) | - (state->descriptor.negative_tolerance << 12) | - (state->descriptor.positive_tolerance)); + (state->descriptor.negative_tolerance << 12) | + (state->descriptor.positive_tolerance)); net_buf_simple_add_u8(msg, state->descriptor.measure_period); net_buf_simple_add_u8(msg, state->descriptor.update_interval); break; @@ -85,8 +86,8 @@ static void send_sensor_descriptor_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); + bt_mesh_free_buf(msg); - return; } static void send_sensor_data_status(struct bt_mesh_model *model, @@ -120,6 +121,7 @@ static void send_sensor_data_status(struct bt_mesh_model *model, BT_WARN("Too large sensor status"); break; } + if (state->sensor_data.format == SENSOR_DATA_FORMAT_A) { uint16_t mpid = ((state->sensor_property_id & BIT_MASK(11)) << 5) | ((state->sensor_data.length & BIT_MASK(4)) << 1) | @@ -139,7 +141,7 @@ static void send_sensor_data_status(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { uint8_t mpid_len = (state->sensor_data.format == SENSOR_DATA_FORMAT_A) ? SENSOR_DATA_FORMAT_A_MPID_LEN : SENSOR_DATA_FORMAT_B_MPID_LEN; total_len += (mpid_len + (state->sensor_data.raw_value ? @@ -175,8 +177,8 @@ static void send_sensor_data_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); + bt_mesh_free_buf(msg); - return; } static void send_sensor_cadence_status(struct bt_mesh_model *model, @@ -192,7 +194,7 @@ static void send_sensor_cadence_status(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id && state->cadence) { + state->sensor_property_id == prop_id && state->cadence) { length = SENSOR_PROPERTY_ID_LEN + 1 + 1; if (state->cadence->trigger_delta_down) { if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) { @@ -240,7 +242,7 @@ static void send_sensor_cadence_status(struct bt_mesh_model *model, if (i != srv->state_count) { if (state->cadence) { net_buf_simple_add_u8(msg, (state->cadence->trigger_type << 7) | - state->cadence->period_divisor); + state->cadence->period_divisor); if (state->cadence->trigger_delta_down) { if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) { net_buf_simple_add_mem(msg, state->cadence->trigger_delta_down->data, @@ -277,7 +279,6 @@ static void send_sensor_cadence_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void send_sensor_settings_status(struct bt_mesh_model *model, @@ -325,8 +326,8 @@ static void send_sensor_settings_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); + bt_mesh_free_buf(msg); - return; } static struct sensor_setting *find_sensor_setting(struct bt_mesh_model *model, @@ -340,12 +341,12 @@ static struct sensor_setting *find_sensor_setting(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id && - state->setting_count && state->settings) { + state->sensor_property_id == prop_id && + state->setting_count && state->settings) { for (j = 0; j < state->setting_count; j++) { item = &state->settings[j]; if (item->property_id != INVALID_SENSOR_SETTING_PROPERTY_ID && - item->property_id == set_prop_id) { + item->property_id == set_prop_id) { return item; } } @@ -420,7 +421,6 @@ static void send_sensor_setting_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void send_sensor_column_status(struct bt_mesh_model *model, @@ -437,7 +437,7 @@ static void send_sensor_column_status(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { length = SENSOR_PROPERTY_ID_LEN; if (state->series_column.raw_value_x) { length += state->series_column.raw_value_x->len; @@ -494,8 +494,8 @@ static void send_sensor_column_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); + bt_mesh_free_buf(msg); - return; } static void send_sensor_series_status(struct bt_mesh_model *model, @@ -512,7 +512,7 @@ static void send_sensor_series_status(struct bt_mesh_model *model, for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { length = SENSOR_PROPERTY_ID_LEN; /* TODO: raw value x, column width & raw value y in Sensor Series * Status are optional, here we need to add some conditions to @@ -569,8 +569,8 @@ static void send_sensor_series_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); + bt_mesh_free_buf(msg); - return; } static void sensor_get(struct bt_mesh_model *model, @@ -611,8 +611,8 @@ static void sensor_get(struct bt_mesh_model *model, .sensor_descriptor_get.op_en = !get_all, .sensor_descriptor_get.id = prop_id, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_descriptor_status(model, ctx, prop_id, get_all); } @@ -622,8 +622,8 @@ static void sensor_get(struct bt_mesh_model *model, .sensor_get.op_en = !get_all, .sensor_get.id = prop_id, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_data_status(model, ctx, prop_id, get_all); } @@ -640,8 +640,8 @@ static void sensor_get(struct bt_mesh_model *model, .sensor_column_get.id = prop_id, .sensor_column_get.raw_x = buf, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_column_status(model, ctx, buf, prop_id); } @@ -651,8 +651,8 @@ static void sensor_get(struct bt_mesh_model *model, .sensor_series_get.id = prop_id, .sensor_series_get.raw = buf, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_series_status(model, ctx, buf, prop_id); } @@ -680,8 +680,8 @@ static void sensor_get(struct bt_mesh_model *model, bt_mesh_sensor_server_recv_get_msg_t get = { .sensor_cadence_get.id = prop_id, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_cadence_status(model, ctx, prop_id, false); } @@ -690,8 +690,8 @@ static void sensor_get(struct bt_mesh_model *model, bt_mesh_sensor_server_recv_get_msg_t get = { .sensor_settings_get.id = prop_id, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_settings_status(model, ctx, prop_id); } @@ -713,8 +713,8 @@ static void sensor_get(struct bt_mesh_model *model, .sensor_setting_get.id = prop_id, .sensor_setting_get.setting_id = set_prop_id, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); } else { send_sensor_setting_status(model, ctx, prop_id, set_prop_id, false); } @@ -756,15 +756,15 @@ static void sensor_cadence_set(struct bt_mesh_model *model, .sensor_cadence_set.id = prop_id, .sensor_cadence_set.cadence = buf, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { break; } } @@ -850,8 +850,8 @@ static void sensor_cadence_set(struct bt_mesh_model *model, change.sensor_cadence_set.min_interval = state->cadence->min_interval; change.sensor_cadence_set.fast_cadence_low = state->cadence->fast_cadence_low; change.sensor_cadence_set.fast_cadence_high = state->cadence->fast_cadence_high; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET) { send_sensor_cadence_status(model, ctx, prop_id, false); @@ -871,7 +871,6 @@ static void sensor_cadence_set(struct bt_mesh_model *model, * status publication mechanism. */ update_sensor_periodic_pub(sensor_model, prop_id); - return; } static void update_sensor_periodic_pub(struct bt_mesh_model *model, uint16_t prop_id) @@ -894,7 +893,7 @@ static void update_sensor_periodic_pub(struct bt_mesh_model *model, uint16_t pro for (i = 0; i < srv->state_count; i++) { state = &srv->states[i]; if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID && - state->sensor_property_id == prop_id) { + state->sensor_property_id == prop_id) { break; } } @@ -948,8 +947,8 @@ static void sensor_setting_set(struct bt_mesh_model *model, .sensor_setting_set.setting_id = set_prop_id, .sensor_setting_set.raw = buf, }; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -963,8 +962,8 @@ static void sensor_setting_set(struct bt_mesh_model *model, change.sensor_setting_set.id = prop_id; change.sensor_setting_set.setting_id = set_prop_id; change.sensor_setting_set.value = item->raw; - bt_mesh_sensor_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_sensor_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } } @@ -974,8 +973,6 @@ static void sensor_setting_set(struct bt_mesh_model *model, if (item) { send_sensor_setting_status(model, ctx, prop_id, set_prop_id, true); } - - return; } /* message handlers (End) */ @@ -1006,7 +1003,7 @@ static int check_sensor_server_init(struct bt_mesh_sensor_state *state_start, { struct bt_mesh_sensor_state *state = NULL; struct sensor_setting *setting = NULL; - int i, j; + int i, j, k; for (i = 0; i < state_count; i++) { state = &state_start[i]; @@ -1015,7 +1012,7 @@ static int check_sensor_server_init(struct bt_mesh_sensor_state *state_start, return -EINVAL; } /* Check if the same Sensor Property ID exists */ - for (int k = i + 1; k < state_count; k++) { + for (k = i + 1; k < state_count; k++) { if (state->sensor_property_id == state_start[k].sensor_property_id) { BT_ERR("Same Sensor Property ID 0x%04x exists", state->sensor_property_id); return -EINVAL; @@ -1029,7 +1026,7 @@ static int check_sensor_server_init(struct bt_mesh_sensor_state *state_start, return -EINVAL; } /* Check if the same Sensor Setting Property ID exists */ - for (int k = j + 1; k < state->setting_count; k++) { + for (k = j + 1; k < state->setting_count; k++) { if (setting->property_id == state->settings[k].property_id) { BT_ERR("Same Sensor Setting Property ID 0x%04x exists", setting->property_id); return -EINVAL; @@ -1039,9 +1036,9 @@ static int check_sensor_server_init(struct bt_mesh_sensor_state *state_start, } if (state->cadence) { if (state->cadence->trigger_delta_down == NULL || - state->cadence->trigger_delta_up == NULL || - state->cadence->fast_cadence_low == NULL || - state->cadence->fast_cadence_high == NULL) { + state->cadence->trigger_delta_up == NULL || + state->cadence->fast_cadence_low == NULL || + state->cadence->fast_cadence_high == NULL) { BT_ERR("Invalid Sensor Cadence state"); return -EINVAL; } @@ -1069,9 +1066,11 @@ static int sensor_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Sensor state, model id 0x%04x", model->id); return -EINVAL; } + if (check_sensor_server_init(srv->states, srv->state_count)) { return -EINVAL; } + srv->model = model; break; } @@ -1081,9 +1080,11 @@ static int sensor_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Sensor state, model id 0x%04x", model->id); return -EINVAL; } + if (check_sensor_server_init(srv->states, srv->state_count)) { return -EINVAL; } + srv->model = model; break; } diff --git a/components/bt/esp_ble_mesh/models/server/server_common.c b/components/bt/esp_ble_mesh/models/server/server_common.c index 8e7879cc4f..a12ce6ba38 100644 --- a/components/bt/esp_ble_mesh/models/server/server_common.c +++ b/components/bt/esp_ble_mesh/models/server/server_common.c @@ -171,9 +171,9 @@ void bt_mesh_server_alloc_ctx(struct k_work *work) * Here we use the allocated heap memory to store the "struct bt_mesh_msg_ctx". */ __ASSERT(work, "Invalid parameter"); - if (!work->_reserved) { - work->_reserved = bt_mesh_calloc(sizeof(struct bt_mesh_msg_ctx)); - __ASSERT(work->_reserved, "Out of memory"); + if (!work->user_data) { + work->user_data = bt_mesh_calloc(sizeof(struct bt_mesh_msg_ctx)); + __ASSERT(work->user_data, "Out of memory"); } } @@ -181,9 +181,9 @@ void bt_mesh_server_alloc_ctx(struct k_work *work) void bt_mesh_server_free_ctx(struct k_work *work) { __ASSERT(work, "Invalid parameter"); - if (work->_reserved) { - bt_mesh_free(work->_reserved); - work->_reserved = NULL; + if (work->user_data) { + bt_mesh_free(work->user_data); + work->user_data = NULL; } } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -199,7 +199,7 @@ bool bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info *last, } if (last->tid == tid && last->src == src && last->dst == dst && - (*now - last->timestamp <= K_SECONDS(6))) { + (*now - last->timestamp <= K_SECONDS(6))) { return true; } @@ -218,7 +218,6 @@ void bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info *last, last->src = src; last->dst = dst; last->timestamp = *now; - return; } struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, uint16_t msg_len) @@ -231,7 +230,7 @@ struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, u } if (model->pub == NULL || model->pub->msg == NULL || - model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) { + model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) { BT_DBG("No publication support, model id 0x%04x", model->id); return NULL; } diff --git a/components/bt/esp_ble_mesh/models/server/state_binding.c b/components/bt/esp_ble_mesh/models/server/state_binding.c index 3896d6c251..4a2da3aa18 100644 --- a/components/bt/esp_ble_mesh/models/server/state_binding.c +++ b/components/bt/esp_ble_mesh/models/server/state_binding.c @@ -10,50 +10,18 @@ #include "mesh/config.h" #include "mesh/common.h" +#include "mesh/model_common.h" #include "mesh/model_opcode.h" #include "mesh/state_binding.h" #include "mesh/state_transition.h" #if CONFIG_BLE_MESH_SERVER_MODEL -#define MINDIFF (2.25e-308) - -static float bt_mesh_sqrt(float square) -{ - float root = 0.0, last = 0.0, diff = 0.0; - - root = square / 3.0; - diff = 1; - - if (square <= 0) { - return 0; - } - - do { - last = root; - root = (root + square / root) / 2.0; - diff = root - last; - } while (diff > MINDIFF || diff < -MINDIFF); - - return root; -} - -static int32_t bt_mesh_ceiling(float num) -{ - int32_t inum = (int32_t)num; - - if (num == (float)inum) { - return inum; - } - - return inum + 1; -} - uint16_t bt_mesh_convert_lightness_actual_to_linear(uint16_t actual) { float tmp = ((float) actual / UINT16_MAX); - return bt_mesh_ceiling(UINT16_MAX * tmp * tmp); + return bt_mesh_ceil(UINT16_MAX * tmp * tmp); } uint16_t bt_mesh_convert_lightness_linear_to_actual(uint16_t linear) @@ -99,7 +67,7 @@ int bt_mesh_update_binding_state(struct bt_mesh_model *model, bt_mesh_server_state_value_t *value) { if (model == NULL || model->user_data == NULL || - value == NULL || type > BIND_STATE_MAX) { + value == NULL || type > BIND_STATE_MAX) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } diff --git a/components/bt/esp_ble_mesh/models/server/state_transition.c b/components/bt/esp_ble_mesh/models/server/state_transition.c index 8a8d04e06c..46c8281697 100644 --- a/components/bt/esp_ble_mesh/models/server/state_transition.c +++ b/components/bt/esp_ble_mesh/models/server/state_transition.c @@ -238,26 +238,27 @@ void scene_tt_values(struct bt_mesh_scene_srv *srv, uint8_t trans_time, uint8_t #if CONFIG_BLE_MESH_GENERIC_SERVER void generic_onoff_work_handler(struct k_work *work) { - struct bt_mesh_gen_onoff_srv *srv = - CONTAINER_OF(work, struct bt_mesh_gen_onoff_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_gen_onoff_srv *srv = CONTAINER_OF(work, + struct bt_mesh_gen_onoff_srv, + transition.timer.work); bt_mesh_gen_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; - if (srv == NULL || srv->transition.timer.work._reserved == NULL) { + if (srv == NULL || srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_generic_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.gen_onoff_set.onoff = srv->state.onoff; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { /** @@ -269,8 +270,8 @@ void generic_onoff_work_handler(struct k_work *work) if (srv->state.target_onoff == BLE_MESH_STATE_ON) { srv->state.onoff = BLE_MESH_STATE_ON; change.gen_onoff_set.onoff = srv->state.onoff; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); } transition_timer_start(&srv->transition); } @@ -288,32 +289,32 @@ void generic_onoff_work_handler(struct k_work *work) srv->state.onoff = srv->state.target_onoff; if (srv->state.target_onoff != BLE_MESH_STATE_ON) { change.gen_onoff_set.onoff = srv->state.onoff; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); } } gen_onoff_publish(srv->model); bt_mesh_generic_server_unlock(); - return; } void generic_level_work_handler(struct k_work *work) { - struct bt_mesh_gen_level_srv *srv = - CONTAINER_OF(work, struct bt_mesh_gen_level_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_gen_level_srv *srv = CONTAINER_OF(work, + struct bt_mesh_gen_level_srv, + transition.timer.work); bt_mesh_gen_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; - if (srv == NULL || srv->transition.timer.work._reserved == NULL) { + if (srv == NULL || srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_generic_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; @@ -332,8 +333,8 @@ void generic_level_work_handler(struct k_work *work) change.gen_move_set.level = srv->state.level; break; } - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -367,38 +368,38 @@ void generic_level_work_handler(struct k_work *work) change.gen_move_set.level = srv->state.level; break; } - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); gen_level_publish(srv->model); bt_mesh_generic_server_unlock(); - return; } void generic_power_level_work_handler(struct k_work *work) { - struct bt_mesh_gen_power_level_srv *srv = - CONTAINER_OF(work, struct bt_mesh_gen_power_level_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_gen_power_level_srv *srv = CONTAINER_OF(work, + struct bt_mesh_gen_power_level_srv, + transition.timer.work); bt_mesh_gen_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_generic_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.gen_power_level_set.power = srv->state->power_actual; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -429,40 +430,40 @@ void generic_power_level_work_handler(struct k_work *work) } change.gen_power_level_set.power = srv->state->power_actual; - bt_mesh_generic_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); gen_power_level_publish(srv->model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS); bt_mesh_generic_server_unlock(); - return; } #endif /* CONFIG_BLE_MESH_GENERIC_SERVER */ #if CONFIG_BLE_MESH_LIGHTING_SERVER void light_lightness_actual_work_handler(struct k_work *work) { - struct bt_mesh_light_lightness_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_lightness_srv, actual_transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_lightness_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_lightness_srv, + actual_transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->actual_transition.timer.work._reserved == NULL) { + srv->actual_transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->actual_transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->actual_transition.timer.work.user_data; if (srv->actual_transition.just_started) { srv->actual_transition.just_started = false; if (srv->actual_transition.counter == 0U) { change.lightness_set.lightness = srv->state->lightness_actual; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->actual_transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->actual_transition); @@ -493,38 +494,38 @@ void light_lightness_actual_work_handler(struct k_work *work) } change.lightness_set.lightness = srv->state->lightness_actual; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS); bt_mesh_light_server_unlock(); - return; } void light_lightness_linear_work_handler(struct k_work *work) { - struct bt_mesh_light_lightness_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_lightness_srv, linear_transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_lightness_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_lightness_srv, + linear_transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->linear_transition.timer.work._reserved == NULL) { + srv->linear_transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->linear_transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->linear_transition.timer.work.user_data; if (srv->linear_transition.just_started) { srv->linear_transition.just_started = false; if (srv->linear_transition.counter == 0U) { change.lightness_linear_set.lightness = srv->state->lightness_linear; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->linear_transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->linear_transition); @@ -545,31 +546,31 @@ void light_lightness_linear_work_handler(struct k_work *work) } change.lightness_linear_set.lightness = srv->state->lightness_linear; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS); bt_mesh_light_server_unlock(); - return; } void light_ctl_work_handler(struct k_work *work) { - struct bt_mesh_light_ctl_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_ctl_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_ctl_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_ctl_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; @@ -577,8 +578,8 @@ void light_ctl_work_handler(struct k_work *work) change.ctl_set.lightness = srv->state->lightness; change.ctl_set.temperature = srv->state->temperature; change.ctl_set.delta_uv = srv->state->delta_uv; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -605,39 +606,39 @@ void light_ctl_work_handler(struct k_work *work) change.ctl_set.lightness = srv->state->lightness; change.ctl_set.temperature = srv->state->temperature; change.ctl_set.delta_uv = srv->state->delta_uv; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS); bt_mesh_light_server_unlock(); - return; } void light_ctl_temp_work_handler(struct k_work *work) { - struct bt_mesh_light_ctl_temp_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_ctl_temp_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_ctl_temp_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_ctl_temp_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.ctl_temp_set.temperature = srv->state->temperature; change.ctl_temp_set.delta_uv = srv->state->delta_uv; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -661,31 +662,31 @@ void light_ctl_temp_work_handler(struct k_work *work) change.ctl_temp_set.temperature = srv->state->temperature; change.ctl_temp_set.delta_uv = srv->state->delta_uv; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS); bt_mesh_light_server_unlock(); - return; } void light_hsl_work_handler(struct k_work *work) { - struct bt_mesh_light_hsl_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_hsl_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_hsl_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_hsl_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; @@ -693,8 +694,8 @@ void light_hsl_work_handler(struct k_work *work) change.hsl_set.lightness = srv->state->lightness; change.hsl_set.hue = srv->state->hue; change.hsl_set.saturation = srv->state->saturation; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -721,38 +722,38 @@ void light_hsl_work_handler(struct k_work *work) change.hsl_set.lightness = srv->state->lightness; change.hsl_set.hue = srv->state->hue; change.hsl_set.saturation = srv->state->saturation; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS); bt_mesh_light_server_unlock(); - return; } void light_hsl_hue_work_handler(struct k_work *work) { - struct bt_mesh_light_hsl_hue_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_hsl_hue_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_hsl_hue_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_hsl_hue_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.hsl_hue_set.hue = srv->state->hue; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -773,38 +774,38 @@ void light_hsl_hue_work_handler(struct k_work *work) } change.hsl_hue_set.hue = srv->state->hue; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS); bt_mesh_light_server_unlock(); - return; } void light_hsl_sat_work_handler(struct k_work *work) { - struct bt_mesh_light_hsl_sat_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_hsl_sat_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_hsl_sat_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_hsl_sat_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.hsl_saturation_set.saturation = srv->state->saturation; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -825,31 +826,31 @@ void light_hsl_sat_work_handler(struct k_work *work) } change.hsl_saturation_set.saturation = srv->state->saturation; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS); bt_mesh_light_server_unlock(); - return; } void light_xyl_work_handler(struct k_work *work) { - struct bt_mesh_light_xyl_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_xyl_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_xyl_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_xyl_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; @@ -857,8 +858,8 @@ void light_xyl_work_handler(struct k_work *work) change.xyl_set.lightness = srv->state->lightness; change.xyl_set.x = srv->state->x; change.xyl_set.y = srv->state->y; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -885,37 +886,37 @@ void light_xyl_work_handler(struct k_work *work) change.xyl_set.lightness = srv->state->lightness; change.xyl_set.x = srv->state->x; change.xyl_set.y = srv->state->y; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); light_xyl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS); bt_mesh_light_server_unlock(); - return; } void light_lc_work_handler(struct k_work *work) { - struct bt_mesh_light_lc_srv *srv = - CONTAINER_OF(work, struct bt_mesh_light_lc_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_light_lc_srv *srv = CONTAINER_OF(work, + struct bt_mesh_light_lc_srv, + transition.timer.work); bt_mesh_light_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; - if (srv == NULL || srv->transition.timer.work._reserved == NULL) { + if (srv == NULL || srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_light_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { /** @@ -929,8 +930,8 @@ void light_lc_work_handler(struct k_work *work) bt_mesh_light_server_state_change_t change = { .lc_light_onoff_set.onoff = srv->lc->state.light_onoff, }; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); } transition_timer_start(&srv->transition); } @@ -948,42 +949,42 @@ void light_lc_work_handler(struct k_work *work) srv->lc->state.light_onoff = srv->lc->state.target_light_onoff; if (srv->lc->state.light_onoff != BLE_MESH_STATE_ON) { change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff; - bt_mesh_lighting_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); } } light_lc_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS); bt_mesh_light_server_unlock(); - return; } #endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */ #if CONFIG_BLE_MESH_TIME_SCENE_SERVER void scene_recall_work_handler(struct k_work *work) { - struct bt_mesh_scene_srv *srv = - CONTAINER_OF(work, struct bt_mesh_scene_srv, transition.timer.work); - struct bt_mesh_msg_ctx *ctx = NULL; + struct bt_mesh_scene_srv *srv = CONTAINER_OF(work, + struct bt_mesh_scene_srv, + transition.timer.work); bt_mesh_time_scene_server_state_change_t change = {0}; + struct bt_mesh_msg_ctx *ctx = NULL; if (srv == NULL || srv->state == NULL || - srv->transition.timer.work._reserved == NULL) { + srv->transition.timer.work.user_data == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; } bt_mesh_time_scene_server_lock(); - ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved; + ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data; if (srv->transition.just_started) { srv->transition.just_started = false; if (srv->transition.counter == 0U) { change.scene_recall.scene_number = srv->state->current_scene; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START); } else { transition_timer_start(&srv->transition); @@ -1005,13 +1006,12 @@ void scene_recall_work_handler(struct k_work *work) } change.scene_recall.scene_number = srv->state->current_scene; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, srv->model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + srv->model, ctx, (const uint8_t *)&change, sizeof(change)); scene_publish(srv->model, ctx, BLE_MESH_MODEL_OP_SCENE_STATUS); bt_mesh_time_scene_server_unlock(); - return; } #endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */ @@ -1027,11 +1027,9 @@ void bt_mesh_server_stop_transition(struct bt_mesh_state_transition *transition) void bt_mesh_server_start_transition(struct bt_mesh_state_transition *transition) { + k_delayed_work_submit(&transition->timer, K_MSEC(5 * transition->delay)); if (transition->delay) { - k_delayed_work_submit(&transition->timer, K_MSEC(5 * transition->delay)); bt_mesh_atomic_set_bit(transition->flag, BLE_MESH_TRANS_TIMER_START); - } else { - k_work_submit(&transition->timer.work); } } diff --git a/components/bt/esp_ble_mesh/models/server/time_scene_server.c b/components/bt/esp_ble_mesh/models/server/time_scene_server.c index 4166a08766..3494653aaa 100644 --- a/components/bt/esp_ble_mesh/models/server/time_scene_server.c +++ b/components/bt/esp_ble_mesh/models/server/time_scene_server.c @@ -18,20 +18,6 @@ static bt_mesh_mutex_t time_scene_server_lock; -static inline void bt_mesh_time_scene_server_mutex_new(void) -{ - if (!time_scene_server_lock.mutex) { - bt_mesh_mutex_create(&time_scene_server_lock); - } -} - -#if CONFIG_BLE_MESH_DEINIT -static inline void bt_mesh_time_scene_server_mutex_free(void) -{ - bt_mesh_mutex_free(&time_scene_server_lock); -} -#endif /* CONFIG_BLE_MESH_DEINIT */ - void bt_mesh_time_scene_server_lock(void) { bt_mesh_mutex_lock(&time_scene_server_lock); @@ -148,7 +134,6 @@ static void send_time_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void time_get(struct bt_mesh_model *model, @@ -191,8 +176,8 @@ static void time_get(struct bt_mesh_model *model, if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { if (ctx->recv_op != BLE_MESH_MODEL_OP_TIME_STATUS) { - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } } @@ -208,7 +193,7 @@ static void time_get(struct bt_mesh_model *model, return; } if (srv->state->time_role != TIME_RELAY && - srv->state->time_role != TIME_CLINET) { + srv->state->time_role != TIME_CLIENT) { /** * If the value of the Time Role state of the element is 0x00 (None) or * 0x01 (Time Authority), the message shall be ignored. @@ -231,8 +216,8 @@ static void time_get(struct bt_mesh_model *model, status.time_status.tai_utc_delta = (val >> 1) & BIT_MASK(15); status.time_status.time_zone_offset = net_buf_simple_pull_u8(buf); } - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG, model, ctx, (const uint8_t *)&status, sizeof(status)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG, + model, ctx, (const uint8_t *)&status, sizeof(status)); return; } memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN); @@ -260,8 +245,8 @@ static void time_get(struct bt_mesh_model *model, change.time_status.uncertainty = srv->state->time.uncertainty; change.time_status.time_authority = srv->state->time.time_authority; change.time_status.tai_utc_delta_curr = srv->state->time.subsecond; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (model->pub == NULL || model->pub->msg == NULL || model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) { @@ -296,7 +281,6 @@ static void time_get(struct bt_mesh_model *model, } send_time_status(model, ctx, false, opcode); - return; } static void time_set(struct bt_mesh_model *model, @@ -325,8 +309,8 @@ static void time_set(struct bt_mesh_model *model, set.time_set.time_authority = val & BIT(0); set.time_set.tai_utc_delta = (val >> 1) & BIT_MASK(15); set.time_set.time_zone_offset = net_buf_simple_pull_u8(buf); - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN); @@ -345,8 +329,8 @@ static void time_set(struct bt_mesh_model *model, set.time_zone_set.time_zone_offset_new = net_buf_simple_pull_u8(buf); memcpy(set.time_zone_set.tai_zone_change, buf->data, TAI_OF_ZONE_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_ZONE_CHANGE_LEN); - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } srv->state->time.time_zone_offset_new = net_buf_simple_pull_u8(buf); @@ -365,8 +349,8 @@ static void time_set(struct bt_mesh_model *model, set.tai_utc_delta_set.tai_utc_delta_new = val & BIT_MASK(15); memcpy(set.tai_utc_delta_set.tai_delta_change, buf->data, TAI_OF_DELTA_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_DELTA_CHANGE_LEN); - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } srv->state->time.tai_utc_delta_new = val & BIT_MASK(15); @@ -376,7 +360,7 @@ static void time_set(struct bt_mesh_model *model, break; case BLE_MESH_MODEL_OP_TIME_ROLE_SET: role = net_buf_simple_pull_u8(buf); - if (role > TIME_CLINET) { + if (role > TIME_CLIENT) { BT_ERR("Invalid Time Role 0x%02x", role); return; } @@ -384,8 +368,8 @@ static void time_set(struct bt_mesh_model *model, bt_mesh_time_scene_server_recv_set_msg_t set = { .time_role_set.time_role = role, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } srv->state->time_role = role; @@ -419,12 +403,11 @@ static void time_set(struct bt_mesh_model *model, return; } - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); /* Send corresponding time status message */ send_time_status(model, ctx, false, opcode); - return; } /* Scene Server & Scene Setup Server message handlers */ @@ -480,7 +463,6 @@ static void send_scene_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void send_scene_register_status(struct bt_mesh_model *model, @@ -520,7 +502,7 @@ static void send_scene_register_status(struct bt_mesh_model *model, if (scene->scene_number != INVALID_SCENE_NUMBER) { total_len += SCENE_NUMBER_LEN; if ((publish == false && total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) || - (publish == true && total_len > msg->size + BLE_MESH_SERVER_TRANS_MIC_SIZE)) { + (publish == true && total_len > msg->size + BLE_MESH_SERVER_TRANS_MIC_SIZE)) { /* Add this in case the message is too long */ BT_WARN("Too large scene register status"); break; @@ -535,7 +517,6 @@ static void send_scene_register_status(struct bt_mesh_model *model, } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } - return; } static void scene_get(struct bt_mesh_model *model, @@ -550,8 +531,8 @@ static void scene_get(struct bt_mesh_model *model, } if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -583,7 +564,6 @@ void scene_publish(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uin } send_scene_status(model, ctx, true); - return; } static void scene_recall(struct bt_mesh_model *model, @@ -622,8 +602,8 @@ static void scene_recall(struct bt_mesh_model *model, .scene_recall.trans_time = trans_time, .scene_recall.delay = delay, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -681,16 +661,16 @@ static void scene_recall(struct bt_mesh_model *model, bt_mesh_time_scene_server_state_change_t change = { .scene_recall.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); bt_mesh_time_scene_server_unlock(); return; } /* Copy the ctx of the received message */ - if (srv->transition.timer.work._reserved) { - memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); + if (srv->transition.timer.work.user_data) { + memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ @@ -715,7 +695,6 @@ static void scene_recall(struct bt_mesh_model *model, bt_mesh_time_scene_server_unlock(); bt_mesh_server_start_transition(&srv->transition); - return; } static void scene_action(struct bt_mesh_model *model, @@ -745,8 +724,8 @@ static void scene_action(struct bt_mesh_model *model, bt_mesh_time_scene_server_recv_set_msg_t set = { .scene_store.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } /* Try to find a matching Scene Number */ @@ -800,8 +779,8 @@ static void scene_action(struct bt_mesh_model *model, bt_mesh_time_scene_server_state_change_t change = { .scene_store.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); } break; } @@ -811,8 +790,8 @@ static void scene_action(struct bt_mesh_model *model, bt_mesh_time_scene_server_recv_set_msg_t set = { .scene_delete.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } for (i = 0; i < srv->state->scene_count; i++) { @@ -904,8 +883,8 @@ static void scene_action(struct bt_mesh_model *model, bt_mesh_time_scene_server_state_change_t change = { .scene_delete.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); break; } default: @@ -918,8 +897,6 @@ static void scene_action(struct bt_mesh_model *model, send_scene_register_status(model, ctx, srv->state->status_code, false); } send_scene_register_status(model, NULL, srv->state->status_code, true); - - return; } static uint16_t get_schedule_reg_bit(struct bt_mesh_scheduler_state *state) @@ -981,7 +958,6 @@ static void send_scheduler_act_status(struct bt_mesh_model *model, } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL)); - return; } static void scheduler_get(struct bt_mesh_model *model, @@ -999,8 +975,8 @@ static void scheduler_get(struct bt_mesh_model *model, switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SCHEDULER_GET: { if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, + model, ctx, NULL, 0); return; } @@ -1020,8 +996,8 @@ static void scheduler_get(struct bt_mesh_model *model, bt_mesh_time_scene_server_recv_get_msg_t get = { .scheduler_act_get.index = index, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, (const uint8_t *)&get, sizeof(get)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, + model, ctx, (const uint8_t *)&get, sizeof(get)); return; } @@ -1109,8 +1085,8 @@ static void scheduler_act_set(struct bt_mesh_model *model, .scheduler_act_set.trans_time = trans_time, .scheduler_act_set.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const uint8_t *)&set, sizeof(set)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, + model, ctx, (const uint8_t *)&set, sizeof(set)); return; } @@ -1139,14 +1115,12 @@ static void scheduler_act_set(struct bt_mesh_model *model, .scheduler_act_set.trans_time = trans_time, .scheduler_act_set.scene_number = scene_number, }; - bt_mesh_time_scene_server_cb_evt_to_btc( - BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const uint8_t *)&change, sizeof(change)); + bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, + model, ctx, (const uint8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET) { send_scheduler_act_status(model, ctx, index); } - - return; } /* message handlers (End) */ @@ -1235,6 +1209,7 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Time State"); return -EINVAL; } + srv->model = model; break; } @@ -1244,6 +1219,7 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Time State"); return -EINVAL; } + srv->model = model; break; } @@ -1253,9 +1229,11 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Scene State"); return -EINVAL; } + if (check_scene_server_init(srv->state)) { return -EINVAL; } + if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) { bt_mesh_server_alloc_ctx(&srv->transition.timer.work); k_delayed_work_init(&srv->transition.timer, scene_recall_work_handler); @@ -1269,9 +1247,11 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Scene State"); return -EINVAL; } + if (check_scene_server_init(srv->state)) { return -EINVAL; } + srv->model = model; break; } @@ -1281,10 +1261,12 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Scheduler State"); return -EINVAL; } + if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) { BT_ERR("Invalid Register Schedule"); return -EINVAL; } + srv->model = model; break; } @@ -1294,10 +1276,12 @@ static int time_scene_server_init(struct bt_mesh_model *model) BT_ERR("Invalid Scheduler State"); return -EINVAL; } + if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) { BT_ERR("Invalid Register Schedule"); return -EINVAL; } + srv->model = model; break; } @@ -1306,7 +1290,7 @@ static int time_scene_server_init(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_time_scene_server_mutex_new(); + bt_mesh_mutex_create(&time_scene_server_lock); return 0; } @@ -1429,9 +1413,11 @@ static int time_scene_server_deinit(struct bt_mesh_model *model) BT_ERR("Invalid Scene State"); return -EINVAL; } + if (check_scene_server_init(srv->state)) { return -EINVAL; } + if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) { bt_mesh_server_free_ctx(&srv->transition.timer.work); k_delayed_work_free(&srv->transition.timer); @@ -1449,7 +1435,7 @@ static int time_scene_server_deinit(struct bt_mesh_model *model) return -EINVAL; } - bt_mesh_time_scene_server_mutex_free(); + bt_mesh_mutex_free(&time_scene_server_lock); return 0; } diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_agg_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_agg_model_api.c new file mode 100644 index 0000000000..5e4ac36b23 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_agg_model_api.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_agg_model.h" +#include "esp_ble_mesh_agg_model_api.h" + +#if CONFIG_BLE_MESH_AGG_CLI +esp_err_t esp_ble_mesh_register_agg_client_callback(esp_ble_mesh_agg_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_AGG_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_agg_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_agg_client_msg_t *msg) +{ + btc_ble_mesh_agg_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || msg == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_AGG_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_AGG_CLIENT_SEND; + + btc_arg.agg_send.params = params; + btc_arg.agg_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_agg_client_args_t), + btc_ble_mesh_agg_client_arg_deep_copy, + btc_ble_mesh_agg_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_AGG_CLI */ + +#if CONFIG_BLE_MESH_AGG_SRV +esp_err_t esp_ble_mesh_register_agg_server_callback(esp_ble_mesh_agg_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_AGG_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_AGG_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_brc_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_brc_model_api.c new file mode 100644 index 0000000000..a75b788c9b --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_brc_model_api.c @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" +#include "btc_ble_mesh_brc_model.h" +#include "esp_ble_mesh_brc_model_api.h" + +#if CONFIG_BLE_MESH_BRC_CLI +esp_err_t esp_ble_mesh_register_brc_client_callback(esp_ble_mesh_brc_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_BRC_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool bridge_cfg_client_send_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET: + case ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_SET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_ADD: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_REMOVE: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_brc_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_brc_client_msg_t *msg) +{ + btc_ble_mesh_brc_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (bridge_cfg_client_send_need_param(params->opcode) && msg == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_BRC_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_BRC_CLIENT_SEND; + + btc_arg.brc_send.params = params; + btc_arg.brc_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_brc_client_args_t), + btc_ble_mesh_brc_client_arg_deep_copy, + btc_ble_mesh_brc_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_BRC_CLI */ + +#if CONFIG_BLE_MESH_BRC_SRV +esp_err_t esp_ble_mesh_register_brc_server_callback(esp_ble_mesh_brc_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_BRC_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_BRC_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_cm_data_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_cm_data_api.c new file mode 100644 index 0000000000..08aa94e971 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_cm_data_api.c @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_err.h" + +#include "mesh_v1.1/utils.h" +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_cm_data_api.h" + +extern int bt_mesh_comp_1_register(const void *comp); +extern int bt_mesh_models_metadata_register(const void *metadata, uint8_t metadata_page); + +esp_err_t esp_ble_mesh_comp_1_register(const esp_ble_mesh_comp_1_t *comp) +{ + if (comp == NULL || comp->element_count == 0 || + comp->elements == NULL) { + return ESP_ERR_INVALID_ARG; + } + + return bt_mesh_comp_1_register(comp); +} + +esp_err_t esp_ble_mesh_models_metadata_register(const esp_ble_mesh_models_metadata_t *metadata, + uint8_t metadata_page) +{ + if (metadata == NULL || metadata->element_count == 0 || + metadata->elements == NULL || + (metadata_page != 0 && metadata_page != 128)) { + return ESP_ERR_INVALID_ARG; + } + + return bt_mesh_models_metadata_register(metadata, metadata_page); +} diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_df_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_df_model_api.c new file mode 100644 index 0000000000..9868cd9e23 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_df_model_api.c @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_df_model.h" +#include "esp_ble_mesh_df_model_api.h" + +#if CONFIG_BLE_MESH_DF_CLI +esp_err_t esp_ble_mesh_register_df_client_callback(esp_ble_mesh_df_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_DF_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool directed_forwarding_client_get_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_GET: + case ESP_BLE_MESH_MODEL_OP_PATH_METRIC_GET: + case ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET: + case ESP_BLE_MESH_MODEL_OP_WANTED_LANES_GET: + case ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_GET: + case ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_GET: + case ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_GET: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_df_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_get_t *get) +{ + btc_ble_mesh_df_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (directed_forwarding_client_get_need_param(params->opcode) && get == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DF_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DF_CLIENT_GET_STATE; + + arg.df_get.params = params; + arg.df_get.get = get; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_df_client_args_t), + btc_ble_mesh_df_client_arg_deep_copy, + btc_ble_mesh_df_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_df_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_set_t *set) +{ + btc_ble_mesh_df_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || set == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DF_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DF_CLIENT_SET_STATE; + + arg.df_set.params = params; + arg.df_set.set = set; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_df_client_args_t), + btc_ble_mesh_df_client_arg_deep_copy, + btc_ble_mesh_df_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_DF_CLI */ + +#if CONFIG_BLE_MESH_DF_SRV +esp_err_t esp_ble_mesh_register_df_server_callback(esp_ble_mesh_df_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_DF_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_DF_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_lcd_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_lcd_model_api.c new file mode 100644 index 0000000000..c6f3f0f1a3 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_lcd_model_api.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_lcd_model.h" +#include "esp_ble_mesh_lcd_model_api.h" + +#if CONFIG_BLE_MESH_LCD_CLI +esp_err_t esp_ble_mesh_register_lcd_client_callback(esp_ble_mesh_lcd_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_LCD_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_lcd_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_lcd_client_msg_t *msg) +{ + btc_ble_mesh_lcd_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || msg == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_LCD_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_LCD_CLIENT_SEND; + + btc_arg.lcd_send.params = params; + btc_arg.lcd_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_lcd_client_args_t), + btc_ble_mesh_lcd_client_arg_deep_copy, + btc_ble_mesh_lcd_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_LCD_CLI */ + +#if CONFIG_BLE_MESH_LCD_SRV +esp_err_t esp_ble_mesh_register_lcd_server_callback(esp_ble_mesh_lcd_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_LCD_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_LCD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_odp_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_odp_model_api.c new file mode 100644 index 0000000000..e5000ff553 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_odp_model_api.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_odp_model.h" +#include "esp_ble_mesh_odp_model_api.h" + +#if CONFIG_BLE_MESH_ODP_CLI +esp_err_t esp_ble_mesh_register_odp_client_callback(esp_ble_mesh_odp_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_ODP_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_odp_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_odp_client_msg_t *msg) +{ + btc_ble_mesh_odp_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (params->opcode == ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_SET && msg == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_ODP_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_ODP_CLIENT_SEND; + + btc_arg.odp_send.params = params; + btc_arg.odp_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_odp_client_args_t), + btc_ble_mesh_odp_client_arg_deep_copy, + btc_ble_mesh_odp_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_ODP_CLI */ + +#if CONFIG_BLE_MESH_ODP_SRV +esp_err_t esp_ble_mesh_register_odp_server_callback(esp_ble_mesh_odp_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_ODP_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_ODP_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_prb_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_prb_model_api.c new file mode 100644 index 0000000000..8c855f2ee7 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_prb_model_api.c @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" +#include "btc_ble_mesh_prb_model.h" +#include "esp_ble_mesh_prb_model_api.h" + +#if CONFIG_BLE_MESH_PRB_CLI +esp_err_t esp_ble_mesh_register_prb_client_callback(esp_ble_mesh_prb_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_PRB_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool private_beacon_client_send_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_SET: + case ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_SET: + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_GET: + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_SET: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_prb_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_prb_client_msg_t *msg) +{ + btc_ble_mesh_prb_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (private_beacon_client_send_need_param(params->opcode) && msg == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_PRB_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_PRB_CLIENT_SEND; + + btc_arg.prb_send.params = params; + btc_arg.prb_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_prb_client_args_t), + btc_ble_mesh_prb_client_arg_deep_copy, + btc_ble_mesh_prb_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_PRB_CLI */ + +#if CONFIG_BLE_MESH_PRB_SRV +esp_err_t esp_ble_mesh_register_prb_server_callback(esp_ble_mesh_prb_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_PRB_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_PRB_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_rpr_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_rpr_model_api.c new file mode 100644 index 0000000000..5ab2cd17d9 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_rpr_model_api.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_rpr_model.h" +#include "esp_ble_mesh_rpr_model_api.h" + +#if CONFIG_BLE_MESH_RPR_CLI +esp_err_t esp_ble_mesh_register_rpr_client_callback(esp_ble_mesh_rpr_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_RPR_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool remote_prov_client_get_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START: + case ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_START: + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_rpr_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_rpr_client_msg_t *msg) +{ + btc_ble_mesh_rpr_client_args_t arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (remote_prov_client_get_need_param(params->opcode) && msg == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_RPR_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_RPR_CLIENT_SEND; + + arg.rpr_send.params = params; + arg.rpr_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &arg, sizeof(btc_ble_mesh_rpr_client_args_t), + btc_ble_mesh_rpr_client_arg_deep_copy, + btc_ble_mesh_rpr_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_rpr_client_action(esp_ble_mesh_rpr_client_act_type_t type, + esp_ble_mesh_rpr_client_act_param_t *param) +{ + btc_ble_mesh_rpr_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (type > ESP_BLE_MESH_RPR_CLIENT_ACT_MAX || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_RPR_CLIENT; + msg.act = BTC_BLE_MESH_ACT_RPR_CLIENT_ACT; + + arg.rpr_act.type = type; + arg.rpr_act.param = param; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_rpr_client_args_t), + btc_ble_mesh_rpr_client_arg_deep_copy, + btc_ble_mesh_rpr_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_RPR_CLI */ + +#if CONFIG_BLE_MESH_RPR_SRV +esp_err_t esp_ble_mesh_register_rpr_server_callback(esp_ble_mesh_rpr_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_RPR_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_RPR_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c new file mode 100644 index 0000000000..51a051ec12 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_sar_model.h" +#include "esp_ble_mesh_sar_model_api.h" + +#if CONFIG_BLE_MESH_SAR_CLI +esp_err_t esp_ble_mesh_register_sar_client_callback(esp_ble_mesh_sar_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_SAR_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_sar_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sar_client_msg_t *msg) +{ + btc_ble_mesh_sar_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || (msg == NULL && + (params->opcode == ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_SET || + params->opcode == ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_SET)) || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_SAR_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_SAR_CLIENT_SEND; + + btc_arg.sar_send.params = params; + btc_arg.sar_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_sar_client_args_t), + btc_ble_mesh_sar_client_arg_deep_copy, + btc_ble_mesh_sar_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_SAR_CLI */ + +#if CONFIG_BLE_MESH_SAR_SRV +esp_err_t esp_ble_mesh_register_sar_server_callback(esp_ble_mesh_sar_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_SAR_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_SAR_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c new file mode 100644 index 0000000000..8d5aa16b4d --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_srpl_model.h" +#include "esp_ble_mesh_srpl_model_api.h" + +#if CONFIG_BLE_MESH_SRPL_CLI +esp_err_t esp_ble_mesh_register_srpl_client_callback(esp_ble_mesh_srpl_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_SRPL_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_srpl_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_srpl_client_msg_t *msg) +{ + btc_ble_mesh_srpl_client_args_t btc_arg = {0}; + btc_msg_t btc_msg = {0}; + + if (params == NULL || params->model == NULL || msg == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + btc_msg.sig = BTC_SIG_API_CALL; + btc_msg.pid = BTC_PID_SRPL_CLIENT; + btc_msg.act = BTC_BLE_MESH_ACT_SRPL_CLIENT_SEND; + + btc_arg.srpl_send.params = params; + btc_arg.srpl_send.msg = msg; + + return (btc_transfer_context(&btc_msg, &btc_arg, sizeof(btc_ble_mesh_srpl_client_args_t), + btc_ble_mesh_srpl_client_arg_deep_copy, + btc_ble_mesh_srpl_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ + +#if CONFIG_BLE_MESH_SRPL_SRV +esp_err_t esp_ble_mesh_register_srpl_server_callback(esp_ble_mesh_srpl_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_SRPL_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_SRPL_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_agg_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_agg_model_api.h new file mode 100644 index 0000000000..08f436fa6d --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_agg_model_api.h @@ -0,0 +1,218 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_AGG_MODEL_API_H_ +#define _ESP_BLE_MESH_AGG_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Defines the Opcodes Aggregator message opcode. */ +#define ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE ESP_BLE_MESH_MODEL_OP_2(0x80, 0x72) +#define ESP_BLE_MESH_MODEL_OP_AGG_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x73) + +/** Defines the status codes for Opcodes Aggregator messages. */ +#define ESP_BLE_MESH_AGG_STATUS_SUCCESS 0x00 +#define ESP_BLE_MESH_AGG_STATUS_INVALID_ADDRESS 0x01 +#define ESP_BLE_MESH_AGG_STATUS_INVALID_MODEL 0x02 +#define ESP_BLE_MESH_AGG_STATUS_WRONG_ACCESS_KEY 0x03 +#define ESP_BLE_MESH_AGG_STATUS_WRONG_OPCODE 0x04 +#define ESP_BLE_MESH_AGG_STATUS_MSG_NOT_UNDERSTOOD 0x05 + +/* A message that is not understood includes messages that have + * one or more of the following conditions: + * • The application opcode is unknown by the receiving element. + * • The access message size for the application opcode is incorrect. + * • The application parameters contain values that are currently + * Prohibited. + */ + +/** Values of the Length_Format */ +#define ESP_BLE_MESH_AGG_ITEM_LENGTH_FORMAT_SHORT 0 +#define ESP_BLE_MESH_AGG_ITEM_LENGTH_FORMAT_LONG 1 + +/** @def ESP_BLE_MESH_MODEL_AGG_SRV + * + * @brief Define a new Opcodes Aggregator Server model. + * + * @note If supported, the Opcodes Aggregator Server model shall be + * supported by a primary element. + * + * @param srv_data Pointer to a unique Opcodes Aggregator Server + * model user_data. + * + * @return New Opcodes Aggregator Server model instance. + */ +#define ESP_BLE_MESH_MODEL_AGG_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_AGG_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_AGG_CLI + * + * @brief Define a new Opcodes Aggregator Client model. + * + * @note If supported, the model shall be supported by the primary + * element and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique Opcodes Aggregator Client + * model user_data. + * + * @return New Opcodes Aggregator Client model instance. + */ +#define ESP_BLE_MESH_MODEL_AGG_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_AGG_CLI, \ + NULL, NULL, cli_data) + +/** Opcodes Aggregator Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Opcodes Aggregator Server model */ +} esp_ble_mesh_agg_srv_t; /*!< Opcodes Aggregator Server model context */ + +/** Parameters of Aggregator Item */ +typedef struct { + uint16_t length_format:1, /*!< 0: Length_Short; 1: Length_Long */ + length:15; /*!< Size of Opcode_And_Parameters field */ + const uint8_t *data; /*!< Opcode and parameters */ +} esp_ble_mesh_agg_item_t; /*!< Parameters of Aggregator Item */ + +/** Parameters of Opcodes Aggregator Sequence */ +typedef struct { + uint16_t element_addr; /*!< Element address */ + struct net_buf_simple *items; /*!< List of items with each item represented as an Aggregator Item */ +} esp_ble_mesh_agg_sequence_t; /*!< Parameters of Opcodes Aggregator Sequence */ + +/** + * @brief Opcodes Aggregator Client model message union + */ +typedef union { + esp_ble_mesh_agg_sequence_t agg_sequence; /*!< For ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE */ +} esp_ble_mesh_agg_client_msg_t; /*!< Opcodes Aggregator Client model message union */ + +/** Parameters of Opcodes Aggregator Status */ +typedef struct { + uint8_t status; /*!< Status of the most recent operation */ + uint16_t element_addr; /*!< Element Address */ + struct net_buf_simple *items; /*!< List of status items with each status item containing an unacknowledged access layer message or empty item (Optional) */ +} esp_ble_mesh_agg_status_t; /*!< Parameters of Opcodes Aggregator Status */ + +/** Result of sending Opcodes Aggregator Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_agg_client_send_cb_t; /*!< Result of sending Opcodes Aggregator Client messages */ + +/** + * @brief Opcodes Aggregator Client model received message union + */ +typedef union { + esp_ble_mesh_agg_status_t agg_status; /*!< For ESP_BLE_MESH_MODEL_OP_AGG_STATUS */ +} esp_ble_mesh_agg_client_recv_cb_t; /*!< Opcodes Aggregator Client model received message union */ + +/** Opcodes Aggregator Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events */ + /** Union of AGG Client callback */ + union { + esp_ble_mesh_agg_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_agg_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_agg_client_cb_param_t; /*!< Opcodes Aggregator Client model callback parameters */ + +/** This enum value is the event of Opcodes Aggregator Client model */ +typedef enum { + ESP_BLE_MESH_AGG_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_AGG_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_AGG_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_AGG_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_AGG_CLIENT_EVT_MAX, +} esp_ble_mesh_agg_client_cb_event_t; + +/** + * @brief Opcodes Aggregator Server model related context. + */ + +/** + * @brief Opcodes Aggregator Server model received message union + */ +typedef union { + esp_ble_mesh_agg_sequence_t agg_sequence; /*!< For ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE */ +} esp_ble_mesh_agg_server_recv_msg_t; /*!< Opcodes Aggregator Server model received message union */ + +/** Opcodes Aggregator Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + /** Union of AGG Server callback */ + union { + esp_ble_mesh_agg_server_recv_msg_t recv; /*!< Received message callback values */ + }; +} esp_ble_mesh_agg_server_cb_param_t; /*!< Opcodes Aggregator Server model callback parameters */ + +/** This enum value is the event of Opcodes Aggregator Server model */ +typedef enum { + ESP_BLE_MESH_AGG_SERVER_RECV_MSG_EVT, + ESP_BLE_MESH_AGG_SERVER_EVT_MAX, +} esp_ble_mesh_agg_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Opcodes Aggregator client and server model functions. + */ + +/** + * @brief Opcodes Aggregator Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_agg_client_cb_t)(esp_ble_mesh_agg_client_cb_event_t event, + esp_ble_mesh_agg_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Opcodes Aggregator Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_agg_client_callback(esp_ble_mesh_agg_client_cb_t callback); + +/** + * @brief Set the value of Opcodes Aggregator Server model state with the corresponding set message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Opcodes Aggregator Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_agg_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_agg_client_msg_t *msg); + +/** + * @brief Opcodes Aggregator Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_agg_server_cb_t)(esp_ble_mesh_agg_server_cb_event_t event, + esp_ble_mesh_agg_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Opcodes Aggregator Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_agg_server_callback(esp_ble_mesh_agg_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_AGG_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_brc_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_brc_model_api.h new file mode 100644 index 0000000000..e1d4d336e8 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_brc_model_api.h @@ -0,0 +1,322 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_BRC_MODEL_API_H_ +#define _ESP_BLE_MESH_BRC_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB1) +#define ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB2) +#define ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB3) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_ADD ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB4) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_REMOVE ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB5) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB6) +#define ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB7) +#define ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_LIST ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB8) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB9) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_LIST ESP_BLE_MESH_MODEL_OP_2(0x80, 0xBA) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_SIZE_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xBB) +#define ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_SIZE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xBC) + +/** @def ESP_BLE_MESH_MODEL_BRC_SRV + * + * @brief Define a new Bridge Configuration Server model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param srv_data Pointer to a unique Bridge Configuration Server + * model user_data. + * + * @return New Bridge Configuration Server model instance. + */ +#define ESP_BLE_MESH_MODEL_BRC_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BRC_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_BRC_CLI + * + * @brief Define a new Bridge Configuration Client model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique Bridge Configuration Client + * model user_data. + * + * @return New Bridge Configuration Client model instance. + */ +#define ESP_BLE_MESH_MODEL_BRC_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BRC_CLI, \ + NULL, NULL, cli_data) + +/** Parameters of subnet bridge table */ +typedef struct { + uint8_t bridge_direction; /*!< Allowed directions for the bridged traffic */ + uint8_t bridge_net_idx[3]; /*!< Two NetKey Indexes are packed into three octets */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_subnet_bridge_table_t; /*!< Entries of subnet bridge table */ + +#if CONFIG_BLE_MESH_BRC_SRV +/** Bridge Configuration Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Bridge Configuration Server model */ + + uint8_t subnet_bridge; /*!< Subnet Bridge state */ + uint16_t bridging_table_size; /*!< Bridging Table Size */ + + esp_ble_mesh_subnet_bridge_table_t bridge_table[CONFIG_BLE_MESH_MAX_BRIDGING_TABLE_ENTRY_COUNT]; /*!< Subnet Bridge table, used to storage bridging table entries */ +} esp_ble_mesh_brc_srv_t; /*!< Bridge Configuration Server model context */ +#endif + +/** Parameters of Subnet Bridge Set */ +typedef struct { + uint8_t subnet_bridge; /*!< New Subnet Bridge state */ +} esp_ble_mesh_subnet_bridge_set_t; /*!< Parameters of Subnet Bridge Set */ + +/** Parameters of Bridging Table Add */ +typedef struct { + uint8_t bridge_direction; /*!< Allowed directions for the bridged traffic */ + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_bridging_table_add_t; /*!< Parameters of Bridging Table Add */ + +/** Parameters of Bridging Table Remove */ +typedef struct { + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_bridging_table_remove_t; /*!< Parameters of Bridging Table Remove */ + +/** Parameters of Bridged Subnets Get */ +typedef struct { + uint16_t bridge_filter:2, /*!< Filter to be applied when reporting the set of pairs of NetKey Indexes */ + bridge_net_idx:12; /*!< NetKey Index of any of the subnets */ + uint8_t bridge_start_idx; /*!< Start offset in units of Bridging Table state entries */ +} esp_ble_mesh_bridged_subnets_get_t; /*!< Parameters of Bridged Subnets Get */ + +/** Parameters of Bridging Table Get */ +typedef struct { + uint16_t bridge_net_idx_1; /*!< NetKey Index of first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_start_idx; /*!< Start offset in units of Bridging Table state entries */ +} esp_ble_mesh_bridging_table_get_t; /*!< Parameters of Bridging Table Get */ + +/** + * @brief Bridge Configuration Client model message union + */ +typedef union { + esp_ble_mesh_bridged_subnets_get_t bridged_subnets_get; /*!< For ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET */ + esp_ble_mesh_bridging_table_get_t bridging_table_get; /*!< For ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET */ + esp_ble_mesh_subnet_bridge_set_t subnet_bridge_set; /*!< For ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_SET */ + esp_ble_mesh_bridging_table_add_t bridging_table_add; /*!< For ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_ADD */ + esp_ble_mesh_bridging_table_remove_t bridging_table_remove; /*!< For ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_REMOVE */ +} esp_ble_mesh_brc_client_msg_t; /*!< Bridge Configuration Client model message union */ + +/** Parameters of Subnet Bridge Status */ +typedef struct { + uint8_t subnet_bridge; /*!< Current Subnet Bridge state */ +} esp_ble_mesh_subnet_bridge_status_t; /*!< Parameters of Subnet Bridge Status */ + +/** Parameters of Bridging Table Status */ +typedef struct { + uint8_t status; /*!< Status Code for the requesting message */ + uint8_t bridge_direction; /*!< Allowed directions for the bridged traffic */ + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_bridging_table_status_t; /*!< Parameters of Bridging Table Status */ + +/** Bridged_Subnets_List entry format */ +typedef struct { + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ +} esp_ble_mesh_bridge_net_idx_pair_entry_t; /*!< Bridged_Subnets_List entry format */ + +/** Parameters of Bridged Subnets List */ +typedef struct { + uint16_t bridge_filter:2, /*!< Filter applied to the set of pairs of NetKey Indexes */ + bridge_net_idx:12; /*!< NetKey Index used for filtering or ignored */ + uint8_t bridge_start_idx; /*!< Start offset in units of bridges */ + + uint8_t bridged_entry_list_size; /*!< Num of pairs of NetKey Indexes */ + esp_ble_mesh_bridge_net_idx_pair_entry_t *net_idx_pair; /*!< Filtered set of N pairs of NetKey Indexes */ +} esp_ble_mesh_bridged_subnets_list_t; /*!< Parameters of Bridged Subnets List */ + +/** Bridged_Addresses_List entry format */ +typedef struct { + uint8_t bridge_direction; /*!< Allowed directions for bridged traffic */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +}esp_ble_mesh_bridged_addr_list_entry_t; /*!< Bridged_Addresses_List entry format */ + +/** Parameters of Bridging Table List */ +typedef struct { + uint8_t status; /*!< Status Code for the requesting message */ + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_start_idx; /*!< Start offset in units of Bridging Table state entries */ + uint16_t bridged_addr_list_size; /*!< Num of pairs of entry */ + esp_ble_mesh_bridged_addr_list_entry_t *bridged_addr_list; /*!< List of bridged addresses and allowed traffic directions */ +} esp_ble_mesh_bridging_table_list_t; /*!< Parameters of Bridging Table List */ + +/** Parameters of Bridging Table Size Status */ +typedef struct { + uint16_t bridging_table_size; /*!< Bridging Table Size state */ +} esp_ble_mesh_bridging_table_size_status_t; /*!< Parameters of Bridging Table Size Status */ + +/** + * @brief Bridge Configuration Client model received message union + */ +typedef union { + esp_ble_mesh_subnet_bridge_status_t subnet_bridge_status; /*!< ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_STATUS */ + esp_ble_mesh_bridging_table_status_t bridging_table_status; /*!< ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_STATUS */ + esp_ble_mesh_bridged_subnets_list_t bridged_subnets_list; /*!< ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_LIST */ + esp_ble_mesh_bridging_table_list_t bridging_table_list; /*!< ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_LIST */ + esp_ble_mesh_bridging_table_size_status_t bridging_table_size_status; /*!< ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_SIZE_STATUS */ +} esp_ble_mesh_brc_client_recv_cb_t;/*!< */ + +/** Result of sending Bridge Configuration Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_brc_client_send_cb_t; /*!< Result of sending Bridge Configuration Client messages */ + +/** Bridge Configuration Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of Bridge Configuration Client callback */ + union { + esp_ble_mesh_brc_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_brc_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_brc_client_cb_param_t; /*!< Bridge Configuration Client model callback parameters */ + +/** This enum value is the event of Bridge Configuration Client model */ +typedef enum { + ESP_BLE_MESH_BRC_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_BRC_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_BRC_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_BRC_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_BRC_CLIENT_EVT_MAX, +} esp_ble_mesh_brc_client_cb_event_t; + +/** + * @brief Bridge Configuration Server model related context. + */ +/** Parameters of Bridging Table Add */ +typedef struct { + uint8_t bridge_direction; /*!< Allowed directions for the bridged traffic */ + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_state_change_bridging_table_add_t; /*!< Parameters of Bridging Table Add */ + +/** Parameters of Bridging Table Remove */ +typedef struct { + uint16_t bridge_net_idx_1; /*!< NetKey Index of the first subnet */ + uint16_t bridge_net_idx_2; /*!< NetKey Index of the second subnet */ + uint16_t bridge_addr_1; /*!< Address of the node in the first subnet */ + uint16_t bridge_addr_2; /*!< Address of the node in the second subnet */ +} esp_ble_mesh_state_change_bridging_table_remove_t; /*!< Parameters of Bridging Table Remove */ + +/** + * @brief Bridge Configuration Server model state change value union + */ +typedef union { + /** + * The recv_op in ctx can be used to decide which state is changed. + */ + esp_ble_mesh_state_change_bridging_table_add_t bridging_table_add; /*!< Bridging Table Add */ + esp_ble_mesh_state_change_bridging_table_remove_t bridging_table_remove; /*!< Bridging Table Remove*/ +} esp_ble_mesh_brc_server_state_change_t; /*!< Bridge Configuration Server model state change value union */ + +/** + * @brief Bridge Configuration Server model callback value union + */ +typedef union { + esp_ble_mesh_brc_server_state_change_t state_change; /*!< For ESP_BLE_MESH_BRC_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_brc_server_cb_value_t; /*!< Bridge Configuration Server model callback value union */ + +/** Bridge Configuration Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_brc_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_brc_server_cb_param_t; /*!< Bridge Configuration Server model callback parameters */ + +/** This enum value is the event of Bridge Configuration Server model */ +typedef enum { + ESP_BLE_MESH_BRC_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_BRC_SERVER_EVT_MAX, +} esp_ble_mesh_brc_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Bridge Configuration client and server model functions. + */ + +/** + * @brief Bridge Configuration Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_brc_client_cb_t)(esp_ble_mesh_brc_client_cb_event_t event, + esp_ble_mesh_brc_client_cb_param_t *param); + +/** + * @brief Bridge Configuration Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_brc_server_cb_t)(esp_ble_mesh_brc_server_cb_event_t event, + esp_ble_mesh_brc_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Bridge Configuration Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_brc_client_callback(esp_ble_mesh_brc_client_cb_t callback); + +/** + * @brief Register BLE Mesh Bridge Configuration Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_brc_server_callback(esp_ble_mesh_brc_server_cb_t callback); + +/** + * @brief Get/Set the value of Bridge Configuration Server model state with the corresponding message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Bridge Configuration Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_brc_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_brc_client_msg_t *msg); +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_BRC_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_cm_data_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_cm_data_api.h new file mode 100644 index 0000000000..ed8d288244 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_cm_data_api.h @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_CM_DATA_API_H_ +#define _ESP_BLE_MESH_CM_DATA_API_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Definitions of the format of Extended_Model_Items indicator */ +#define ESP_BLE_MESH_MODEL_ITEM_SHORT 0 +#define ESP_BLE_MESH_MODEL_ITEM_LONG 1 + +/* The value of the Element_Offset field is mapped to an integer value. + * |----------------|-------------------| + * | Element_Offset | Represented Value | + * |----------------|-------------------| + * | 0 | 0 | + * | 1 | 1 | + * | 2 | 2 | + * | 3 | 3 | + * | 4 | -4 | + * | 5 | -3 | + * | 6 | -2 | + * | 7 | -1 | + * |----------------|-------------------| + */ + +/** Format of Extended Model Item */ +typedef struct { + /** Union of Extended Model Item */ + union { + uint8_t element_offset:3, /*!< Element address modifier, in the range -4 to 3. See above. */ + model_item_idx:5; /*!< Model Index, in the range 0 to 31 */ + /** Extended Model Item long format */ + struct { + int8_t element_offset; /*!< Element address modifier, in the range -128 to 127 */ + uint8_t model_item_idx; /*!< Model index, in the range 0 to 255 */ + } long_fmt; /*!< Extended Model Item long format */ + }; +} esp_ble_mesh_extended_model_item_t; /*!< Format of Extended Model Item */ + +/** Format of Model Item */ +typedef struct { + uint8_t corresponding_present:1, /*!< Corresponding_Group_ID field indicator */ + format:1, /*!< Format of Extended_Model_Items indicator */ + extended_items_count:6; /*!< Number of Extended Model Items in the Extended_Model_Items field */ + uint8_t corresponding_group_id; /*!< Corresponding group identifier */ + esp_ble_mesh_extended_model_item_t *const extended_model_items; /*!< List of Extended Model Items */ +} esp_ble_mesh_model_item_t; /*!< Format of Model Item */ + +/** Format of element of Composition Data Page 1 */ +typedef struct { + const uint8_t num_s; /*!< A count of SIG Models Items in this element */ + const uint8_t num_v; /*!< A count of Vendor Models Items in this element */ + + esp_ble_mesh_model_item_t *const model_items_s; /*!< A sequence of "num_s" SIG Model Items */ + esp_ble_mesh_model_item_t *const model_items_v; /*!< A sequence of "num_v" Vendor Model Items */ +} esp_ble_mesh_comp_1_elem_t; /*!< Format of element of Composition Data Page 1 */ + +/** Format of Composition Data Page 1 */ +typedef struct { + size_t element_count; /*!< Element count */ + esp_ble_mesh_comp_1_elem_t *elements; /*!< A sequence of element descriptions */ +} esp_ble_mesh_comp_1_t; /*!< Format of Composition Data Page 1 */ + +/** Format of Metadata entry */ +typedef struct { + uint16_t metadata_len; /*!< Size of the Metadata field */ + uint16_t metadata_id; /*!< Bluetooth assigned number for the Metadata Identifier */ + const uint8_t *metadata; /*!< Model’s metadata */ +} esp_ble_mesh_metadata_entry_t; /*!< Format of Metadata entry */ + +/** Format of Metadata item */ +typedef struct { + /** Union of model ID */ + union { + uint16_t model_id; /*!< Model ID */ + /** Vendor model identifier */ + struct { + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ + } vnd; /*!< Vendor model identifier */ + }; + uint8_t metadata_entries_num; /*!< Number of metadata entries */ + esp_ble_mesh_metadata_entry_t *const metadata_entries; /*!< List of model’s metadata */ +} esp_ble_mesh_metadata_item_t; /*!< Format of Metadata item */ + +/** Format of Metadata element of Models Metadata Page 0/128 */ +typedef struct { + const uint8_t items_num_s; /*!< Number of metadata items for SIG models in the element */ + const uint8_t items_num_v; /*!< Number of metadata items for Vendor models in the element */ + + esp_ble_mesh_metadata_item_t *const metadata_items_s; /*!< List of metadata items for SIG models in the element */ + esp_ble_mesh_metadata_item_t *const metadata_items_v; /*!< List of metadata items for Vendor models in the element */ +} esp_ble_mesh_metadata_elem_t; /*!< Format of Metadata element of Models Metadata Page 0/128 */ + +/** Format of the Models Metadata Page 0/128 */ +typedef struct { + size_t element_count; /*!< Element count */ + esp_ble_mesh_metadata_elem_t *elements; /*!< List of metadata for models for each element */ +} esp_ble_mesh_models_metadata_t; /*!< Format of the Models Metadata Page 0/128 */ + +/** + * @brief Register Composition Data Page 1. + * + * @param[in] comp: Pointer to Composition Data Page 1. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_comp_1_register(const esp_ble_mesh_comp_1_t *comp); + +/** + * @brief Register Models Metadata Page 0 or 128. + * + * @param[in] metadata: Pointer to Models Metadata Page 0 or 128. + * @param[in] metadata_page: Models Metadata Page number, i.e. 0 or 128. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_models_metadata_register(const esp_ble_mesh_models_metadata_t *metadata, + uint8_t metadata_page); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_CM_DATA_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_df_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_df_model_api.h new file mode 100644 index 0000000000..f03b0a00ce --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_df_model_api.h @@ -0,0 +1,746 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_DF_MODEL_API_H_ +#define _ESP_BLE_MESH_DF_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7B) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7C) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7D) +#define ESP_BLE_MESH_MODEL_OP_PATH_METRIC_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7E) +#define ESP_BLE_MESH_MODEL_OP_PATH_METRIC_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7F) +#define ESP_BLE_MESH_MODEL_OP_PATH_METRIC_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x80) +#define ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x81) +#define ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x82) +#define ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x83) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ADD ESP_BLE_MESH_MODEL_OP_2(0x80, 0x84) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEL ESP_BLE_MESH_MODEL_OP_2(0x80, 0x85) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x86) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_ADD ESP_BLE_MESH_MODEL_OP_2(0x80, 0x87) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_DEL ESP_BLE_MESH_MODEL_OP_2(0x80, 0x88) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x89) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8A) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8B) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8C) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8D) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8E) +#define ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x8F) +#define ESP_BLE_MESH_MODEL_OP_WANTED_LANES_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x90) +#define ESP_BLE_MESH_MODEL_OP_WANTED_LANES_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x91) +#define ESP_BLE_MESH_MODEL_OP_WANTED_LANES_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x92) +#define ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x93) +#define ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x94) +#define ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x95) +#define ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x96) +#define ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x97) +#define ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x98) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x99) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9A) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9B) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9C) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9D) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9E) +#define ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x9F) +#define ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA0) +#define ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA1) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_PATHS_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA2) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_PATHS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA3) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA4) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA5) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA6) +#define ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA7) +#define ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA8) +#define ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xA9) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xAB) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xAC) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xAD) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xAE) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0xAF) +#define ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0xB0) + +#define ESP_BLE_MESH_PATH_DISC_INTERVAL_5_SEC 0 +#define ESP_BLE_MESH_PATH_DISC_INTERVAL_30_SEC 1 + +#define ESP_BLE_MESH_LANE_DISC_GUARD_INTERVAL_2_SEC 0 +#define ESP_BLE_MESH_LANE_DISC_GUARD_INTERVAL_10_SEC 1 + +#define ESP_BLE_MESH_DIRECTED_PUB_POLICY_MANAGED_FLOODING 0x00 +#define ESP_BLE_MESH_DIRECTED_PUB_POLICY_DIRECTED_FORWARDING 0x01 + +#define ESP_BLE_MESH_GET_FILTER_MASK(fp, nfp, pom, dm) \ + (((dm) << 3) | ((pom) << 2) | ((nfp) << 1) | (fp)) + +/** @def ESP_BLE_MESH_MODEL_DF_SRV + * + * @brief Define a new Directed Forwarding Configuration Server model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param srv_data Pointer to a unique Directed Forwarding Configuration + * Server model user_data. + * + * @return New Directed Forwarding Configuration Server model instance. + */ +#define ESP_BLE_MESH_MODEL_DF_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DF_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_DF_CLI + * + * @brief Define a new Directed Forwarding Configuration Client model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique Directed Forwarding Configuration + * Client model user_data. + * + * @return New Directed Forwarding Configuration Client model instance. + */ +#define ESP_BLE_MESH_MODEL_DF_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DF_CLI, \ + NULL, NULL, cli_data) + +/** Directed Forwarding Configuration Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Directed Forwarding Configuration Server model */ + + uint8_t directed_net_transmit; /*!< Directed Network Transmit state */ + uint8_t directed_relay_retransmit; /*!< Directed Relay Retransmit state */ + + int8_t default_rssi_threshold; /*!< Default RSSI Threshold state */ + uint8_t rssi_margin; /*!< RSSI Margin state */ + + uint16_t directed_node_paths; /*!< Directed Node Paths state */ + uint16_t directed_relay_paths; /*!< Directed Relay Paths state */ + uint16_t directed_proxy_paths; /*!< Directed Proxy Paths state */ + uint16_t directed_friend_paths; /*!< Directed Friend Paths state */ + + uint16_t path_monitor_interval; /*!< Path Monitoring Interval state */ + uint16_t path_disc_retry_interval; /*!< Path Discovery Retry Interval state */ + uint8_t path_disc_interval:1, /*!< Path Discovery Interval state */ + lane_disc_guard_interval:1; /*!< Lane Discovery Guard Interval state */ + + uint8_t directed_ctl_net_transmit; /*!< Directed Control Network Transmit state */ + uint8_t directed_ctl_relay_retransmit; /*!< Directed Control Relay Retransmit state */ +} esp_ble_mesh_df_srv_t; + +/** Parameters of Directed Control Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_directed_control_get_t; + +/** Parameters of Directed Control Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t directed_forwarding; /*!< New Directed Forwarding state */ + uint8_t directed_relay; /*!< New Directed Relay state */ + uint8_t directed_proxy; /*!< New Directed Proxy state */ + uint8_t directed_proxy_use_default; /*!< New Directed Proxy Use Directed Default state or value to ignore */ + uint8_t directed_friend; /*!< New Directed Friend state or value to ignore */ +} esp_ble_mesh_directed_control_set_t; + +/** Parameters of Path Metric Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_path_metric_get_t; + +/** Parameters of Path Metric Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t path_metric_type:3, /*!< New Path Metric Type state */ + path_lifetime:2; /*!< New Path Lifetime state */ +} esp_ble_mesh_path_metric_set_t; + +/** Parameters of Discovery Table Capabilities Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_discovery_table_caps_get_t; + +/** Parameters of Discovery Table Capabilities Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t max_concurr_init; /*!< New Max Concurrent Init state */ +} esp_ble_mesh_discovery_table_caps_set_t; + +/** Parameters of Forwarding Table Add. */ +typedef struct { + uint16_t net_idx:12, /*!< NetKey Index */ + unicast_dst:1, /*!< Indicates whether or not the destination of the path is a unicast address */ + bw_path_validated:1; /*!< Indicates whether or not the backward path has been validated */ + esp_ble_mesh_uar_t path_origin; /*!< Unicast address range of the Path Origin */ + /** Path target address */ + union { + esp_ble_mesh_uar_t path_target; /*!< Unicast address range of the Path Target */ + uint16_t multicast_dst; /*!< Multicast destination address */ + }; + uint16_t bearer_twd_path_origin; /*!< Index of the bearer toward the Path Origin */ + uint16_t bearer_twd_path_target; /*!< Index of the bearer toward the Path Target */ +} esp_ble_mesh_forwarding_table_add_t; /*!< Parameters of Forwarding Table Add */ + +/** Parameters of Forwarding Table Delete. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ +} esp_ble_mesh_forwarding_table_delete_t; + +/** Parameters of Forwarding Table Dependents Add. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + uint8_t dep_origin_uar_list_size; /*!< Number of entries in the Dependent_Origin_Unicast_Addr_Range_List field */ + uint8_t dep_target_uar_list_size; /*!< Number of entries in the Dependent_Target_Unicast_Addr_Range_List field */ + esp_ble_mesh_uar_t *dep_origin_uar_list; /*!< List of the unicast address ranges of the dependent nodes of the Path Origin */ + esp_ble_mesh_uar_t *dep_target_uar_list; /*!< List of the unicast address ranges of the dependent nodes of the Path Target */ +} esp_ble_mesh_forwarding_table_deps_add_t; + +/** Parameters of Forwarding Table Dependents Delete. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + uint8_t dep_origin_list_size; /*!< Number of entries in the Dependent_Origin_List field */ + uint8_t dep_target_list_size; /*!< Number of entries in the Dependent_Target_List field */ + uint16_t *dep_origin_list; /*!< List of the primary element addresses of the dependent nodes of the Path Origin */ + uint16_t *dep_target_list; /*!< List of the primary element addresses of the dependent nodes of the Path Target */ +} esp_ble_mesh_forwarding_table_deps_delete_t; + +/** Parameters of Forwarding Table Entries Count Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_forwarding_table_entries_cnt_get_t; + +/** Parameters of Forwarding Table Entries Get. */ +typedef struct { + uint16_t net_idx:12, /*!< NetKey Index */ + filter_mask:4; /*!< Filter to be applied to the Forwarding Table entries */ + uint16_t start_index; /*!< Start offset to read in units of Forwarding Table entries */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + + bool include_id; /*!< Indicate whether or not the Forwarding Table Update Identifier is present */ + uint16_t update_id; /*!< Last saved Forwarding Table Update Identifier (Optional) */ +} esp_ble_mesh_forwarding_table_entries_get_t; + +/** Parameters of Forwarding Table Dependents Get. */ +typedef struct { + uint16_t net_idx:12, /*!< NetKey Index */ + dep_list_mask:2, /*!< Filter applied to the lists of unicast address ranges for dependent nodes */ + fixed_path_flag:1; /*!< Indicate whether or not to return the unicast address ranges of dependent nodes in a fixed path entry */ + uint16_t start_index; /*!< Start offset in units of unicast address ranges */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + + bool include_id; /*!< Indicate whether or not the Forwarding Table Update Identifier is present */ + uint16_t update_id; /*!< Last saved Forwarding Table Update Identifier (Optional) */ +} esp_ble_mesh_forwarding_table_deps_get_t; + +/** Parameters of Wanted Lanes Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_wanted_lanes_get_t; + +/** Parameters of Wanted Lanes Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t wanted_lanes; /*!< New Wanted Lanes state */ +} esp_ble_mesh_wanted_lanes_set_t; + +/** Parameters of Two Way Path Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_two_way_path_get_t; + +/** Parameters of Two Way Path Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t two_way_path:1; /*!< Two way path flag */ +} esp_ble_mesh_two_way_path_set_t; + +/** Parameters of Path Echo Interval Get. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ +} esp_ble_mesh_path_echo_interval_get_t; + +/** Parameters of Path Echo Interval Set. */ +typedef struct { + uint16_t net_idx; /*!< NetKey Index */ + uint8_t unicast_echo_interval; /*!< New Unicast Echo Interval state or indication of no state change */ + uint8_t multicast_echo_interval; /*!< New Multicast Echo Interval state or indication of no state change */ +} esp_ble_mesh_path_echo_interval_set_t; + +/** Parameters of Directed Network Transmit Set. */ +typedef struct { + uint8_t net_transmit; /*!< New Directed Network Transmit state */ +} esp_ble_mesh_directed_net_transmit_set_t; + +/** Parameters of Directed Relay Retransmit Set. */ +typedef struct { + uint8_t relay_retransmit; /*!< New Directed Relay Retransmit state */ +} esp_ble_mesh_directed_relay_retransmit_set_t; + +/** Parameters of RSSI Threshold Set. */ +typedef struct { + uint8_t rssi_margin; /*!< New RSSI Margin state */ +} esp_ble_mesh_rssi_threshold_set_t; + +/** Parameters of Directed Publish Policy Get. */ +typedef struct { + uint16_t element_addr; /*!< Address of the element */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_directed_publish_policy_get_t; + +/** Parameters of Directed Publish Policy Set. */ +typedef struct { + uint8_t direct_pub_policy; /*!< New Directed Publish Policy state */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_directed_publish_policy_set_t; + +/** Parameters of Path Discovery Timing Control Set. */ +typedef struct { + uint16_t path_monitor_interval; /*!< New Path Monitoring Interval state */ + uint16_t path_disc_retry_interval; /*!< New Path Discovery Retry Interval state */ + uint8_t path_disc_interval:1, /*!< New Path Discovery Interval state */ + lane_disc_guard_interval:1; /*!< New Lane Discovery Guard Interval state */ +} esp_ble_mesh_path_discovery_timing_ctl_set_t; + +/** Parameters of Directed Control Network Transmit Set. */ +typedef struct { + uint8_t net_transmit; /*!< New Directed Control Network Transmit Count state */ +} esp_ble_mesh_directed_ctl_net_transmit_set_t; + +/** Parameters of Directed Control Relay Retransmit Set. */ +typedef struct { + uint8_t relay_retransmit; /*!< New Directed Control Relay Retransmit Count state */ +} esp_ble_mesh_directed_ctl_relay_retransmit_set_t; + +/** + * @brief Directed Forwarding Configuration Client model get message union + */ +typedef union { + esp_ble_mesh_directed_control_get_t directed_control_get; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_GET */ + esp_ble_mesh_path_metric_get_t path_metric_get; /*!< For ESP_BLE_MESH_MODEL_OP_PATH_METRIC_GET */ + esp_ble_mesh_discovery_table_caps_get_t disc_table_caps_get; /*!< For ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_GET */ + esp_ble_mesh_forwarding_table_entries_cnt_get_t forwarding_table_entries_cnt_get; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_GET */ + esp_ble_mesh_forwarding_table_entries_get_t forwarding_table_entries_get; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET */ + esp_ble_mesh_forwarding_table_deps_get_t forwarding_table_deps_get; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET */ + esp_ble_mesh_wanted_lanes_get_t wanted_lanes_get; /*!< For ESP_BLE_MESH_MODEL_OP_WANTED_LANES_GET */ + esp_ble_mesh_two_way_path_get_t two_way_path_get; /*!< For ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_GET */ + esp_ble_mesh_path_echo_interval_get_t path_echo_interval_get; /*!< For ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_GET */ + esp_ble_mesh_directed_publish_policy_get_t directed_pub_policy_get; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_GET */ +} esp_ble_mesh_df_client_get_t; + +/** + * @brief Directed Forwarding Configuration Client model set message union + */ +typedef union { + esp_ble_mesh_directed_control_set_t directed_control_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET */ + esp_ble_mesh_path_metric_set_t path_metric_set; /*!< For ESP_BLE_MESH_MODEL_OP_PATH_METRIC_SET */ + esp_ble_mesh_discovery_table_caps_set_t disc_table_caps_set; /*!< For ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_SET */ + esp_ble_mesh_forwarding_table_add_t forwarding_table_add; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ADD */ + esp_ble_mesh_forwarding_table_delete_t forwarding_table_del; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEL */ + esp_ble_mesh_forwarding_table_deps_add_t forwarding_table_deps_add; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_ADD */ + esp_ble_mesh_forwarding_table_deps_delete_t forwarding_table_deps_del; /*!< For ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_DEL */ + esp_ble_mesh_wanted_lanes_set_t wanted_lanes_set; /*!< For ESP_BLE_MESH_MODEL_OP_WANTED_LANES_SET */ + esp_ble_mesh_two_way_path_set_t two_way_path_set; /*!< For ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_SET */ + esp_ble_mesh_path_echo_interval_set_t path_echo_interval_set; /*!< For ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_SET */ + esp_ble_mesh_directed_net_transmit_set_t directed_net_transmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_SET */ + esp_ble_mesh_directed_relay_retransmit_set_t directed_relay_retransmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_SET */ + esp_ble_mesh_rssi_threshold_set_t rssi_threshold_set; /*!< For ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_SET */ + esp_ble_mesh_directed_publish_policy_set_t directed_pub_policy_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_SET */ + esp_ble_mesh_path_discovery_timing_ctl_set_t path_disc_timing_ctl_set; /*!< For ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_SET */ + esp_ble_mesh_directed_ctl_net_transmit_set_t directed_ctl_net_transmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_SET */ + esp_ble_mesh_directed_ctl_relay_retransmit_set_t directed_ctl_relay_retransmit_set; /*!< For ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_SET */ +} esp_ble_mesh_df_client_set_t; + +/** Parameters of Directed Control Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t directed_forwarding; /*!< Current Directed Forwarding state */ + uint8_t directed_relay; /*!< Current Directed Relay state */ + uint8_t directed_proxy; /*!< Current Directed Proxy state */ + uint8_t directed_proxy_use_default; /*!< Current Directed Proxy Use Directed Default state or 0xFF */ + uint8_t directed_friend; /*!< Current Directed Friend state */ +} esp_ble_mesh_directed_control_status_t; + +/** Parameters of Path Metric Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t path_metric_type:3, /*!< Current Path Metric Type state */ + path_lifetime:2; /*!< Current Path Lifetime state */ +} esp_ble_mesh_path_metric_status_t; + +/** Parameters of Discovery Table Capabilities Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t max_concurr_init; /*!< Current Max Concurrent Init state */ + uint8_t max_disc_entries; /*!< Max Discovery Table Entries Count state */ +} esp_ble_mesh_discovery_table_caps_status_t; + +/** Parameters of Forwarding Table Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ +} esp_ble_mesh_forwarding_table_status_t; + +/** Parameters of Forwarding Table Dependent Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ +} esp_ble_mesh_forwarding_table_deps_status_t; + +/** Parameters of Forwarding Table Entries Count Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint16_t update_id; /*!< Current Forwarding Table Update Identifier state */ + uint16_t fixed_entry_cnt; /*!< Number of fixed path entries in the Forwarding Table */ + uint16_t non_fixed_entry_cnt; /*!< Number of non-fixed path entries in the Forwarding Table */ +} esp_ble_mesh_forwarding_table_entries_cnt_status_t; + +/** Parameters of Forwarding Table Entry. */ +typedef struct { + uint16_t fixed_path_flag:1, /*!< Indicates whether the table entry is a fixed path entry or a non-fixed path entry */ + unicast_dst_flag:1, /*!< Indicates whether or not the destination of the path is a unicast address */ + bw_path_validated_flag:1, /*!< Indicates whether or not the backward path has been validated */ + bearer_twd_path_origin_ind:1, /*!< Indicates the presence or absence of the Bearer_Toward_Path_Origin field */ + bearer_twd_path_target_ind:1, /*!< Indicates the presence or absence of the Bearer_Toward_Path_Target field */ + dep_origin_list_size_ind:2, /*!< Indicates the size of the Dependent_Origin_List field */ + dep_target_list_size_ind:2; /*!< Indicates the size of the Dependent_Target_List field */ + + /* Only for non-fixed path entry */ + uint8_t lane_counter; /*!< Number of lanes in the path */ + uint16_t path_remaining_time; /*!< Path lifetime remaining */ + uint8_t path_origin_forward_number; /*!< Forwarding number of the Path Origin */ + + /* For fixed path entry and non-fixed path entry */ + esp_ble_mesh_uar_t path_origin; /*!< Path Origin unicast address range */ + uint16_t dep_origin_list_size; /*!< Current number of entries in the list of dependent nodes of the Path Origin */ + uint16_t bearer_twd_path_origin; /*!< Index of the bearer toward the Path Origin */ + esp_ble_mesh_uar_t path_target; /*!< Path Target unicast address range */ + uint16_t multicast_dst; /*!< Multicast destination address */ + uint16_t dep_target_list_size; /*!< Current number of entries in the list of dependent nodes of the Path Target */ + uint16_t bearer_twd_path_target; /*!< Index of the bearer toward the Path Target */ +} esp_ble_mesh_forwarding_table_entry_t; + +/** Parameters of Forwarding Table Entries Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx:12, /*!< NetKey Index */ + filter_mask:4; /*!< Filter applied to the Forwarding Table entries */ + uint16_t start_index; /*!< Start offset in units of Forwarding Table entries */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + + bool include_id; /*!< Indicate whether or not the Forwarding Table Update Identifier is present */ + uint16_t update_id; /*!< Current Forwarding Table Update Identifier state */ + + uint8_t entry_list_size; /*!< Current number of entries in the list of Forwarding Table entries */ + esp_ble_mesh_forwarding_table_entry_t *entry_list; /*!< List of Forwarding Table entries */ +} esp_ble_mesh_forwarding_table_entries_status_t; + +/** Parameters of Forwarding Table Dependents Get Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx:12, /*!< NetKey Index */ + dep_list_mask:2, /*!< Filter applied to the lists of unicast address ranges for dependent nodes */ + fixed_path_flag:1; /*!< Flag indicating whether or not to return the unicast address ranges of dependent nodes in a fixed path entry */ + uint16_t start_index; /*!< Start offset in units of unicast address ranges */ + uint16_t path_origin; /*!< Primary element address of the Path Origin */ + uint16_t dst; /*!< Destination address */ + + bool include_id; /*!< Indicate whether or not the Forwarding Table Update Identifier is present */ + uint16_t update_id; /*!< Current Forwarding Table Update Identifier state */ + + uint8_t dep_origin_uar_list_size; /*!< Number of unicast address ranges in the Dependent_Origin_Unicast_Addr_Range_List field */ + uint8_t dep_target_uar_list_size; /*!< Number of unicast address ranges in the Dependent_Target_Unicast_Addr_Range_List field */ + esp_ble_mesh_uar_t *dep_origin_uar_list; /*!< List of unicast address ranges of dependent nodes of the Path Origin */ + esp_ble_mesh_uar_t *dep_target_uar_list; /*!< List of unicast address ranges of dependent nodes of the Path Target */ +} esp_ble_mesh_forwarding_table_deps_get_status_t; + +/** Parameters of Wanted Lanes Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t wanted_lanes; /*!< Current Wanted Lanes state */ +} esp_ble_mesh_wanted_lanes_status_t; + +/** Parameters of Two Way Path Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t two_way_path; /*!< Current Two Way Path state */ +} esp_ble_mesh_two_way_path_status_t; + +/** Parameters of Path Echo Interval Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint16_t net_idx; /*!< NetKey Index */ + uint8_t unicast_echo_interval; /*!< Current Unicast Echo Interval state */ + uint8_t multicast_echo_interval; /*!< Current Multicast Echo Interval state */ +} esp_ble_mesh_path_echo_interval_status_t; + +/** Parameters of Directed Network Transmit Status. */ +typedef struct { + uint8_t net_transmit; /*!< Current Directed Network Transmit state */ +} esp_ble_mesh_directed_net_transmit_status_t; + +/** Parameters of Directed Relay Retransmit Status. */ +typedef struct { + uint8_t relay_retransmit; /*!< Current Directed Relay Retransmit state */ +} esp_ble_mesh_directed_relay_retransmit_status_t; + +/** Parameters of RSSI Threshold Status. */ +typedef struct { + uint8_t default_rssi_threshold; /*!< Default RSSI Threshold state */ + uint8_t rssi_margin; /*!< Current RSSI Margin state */ +} esp_ble_mesh_rssi_threshold_status_t; + +/** Parameters of Directed Paths Status. */ +typedef struct { + uint16_t directed_node_paths; /*!< Directed Node Paths state */ + uint16_t directed_relay_paths; /*!< Directed Relay Paths state */ + uint16_t directed_proxy_paths; /*!< Directed Proxy Paths state */ + uint16_t directed_friend_paths; /*!< Directed Friend Paths state */ +} esp_ble_mesh_directed_paths_status_t; + +/** Parameters of Directed Publish Policy Status. */ +typedef struct { + uint8_t status; /*!< Status code for the requesting message */ + uint8_t directed_pub_policy; /*!< Current Directed Publish Policy state */ + uint16_t element_addr; /*!< Address of the element */ + uint16_t company_id; /*!< Company ID */ + uint16_t model_id; /*!< Model ID */ +} esp_ble_mesh_directed_pub_policy_status_t; + +/** Parameters of Path Discovery Timing Control Status. */ +typedef struct { + uint16_t path_monitor_interval; /*!< Current Path Monitoring Interval state */ + uint16_t path_disc_retry_interval; /*!< Current Path Discovery Retry Interval state */ + uint8_t path_disc_interval:1, /*!< Current Path Discovery Interval state */ + lane_disc_guard_interval:1; /*!< Current Lane Discovery Guard Interval state */ +} esp_ble_mesh_path_disc_timing_ctl_status_cb_t; + +/** Parameters of Directed Control Network Transmit Status. */ +typedef struct { + uint8_t net_transmit; /*!< Current Directed Control Network Transmit state */ +} esp_ble_mesh_directed_ctl_net_transmit_status_t; + +/** Parameters of Directed Control Relay Retransmit Status. */ +typedef struct { + uint8_t relay_retransmit; /*!< Current Directed Control Relay Retransmit state */ +} esp_ble_mesh_directed_ctl_relay_retransmit_status_t; + +/** Result of sending Directed Forwarding Configuration Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_df_client_send_cb_t; + +/** + * @brief Directed Forwarding Configuration Client model received message union + */ +typedef union { + esp_ble_mesh_directed_control_status_t directed_control_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_STATUS */ + esp_ble_mesh_path_metric_status_t path_metric_status; /*!< ESP_BLE_MESH_MODEL_OP_PATH_METRIC_STATUS */ + esp_ble_mesh_discovery_table_caps_status_t disc_table_caps_status; /*!< ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_STATUS */ + esp_ble_mesh_forwarding_table_status_t forwarding_table_status; /*!< ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_STATUS */ + esp_ble_mesh_forwarding_table_deps_status_t forwarding_table_deps_status; /*!< ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_STATUS */ + esp_ble_mesh_forwarding_table_entries_cnt_status_t forwarding_table_entries_cnt_status; /*!< ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_STATUS */ + esp_ble_mesh_forwarding_table_entries_status_t forwarding_table_entries_status; /*!< ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_STATUS */ + esp_ble_mesh_forwarding_table_deps_get_status_t forwarding_table_deps_get_status; /*!< ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET_STATUS */ + esp_ble_mesh_wanted_lanes_status_t wanted_lanes_status; /*!< ESP_BLE_MESH_MODEL_OP_WANTED_LANES_STATUS */ + esp_ble_mesh_two_way_path_status_t two_way_path_status; /*!< ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_STATUS */ + esp_ble_mesh_path_echo_interval_status_t path_echo_interval_status; /*!< ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_STATUS */ + esp_ble_mesh_directed_net_transmit_status_t directed_net_transmit_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_STATUS */ + esp_ble_mesh_directed_relay_retransmit_status_t directed_relay_retransmit_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_STATUS */ + esp_ble_mesh_rssi_threshold_status_t rssi_threshold_status; /*!< ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_STATUS */ + esp_ble_mesh_directed_paths_status_t directed_paths_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_PATHS_STATUS */ + esp_ble_mesh_directed_pub_policy_status_t directed_pub_policy_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_STATUS */ + esp_ble_mesh_path_disc_timing_ctl_status_cb_t path_disc_timing_ctl_status; /*!< ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_STATUS */ + esp_ble_mesh_directed_ctl_net_transmit_status_t directed_ctl_net_transmit_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_STATUS */ + esp_ble_mesh_directed_ctl_relay_retransmit_status_t directed_ctl_relay_retransmit_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_STATUS */ +} esp_ble_mesh_df_client_recv_cb_t; + +/** Directed Forwarding Configuration Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of DF Client callback */ + union { + esp_ble_mesh_df_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_df_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_df_client_cb_param_t; + +/** This enum value is the event of Directed Forwarding Configuration Client model */ +typedef enum { + ESP_BLE_MESH_DF_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_DF_CLIENT_RECV_GET_RSP_EVT, + ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT, + ESP_BLE_MESH_DF_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_DF_CLIENT_EVT_MAX, +} esp_ble_mesh_df_client_cb_event_t; + +/** + * @brief Directed Forwarding Configuration Server model related context. + */ + +/** + * @brief Directed Forwarding Configuration Server model state change value union + */ +typedef union { + uint8_t dummy; /*!< Event not used currently */ +} esp_ble_mesh_df_server_state_change_t; + +typedef enum { + ESP_BLE_MESH_DF_TABLE_ACT_EMPTY, + ESP_BLE_MESH_DF_TABLE_ADD, + ESP_BLE_MESH_DF_TABLE_REMOVE, + ESP_BLE_MESH_DF_TABLE_ENTRY_CHANGE, + ESP_BLE_MESH_DF_TABLE_ACT_MAX_LIMIT, +} esp_ble_mesh_df_table_action_t; + +/** Parameters of directed forwarding table entry change */ +typedef struct { + esp_ble_mesh_df_table_action_t action; /*!< Action of directed forarding table */ + /** Union of directed forwarding table information */ + union { + /** Structure of directed forwarding table add and remove */ + struct { + esp_ble_mesh_uar_t path_origin; /*!< Primary element address of the Path Origin */ + esp_ble_mesh_uar_t path_target; /*!< Primary element address of the Path Target */ + + esp_ble_mesh_uar_t *dep_origin_data; /*!< List of the primary element addresses of the dependent nodes of the Path Origin */ + uint32_t dep_origin_num; /*!< Number of entries in the Dependent_Origin_Listfield of the message */ + + esp_ble_mesh_uar_t *dep_target_data; /*!< List of the primary element addresses of the dependent nodes of the Path Target */ + uint32_t dep_target_num; /*!< Number of entries in the Dependent_Target_List field of the message */ + + uint8_t fixed_path:1, /*!< Indicates whether the table entry is a fixed path entry or a non-fixed path entry */ + bw_path_validate:1, /*!< Indicates whether or not the backward path has been validated */ + path_not_ready:1; /*!< Flag indicating whether or not the path is ready for use */ + + uint8_t forward_number; /*!< Forwarding number of the Path Origin; If the entry is associated with a fixed path, the value is 0 */ + + uint8_t lane_counter; /*!< Number of lanes discovered; if the entry is associated with a fixed path, the value is 1.*/ + } df_table_entry_add_remove; /*!< Structure of directed forwarding table add and remove */ + /** Structure of directed forwarding table entry change */ + struct { + uint8_t dummy; /*!< Event not used currently */ + } df_table_entry_change; /*!< Directed forwarding table entry change */ + } df_table_info; /*!< Directed forwarding table information */ +} esp_ble_mesh_df_server_table_change_t; /*!< Structure of directed forwarding table entry change */ + +/** + * @brief Directed Forwarding Configuration Server model callback value union + */ +typedef union { + esp_ble_mesh_df_server_state_change_t state_change; /*!< For ESP_BLE_MESH_DF_SERVER_STATE_CHANGE_EVT */ + esp_ble_mesh_df_server_table_change_t table_change; /*!< For ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT */ +} esp_ble_mesh_df_server_cb_value_t; + +/** Directed Forwarding Configuration Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_df_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_df_server_cb_param_t; + +/** This enum value is the event of Directed Forwarding Configuration Server model */ +typedef enum { + ESP_BLE_MESH_DF_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT, + ESP_BLE_MESH_DF_SERVER_EVT_MAX, +} esp_ble_mesh_df_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Directed Forwarding Configuration client and server model functions. + */ + +/** + * @brief Directed Forwarding Configuration Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_df_client_cb_t)(esp_ble_mesh_df_client_cb_event_t event, + esp_ble_mesh_df_client_cb_param_t *param); + +/** + * @brief Directed Forwarding Configuration Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_df_server_cb_t)(esp_ble_mesh_df_server_cb_event_t event, + esp_ble_mesh_df_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Directed Forwarding Configuration Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_df_client_callback(esp_ble_mesh_df_client_cb_t callback); + +/** + * @brief Register BLE Mesh Directed Forwarding Configuration Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_df_server_callback(esp_ble_mesh_df_server_cb_t callback); + +/** + * @brief Get the value of Directed Forwarding Configuration Server model state with the corresponding get message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] get: Pointer to a union, each kind of opcode corresponds to one structure inside. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_df_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_get_t *get); + +/** + * @brief Set the value of Directed Forwarding Configuration Server model state with the corresponding set message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] set: Pointer to a union, each kind of opcode corresponds to one structure inside. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_df_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_set_t *set); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_DF_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_lcd_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_lcd_model_api.h new file mode 100644 index 0000000000..63d7c18e61 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_lcd_model_api.h @@ -0,0 +1,211 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_LCD_MODEL_API_H_ +#define _ESP_BLE_MESH_LCD_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x74) +#define ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x75) +#define ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x76) +#define ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x77) + +/** @def ESP_BLE_MESH_MODEL_LCD_SRV + * + * @brief Define a new Large Composition Data Server model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param srv_data Pointer to a unique Large Composition Data Server model user_data. + * + * @return New Large Composition Data Server model instance. + */ +#define ESP_BLE_MESH_MODEL_LCD_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LCD_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_LCD_CLI + * + * @brief Define a new Large Composition Data Client model. + * + * @note If supported, the model shall be supported by the primary element + * and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique Large Composition Data Client model user_data. + * + * @return New Large Composition Data Client model instance. + */ +#define ESP_BLE_MESH_MODEL_LCD_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LCD_CLI, \ + NULL, NULL, cli_data) + +/** Large Composition Data Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Large Composition Data Server model */ +} esp_ble_mesh_lcd_srv_t; + +/** Parameters of Large Composition Data Get */ +typedef struct { + uint8_t page; /*!< Page number of the Composition Data */ + uint16_t offset; /*!< Offset within the page */ +} esp_ble_mesh_large_comp_data_get_t; + +/** Parameters of Models Metadata Get */ +typedef struct { + uint8_t metadata_page; /*!< Page number of the Models Metadata */ + uint16_t offset; /*!< Offset within the page */ +} esp_ble_mesh_models_metadata_get_t; + +/** + * @brief Large Composition Data Client model message union + */ +typedef union { + esp_ble_mesh_large_comp_data_get_t large_comp_data_get; /*!< For ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_GET */ + esp_ble_mesh_models_metadata_get_t models_metadata_get; /*!< For ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_GET */ +} esp_ble_mesh_lcd_client_msg_t; + +/** Parameters of Large Composition Data Status */ +typedef struct { + uint8_t page; /*!< Page number of the Composition Data */ + uint16_t offset; /*!< Offset within the page */ + uint16_t total_size; /*!< Total size of the page */ + struct net_buf_simple *data; /*!< Composition Data for the identified portion of the page */ +} esp_ble_mesh_large_comp_data_status_t; + +/** Parameters of Models Metadata Data Status */ +typedef struct { + uint8_t metadata_page; /*!< Page number of the Models Metadata */ + uint16_t offset; /*!< Offset within the page */ + uint16_t total_size; /*!< Total size of the page */ + struct net_buf_simple *data; /*!< Models Metadata for the identified portion of the page */ +} esp_ble_mesh_models_metadata_status_t; + +/** Result of sending Large Composition Data Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_lcd_client_send_cb_t; + +/** + * @brief Large Composition Data Client model received message union + */ +typedef union { + esp_ble_mesh_large_comp_data_status_t large_comp_data_status; /*!< For ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_STATUS */ + esp_ble_mesh_models_metadata_status_t models_metadata_status; /*!< For ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_STATUS */ +} esp_ble_mesh_lcd_client_recv_cb_t; + +/** Large Composition Data Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of LCD Client callback */ + union { + esp_ble_mesh_lcd_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_lcd_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_lcd_client_cb_param_t; /*!< Large Composition Data Client model callback parameters */ + +/** This enum value is the event of Large Composition Data Client model */ +typedef enum { + ESP_BLE_MESH_LCD_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_LCD_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_LCD_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_LCD_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_LCD_CLIENT_EVT_MAX, +} esp_ble_mesh_lcd_client_cb_event_t; + +/** + * @brief Large Composition Data Server model related context. + */ + +/** + * @brief Large Composition Data Server model state change value union + */ +typedef union { + uint8_t dummy; /*!< Event not used currently */ +} esp_ble_mesh_lcd_server_state_change_t; + +/** + * @brief Large Composition Data Server model callback value union + */ +typedef union { + esp_ble_mesh_lcd_server_state_change_t state_change; /*!< For ESP_BLE_MESH_LCD_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_lcd_server_cb_value_t; + +/** Large Composition Data Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_lcd_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_lcd_server_cb_param_t; + +/** This enum value is the event of Large Composition Data Server model */ +typedef enum { + ESP_BLE_MESH_LCD_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_LCD_SERVER_EVT_MAX, +} esp_ble_mesh_lcd_server_cb_event_t; + +/** + * @brief Large Composition Data client and server model functions. + */ + +/** + * @brief Large Composition Data Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_lcd_client_cb_t)(esp_ble_mesh_lcd_client_cb_event_t event, + esp_ble_mesh_lcd_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Large Composition Data Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_lcd_client_callback(esp_ble_mesh_lcd_client_cb_t callback); + +/** + * @brief Get the value of Large Composition Data Server model state with the corresponding get message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Large Composition Data Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_lcd_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_lcd_client_msg_t *msg); + +/** + * @brief Large Composition Data Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_lcd_server_cb_t)(esp_ble_mesh_lcd_server_cb_event_t event, + esp_ble_mesh_lcd_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Large Composition Data Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_lcd_server_callback(esp_ble_mesh_lcd_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_LCD_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_odp_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_odp_model_api.h new file mode 100644 index 0000000000..d09c031f44 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_odp_model_api.h @@ -0,0 +1,205 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_ODP_MODEL_API_H_ +#define _ESP_BLE_MESH_ODP_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x69) +#define ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6A) +#define ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6B) + +/** @def ESP_BLE_MESH_MODEL_ODP_SRV + * + * @brief Define a new On-Demand Private Proxy Config Server model. + * + * @note The On-Demand Private Proxy Server model is used to represent the + * ability to enable advertising with Private Network Identity type + * of a node. This model extends the Mesh Private Beacon Server model. + * When this model is present on an element, the corresponding + * Solicitation PDU RPL Configuration Server model shall also be present. + * The model shall be supported by a primary element and shall not be + * supported by any secondary elements. + * + * @param srv_data Pointer to a unique On-Demand Private Proxy Config Server + * model user_data. + * + * @return New On-Demand Private Proxy Config Server model instance. + */ +#define ESP_BLE_MESH_MODEL_ODP_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_ODP_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_ODP_CLI + * + * @brief Define a new On-Demand Private Proxy Config Client model. + * + * @note The model shall be supported by a primary element and shall not be + * supported by any secondary elements. + * + * @param cli_data Pointer to a unique On-Demand Private Proxy Config Client + * model user_data. + * + * @return New On-Demand Private Proxy Config Client model instance. + */ +#define ESP_BLE_MESH_MODEL_ODP_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_ODP_CLI, \ + NULL, NULL, cli_data) + +/** On-Demand Private Proxy Config Server model context */ +typedef struct { + /** Pointer to On-Demand Private Proxy Config Server model */ + esp_ble_mesh_model_t *model; + + /** Duration in seconds of the interval during which advertising + * with Private Network Identity type is enabled after receiving + * a Solicitation PDU or after a client disconnect. + * Note: Binding with the Private GATT Proxy state. + */ + uint8_t on_demand_private_gatt_proxy; +} esp_ble_mesh_odp_srv_t; + +/** Parameter of On-Demand Private Proxy Set */ +typedef struct { + uint8_t gatt_proxy; /*!< On-Demand Private GATT Proxy */ +} esp_ble_mesh_od_priv_proxy_set_t; + +/** + * @brief On-Demand Private Proxy Client model message union + */ +typedef union { + esp_ble_mesh_od_priv_proxy_set_t od_priv_proxy_set; /*!< For ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_SET */ +} esp_ble_mesh_odp_client_msg_t; + +/** Parameter of On-Demand Private Proxy Status */ +typedef struct { + uint8_t gatt_proxy; /*!< On-Demand Private GATT Proxy */ +} esp_ble_mesh_od_priv_proxy_status_t; + +/** Result of sending On-Demand Private Proxy Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_odp_client_send_cb_t; + +/** + * @brief On-Demand Private Proxy Client model received message union + */ +typedef union { + esp_ble_mesh_od_priv_proxy_status_t od_priv_proxy_status; /*!< For ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_STATUS */ +} esp_ble_mesh_odp_client_recv_cb_t; + +/** On-Demand Private Proxy Config Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events */ + /** Union of ODP Client callback */ + union { + esp_ble_mesh_odp_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_odp_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_odp_client_cb_param_t; /*!< On-Demand Private Proxy Config Client model callback parameters */ + +/** This enum value is the event of On-Demand Private Proxy Config Client model */ +typedef enum { + ESP_BLE_MESH_ODP_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_ODP_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_ODP_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_ODP_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_ODP_CLIENT_EVT_MAX, +} esp_ble_mesh_odp_client_cb_event_t; + +/** + * @brief On-Demand Private Proxy Config Server model related context. + */ + +/** + * @brief On-Demand Private Proxy Config Server model state change value union + */ +typedef union { + uint8_t dummy; /*!< Event not used currently */ +} esp_ble_mesh_odp_server_state_change_t; + +/** + * @brief On-Demand Private Proxy Config Server model callback value union + */ +typedef union { + esp_ble_mesh_odp_server_state_change_t state_change; /*!< For ESP_BLE_MESH_ODP_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_odp_server_cb_value_t; + +/** On-Demand Private Proxy Config Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_odp_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_odp_server_cb_param_t; + +/** This enum value is the event of On-Demand Private Proxy Config Server model */ +typedef enum { + ESP_BLE_MESH_ODP_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_ODP_SERVER_EVT_MAX, +} esp_ble_mesh_odp_server_cb_event_t; + +/** + * @brief Bluetooth Mesh On-Demand Private Proxy Config client and server model functions. + */ + +/** + * @brief On-Demand Private Proxy Config Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_odp_client_cb_t)(esp_ble_mesh_odp_client_cb_event_t event, + esp_ble_mesh_odp_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh On-Demand Private Proxy Config Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_odp_client_callback(esp_ble_mesh_odp_client_cb_t callback); + +/** + * @brief Get the value of On-Demand Private Proxy Config Server model state with the corresponding get message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to On-Demand Private Proxy Config Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_odp_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_odp_client_msg_t *msg); + +/** + * @brief On-Demand Private Proxy Config Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_odp_server_cb_t)(esp_ble_mesh_odp_server_cb_event_t event, + esp_ble_mesh_odp_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh On-Demand Private Proxy Config Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_odp_server_callback(esp_ble_mesh_odp_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_ODP_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_prb_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_prb_model_api.h new file mode 100644 index 0000000000..115283f8fc --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_prb_model_api.h @@ -0,0 +1,258 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_PRB_MODEL_API_H_ +#define _ESP_BLE_MESH_PRB_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x60) +#define ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x61) +#define ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x62) +#define ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x63) +#define ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x64) +#define ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x65) +#define ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x66) +#define ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x67) +#define ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x68) + +/** @def ESP_BLE_MESH_MODEL_PRB_SRV + * + * @brief Define a new Private Beacon Server Model. + * + * @note The Private Beacon Server Model can only be included by a Primary Element. + * + * @param srv_data Pointer to a unique Private Beacon Server Model user_data. + * + * @return New Private Beacon Server Model instance. + */ +#define ESP_BLE_MESH_MODEL_PRB_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_PRB_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_PRB_CLI + * + * @brief Define a new Private Beacon Client Model. + * + * @note The Private Beacon Client Model can only be included by a Primary Element. + * + * @param cli_data Pointer to a unique struct esp_ble_mesh_client_t. + * + * @return New Private Beacon Client Model instance. + */ +#define ESP_BLE_MESH_MODEL_PRB_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_PRB_CLI, \ + NULL, NULL, cli_data) + +/** Private Beacon Server Model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Private Beacon Server Model */ + + uint8_t private_beacon; /*!< Value of Private Beacon state */ + uint8_t random_update_interval; /*!< Value of Random Update Interval Steps state */ + uint8_t private_gatt_proxy; /*!< Value of Private GATT Proxy state */ + + struct k_delayed_work update_timer; /*!< Timer for update the random field of private beacon */ +} esp_ble_mesh_prb_srv_t; + +/** Parameter of private Beacon Set */ +typedef struct { + uint8_t private_beacon; /*!< New Private Beacon state */ + bool is_effect; /*!< Decide if update_interval exists */ + uint8_t update_interval; /*!< New Random Update Interval Steps state */ +} esp_ble_mesh_priv_beacon_set_t; + +/** Parameter of Private GATT Proxy Set */ +typedef struct { + uint8_t private_gatt_proxy; /*!< New Private GATT Proxy state */ +} esp_ble_mesh_priv_gatt_proxy_set_t; + +/** Parameter of Private node identity Get */ +typedef struct { + uint16_t net_idx; /*!< Index of the NetKey */ +} esp_ble_mesh_priv_node_id_get_t; + +/** Parameter of Private node identity Set */ +typedef struct { + uint16_t net_idx; /*!< Index of the NetKey */ + uint8_t private_node_id; /*!< New Private Node Identity state */ +} esp_ble_mesh_priv_node_id_set_t; + +/** + * @brief Mesh Private Beacon Client model message union + */ +typedef union { + esp_ble_mesh_priv_beacon_set_t priv_beacon_set; /*!< ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_SET. */ + esp_ble_mesh_priv_gatt_proxy_set_t priv_gatt_proxy_set; /*!< ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_SET. */ + esp_ble_mesh_priv_node_id_get_t priv_node_id_get; /*!< ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_GET. */ + esp_ble_mesh_priv_node_id_set_t priv_node_id_set; /*!< ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_SET. */ +} esp_ble_mesh_prb_client_msg_t; + +/** Parameter of Private Beacon Status */ +typedef struct { + uint8_t private_beacon; /*!< Current value of the Private Beacon state */ + uint8_t update_interval; /*!< Current value of the Random Update Interval Steps state */ +} esp_ble_mesh_priv_beacon_status_cb_t; + +/** Parameter of Private GATT Proxy Status */ +typedef struct { + uint8_t private_gatt_proxy; /*!< Private GATT Proxy state */ +} esp_ble_mesh_priv_gatt_proxy_status_cb_t; + +/** Parameters of Private Node Identity Status */ +typedef struct { + uint8_t status; /*!< Status Code for the requesting message */ + uint16_t net_idx; /*!< Index of the NetKey */ + uint8_t private_node_id; /*!< Private Node Identity state */ +} esp_ble_mesh_priv_node_identity_status_cb_t; + +/** + * @brief Private Beacon Client Model received message union + */ +typedef union { + esp_ble_mesh_priv_beacon_status_cb_t priv_beacon_status; /*!< The private beacon status value */ + esp_ble_mesh_priv_gatt_proxy_status_cb_t priv_gatt_proxy_status; /*!< The private gatt proxy status value */ + esp_ble_mesh_priv_node_identity_status_cb_t priv_node_id_status; /*!< The private node identity status value */ +} esp_ble_mesh_prb_client_recv_cb_t; + +/** Result of sending Bridge Configuration Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_prb_client_send_cb_t; + +/** Mesh Private Beacon Client Model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< The client common parameters. */ + /** Union of Private Beacon Client callback */ + union { + esp_ble_mesh_prb_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_prb_client_recv_cb_t recv; /*!< The private beacon message status callback values */ + }; +} esp_ble_mesh_prb_client_cb_param_t; /*!< Mesh Private Beacon Client Model callback parameters */ + +/** This enum value is the event of Private Beacon Client Model */ +typedef enum { + ESP_BLE_MESH_PRB_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_PRB_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_PRB_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_PRB_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_PRB_CLIENT_EVT_MAX, +} esp_ble_mesh_prb_client_cb_event_t; + +/** + * @brief Mesh Private Beacon Server model related context. + */ +/** Parameters of Private Beacon Set. */ +typedef struct { + uint8_t private_beacon; /*!< Private Beacon state */ + bool is_effect; /*!< Decide whether update_interval effect */ + uint8_t update_interval; /*!< Random Update Interval Steps state */ +} esp_ble_mesh_state_change_priv_beacon_set_t; + +/** Parameters of Private GATT Proxy Set. */ +typedef struct { + uint8_t private_gatt_proxy; /*!< Private GATT Proxy state */ +} esp_ble_mesh_state_change_priv_gatt_proxy_set_t; + +/** Parameters of Private Node Identity Set. */ +typedef struct { + uint16_t net_idx; /*!< Index of the NetKey */ + uint8_t private_node_id; /*!< Private Node Identity state */ +} esp_ble_mesh_state_change_priv_node_id_set_t; + +/** + * @brief Mesh Private Beacon Server model state change value union + */ +typedef union { + /** + * The recv_op in ctx can be used to decide which state is changed. + */ + esp_ble_mesh_state_change_priv_beacon_set_t priv_beacon_set; /*!< Private Beacon Set */ + esp_ble_mesh_state_change_priv_gatt_proxy_set_t priv_gatt_proxy_set; /*!< Private GATT Proxy Set */ + esp_ble_mesh_state_change_priv_node_id_set_t priv_node_id_set; /*!< Private Node Identity Set */ +} esp_ble_mesh_prb_server_state_change_t; + +/** + * @brief Private Beacon Server model callback value union + */ +typedef union { + esp_ble_mesh_prb_server_state_change_t state_change; /*!< ESP_BLE_MESH_PRB_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_prb_server_cb_value_t; + +/** Private Beacon Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_prb_server_cb_value_t value; /*!< Value of the received private beacon messages */ +} esp_ble_mesh_prb_server_cb_param_t; + +/** This enum value is the event of Private Beacon Server model */ +typedef enum { + ESP_BLE_MESH_PRB_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_PRB_SERVER_EVT_MAX, +} esp_ble_mesh_prb_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Private Beacon Client and Server Model functions. + */ + +/** + * @brief Private Beacon Client Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_prb_client_cb_t)(esp_ble_mesh_prb_client_cb_event_t event, + esp_ble_mesh_prb_client_cb_param_t *param); + +/** + * @brief Private Beacon Server Model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_prb_server_cb_t)(esp_ble_mesh_prb_server_cb_event_t event, + esp_ble_mesh_prb_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Private Beacon Client Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_prb_client_callback(esp_ble_mesh_prb_client_cb_t callback); + +/** + * @brief Register BLE Mesh Private Beacon Server Model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_prb_server_callback(esp_ble_mesh_prb_server_cb_t callback); + +/** + * @brief Get/Set the value of Private Beacon Server Model states using the corresponding messages of Private Beacon Client Model. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Mesh Private Beacon Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_prb_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_prb_client_msg_t *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_PRB_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h new file mode 100644 index 0000000000..87f9a9b7fb --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h @@ -0,0 +1,479 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_RPR_MODEL_API_H_ +#define _ESP_BLE_MESH_RPR_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x4F) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x50) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x51) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START ESP_BLE_MESH_MODEL_OP_2(0x80, 0x52) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STOP ESP_BLE_MESH_MODEL_OP_2(0x80, 0x53) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x54) +#define ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT ESP_BLE_MESH_MODEL_OP_2(0x80, 0x55) +#define ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_START ESP_BLE_MESH_MODEL_OP_2(0x80, 0x56) +#define ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_REPORT ESP_BLE_MESH_MODEL_OP_2(0x80, 0x57) +#define ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x58) +#define ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN ESP_BLE_MESH_MODEL_OP_2(0x80, 0x59) +#define ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5A) +#define ESP_BLE_MESH_MODEL_OP_RPR_LINK_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5B) +#define ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5C) +#define ESP_BLE_MESH_MODEL_OP_RPR_PDU_SEND ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5D) +#define ESP_BLE_MESH_MODEL_OP_RPR_PDU_OUTBOUND_REPORT ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5E) +#define ESP_BLE_MESH_MODEL_OP_RPR_PDU_REPORT ESP_BLE_MESH_MODEL_OP_2(0x80, 0x5F) + +#define ESP_BLE_MESH_RPR_SRV_MAX_SCANNED_ITEMS_MIN 0x04 + +#define ESP_BLE_MESH_RPR_NOT_SUPPORT_ACTIVE_SCAN 0x00 +#define ESP_BLE_MESH_RPR_SUPPORT_ACTIVE_SCAN 0x01 + +#define ESP_BLE_MESH_RPR_SCAN_IDLE 0x00 +#define ESP_BLE_MESH_RPR_SCAN_MULTIPLE_DEVICE 0x01 +#define ESP_BLE_MESH_RPR_SCAN_SINGLE_DEVICE 0x02 + +#define ESP_BLE_MESH_RPR_SCAN_NOT_IN_PROGRESS 0x00 + +#define ESP_BLE_MESH_RPR_PROHIBIT_SCAN_TIMEOUT 0x00 + +#define ESP_BLE_MESH_RPR_EXT_SCAN_TIMEOUT_MIN 0x01 +#define ESP_BLE_MESH_RPR_EXT_SCAN_TIMEOUT_MAX 0x15 + +#define ESP_BLE_MESH_RPR_AD_TYPE_FILTER_CNT_MIN 0x01 +#define ESP_BLE_MESH_RPR_AD_TYPE_FILTER_CNT_MAX 0x10 + +#define ESP_BLE_MESH_RPR_LINK_OPEN_TIMEOUT_MIN 0x01 +#define ESP_BLE_MESH_RPR_LINK_OPEN_TIMEOUT_MAX 0x3C + +/* The default value of the Timeout parameter is 10 seconds */ +#define ESP_BLE_MESH_RPR_LINK_TIMEOUT_DEFAULT 0x0A + +#define ESP_BLE_MESH_RPR_REASON_SUCCESS 0x00 +#define ESP_BLE_MESH_RPR_REASON_FAIL 0x02 + +#define ESP_BLE_MESH_RPR_LINK_IDLE 0x00 +#define ESP_BLE_MESH_RPR_LINK_OPENING 0x01 +#define ESP_BLE_MESH_RPR_LINK_ACTIVE 0x02 +#define ESP_BLE_MESH_RPR_OUTBOUND_PACKET_TRANSFER 0x03 +#define ESP_BLE_MESH_RPR_LINK_CLOSING 0x04 + +#define ESP_BLE_MESH_RPR_STATUS_SUCCESS 0x00 +#define ESP_BLE_MESH_RPR_STATUS_SCANNING_CANNOT_START 0x01 +#define ESP_BLE_MESH_RPR_STATUS_INVALID_STATE 0x02 +#define ESP_BLE_MESH_RPR_STATUS_LIMITED_RESOURCES 0x03 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CANNOT_OPEN 0x04 +#define ESP_BLE_MESH_RPR_STATUS_LINK_OPEN_FAILED 0x05 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_DEVICE 0x06 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_SERVER 0x07 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_CLIENT 0x08 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_RECEIVE_PDU 0x09 +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_SEND_PDU 0x0A +#define ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_DELIVER_PDU_REPORT 0x0B + +/** @def ESP_BLE_MESH_MODEL_RPR_SRV + * + * @brief Define a new Remote Provisioning Server model. + * + * @note If supported, the model shall be supported by a primary element + * and may be supported by any secondary element. + * + * @param srv_data Pointer to a unique Remote Provisioning Server model + * user_data. + * + * @return New Remote Provisioning Server model instance. + */ +#define ESP_BLE_MESH_MODEL_RPR_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_RPR_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_RPR_CLI + * + * @brief Define a new Remote Provisioning Client model. + * + * @note If supported, the model shall be supported by a primary element + * and may be supported by any secondary element. + * + * @param cli_data Pointer to a unique Remote Provisioning Client model + * user_data. + * + * @return New Remote Provisioning Client model instance. + */ +#define ESP_BLE_MESH_MODEL_RPR_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_RPR_CLI, \ + NULL, NULL, cli_data) + +/** Remote Provisioning Server model context */ +/* typedef struct { + * void *dummy; + * } esp_ble_mesh_rpr_srv_t; + */ + +/** Parameters of Remote Provisioning Scan Start */ +typedef struct { + uint8_t scan_items_limit; /*!< Maximum number of scanned items to be reported */ + uint8_t timeout; /*!< Time limit for a scan (in seconds) */ + + bool uuid_en; /*!< Indicate if Device UUID is present */ + uint8_t uuid[16]; /*!< Device UUID (Optional) */ +} esp_ble_mesh_rpr_scan_start_t; + +/** Parameters of Remote Provisioning Extended Scan Start */ +typedef struct { + uint8_t ad_type_filter_count; /*!< Number of AD Types in the ADTypeFilter field */ + uint8_t ad_type_filter[16]; /*!< List of AD Types to be reported. Minimum is 1, maximum is 16 */ + + bool uuid_en; /*!< Indicate if Device UUID is present */ + uint8_t uuid[16]; /*!< Device UUID (Optional) */ + uint8_t timeout; /*!< Time limit for a scan (in seconds) (C.1) */ +} esp_ble_mesh_rpr_ext_scan_start_t; + +/** Parameters of Remote Provisioning Link Open */ +typedef struct { + bool uuid_en; /*!< Indicate if Device UUID is present */ + uint8_t uuid[16]; /*!< Device UUID (Optional) */ + + bool timeout_en; /*!< Indicate if Link open timeout is present */ + uint8_t timeout; /*!< Link open timeout in seconds (C.1) */ + + uint8_t nppi; /*!< Node Provisioning Protocol Interface (C.2) */ +} esp_ble_mesh_rpr_link_open_t; + +/** Parameters of Remote Provisioning Link Close */ +typedef struct { + uint8_t reason; /*!< Provisioning bearer link close reason code */ +} esp_ble_mesh_rpr_link_close_t; + +/** + * @brief Remote Provisioning Client model message union + */ +typedef union { + esp_ble_mesh_rpr_scan_start_t scan_start; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START */ + esp_ble_mesh_rpr_ext_scan_start_t ext_scan_start; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_START */ + esp_ble_mesh_rpr_link_open_t link_open; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN */ + esp_ble_mesh_rpr_link_close_t link_close; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE */ +} esp_ble_mesh_rpr_client_msg_t; + +/** This enum value is the action of Remote Provisioning Client model */ +typedef enum { + ESP_BLE_MESH_RPR_CLIENT_ACT_START_RPR, + ESP_BLE_MESH_RPR_CLIENT_ACT_MAX, +} esp_ble_mesh_rpr_client_act_type_t; + +/** Parameters of starting remote provisioning */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer of Remote Provisioning Client */ + uint16_t rpr_srv_addr; /*!< Unicast address of Remote Provisioning Server */ +} esp_ble_mesh_rpr_client_start_rpr_t; + +/** + * @brief Remote Provisioning Client model action union + */ +typedef union { + esp_ble_mesh_rpr_client_start_rpr_t start_rpr; /*!< Start remote provisioning */ +} esp_ble_mesh_rpr_client_act_param_t; + +/** Parameters of Remote Provisioning Scan Capabilities Status */ +typedef struct { + uint8_t max_scan_items; /*!< The maximum number of UUIDs that can be reported during scanning */ + uint8_t active_scan; /*!< Indication if active scan is supported */ +} esp_ble_mesh_rpr_scan_caps_status_t; + +/** Parameters of Remote Provisioning Scan Status */ +typedef struct { + uint8_t status; /*!< Status for the requesting message */ + uint8_t rpr_scanning; /*!< The Remote Provisioning Scan state value */ + uint8_t scan_items_limit; /*!< Maximum number of scanned items to be reported */ + uint8_t timeout; /*!< Time limit for a scan (in seconds) */ +} esp_ble_mesh_rpr_scan_status_t; + +/** Parameters of Remote Provisioning Scan Report */ +typedef struct { + int8_t rssi; /*!< An indication of received signal strength measured in dBm */ + uint8_t uuid[16]; /*!< Device UUID */ + uint16_t oob_info; /*!< OOB information */ + uint32_t uri_hash; /*!< URI Hash (Optional) */ +} esp_ble_mesh_rpr_scan_report_t; + +/** Parameters of Remote Provisioning Extended Scan Report */ +typedef struct { + uint8_t status; /*!< Status for the requesting message */ + uint8_t uuid[16]; /*!< Device UUID */ + + bool oob_info_en; /*!< Indicate if OOB Information is present */ + uint16_t oob_info; /*!< OOB Information (Optional) */ + struct net_buf_simple *adv_structures; /*!< Concatenated list of AD Structures (C.1) */ +} esp_ble_mesh_rpr_ext_scan_report_t; + +/** Parameters of Remote Provisioning Link Status */ +typedef struct { + uint8_t status; /*!< Status for the requesting message */ + uint8_t rpr_state; /*!< Remote Provisioning Link state */ +} esp_ble_mesh_rpr_link_status_t; + +/** Parameters of Remote Provisioning Link Report */ +typedef struct { + uint8_t status; /*!< Status of the provisioning bearer or the NPPI */ + uint8_t rpr_state; /*!< Remote Provisioning Link state */ + bool reason_en; /*!< Indicate if Link close Reason code is present */ + uint8_t reason; /*!< Link close Reason code (Optional) */ +} esp_ble_mesh_rpr_link_report_t; + +/** + * @brief Remote Provisioning Client model received message union + */ +typedef union { + esp_ble_mesh_rpr_scan_caps_status_t scan_caps_status; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_STATUS */ + esp_ble_mesh_rpr_scan_status_t scan_status; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS */ + esp_ble_mesh_rpr_scan_report_t scan_report; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT */ + esp_ble_mesh_rpr_ext_scan_report_t ext_scan_report; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_REPORT */ + esp_ble_mesh_rpr_link_status_t link_status; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_LINK_STATUS */ + esp_ble_mesh_rpr_link_report_t link_report; /*!< For ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT */ +} esp_ble_mesh_rpr_client_recv_cb_t; + +/** Remote Provisioning Client model callback parameters */ +typedef union { + /** Event parameters of sending messages */ + struct { + int err_code; /*!< Result of sending a message */ + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters */ + } send; /*!< Event parameters of sending messages */ + /** Event parameters of receiving messages */ + struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters */ + esp_ble_mesh_rpr_client_recv_cb_t val; /*!< Parameters of received status message */ + } recv; /*!< Event parameters of receiving messages */ + /** Event parameters of performed actions */ + struct { + /** Event type of the performed action */ + enum { + ESP_BLE_MESH_START_RPR_COMP_SUB_EVT, + } sub_evt; /*!< Event type of the performed action */ + /** + * @brief ESP_BLE_MESH_START_RPR_COMP_SUB_EVT + */ + struct { + int err_code; /*!< Result of starting remote provisioning */ + esp_ble_mesh_model_t *model; /*!< Pointer of Remote Provisioning Client */ + uint16_t rpr_srv_addr; /*!< Unicast address of Remote Provisioning Server */ + } start_rpr_comp; /*!< Event parameter of ESP_BLE_MESH_START_RPR_COMP_SUB_EVT */ + } act; /*!< Event parameters of performed actions */ + /** + * @brief ESP_BLE_MESH_RPR_CLIENT_LINK_OPEN_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer of Remote Provisioning Client */ + uint16_t rpr_srv_addr; /*!< Unicast address of Remote Provisioning Server */ + } link_open; /*!< Event parameters of ESP_BLE_MESH_RPR_CLIENT_LINK_OPEN_EVT */ + /** + * @brief ESP_BLE_MESH_RPR_CLIENT_LINK_CLOSE_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer of Remote Provisioning Client */ + uint16_t rpr_srv_addr; /*!< Unicast address of Remote Provisioning Server */ + uint8_t reason; /*!< Reason of closing provisioning link */ + } link_close; /*!< Event parameters of ESP_BLE_MESH_RPR_CLIENT_LINK_CLOSE_EVT */ + /** + * @brief ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer of Remote Provisioning Client */ + uint16_t rpr_srv_addr; /*!< Unicast address of Remote Provisioning Server */ + uint8_t nppi; /*!< NPPI Procedure */ + uint16_t index; /*!< Index of the provisioned node */ + uint8_t uuid[16]; /*!< Device UUID */ + uint16_t unicast_addr; /*!< Primary element address */ + uint8_t element_num; /*!< Element number */ + uint16_t net_idx; /*!< NetKey Index */ + } prov; /*!< Event parameters of ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT */ +} esp_ble_mesh_rpr_client_cb_param_t; /*!< Remote Provisioning Client model callback parameters */ + +/** This enum value is the event of Remote Provisioning Client model */ +typedef enum { + ESP_BLE_MESH_RPR_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_RPR_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_RPR_CLIENT_ACT_COMP_EVT, + ESP_BLE_MESH_RPR_CLIENT_LINK_OPEN_EVT, + ESP_BLE_MESH_RPR_CLIENT_LINK_CLOSE_EVT, + ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT, + ESP_BLE_MESH_RPR_CLIENT_EVT_MAX, +} esp_ble_mesh_rpr_client_cb_event_t; + +/** + * @brief Remote Provisioning Server model related context. + */ + +/** + * @brief Remote Provisioning Server model callback value union + */ +typedef union { + /** + * @brief ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t scan_items_limit; /*!< Maximum number of scanned items to be reported */ + uint8_t timeout; /*!< Time limit for a scan (in seconds) */ + uint8_t uuid[16]; /*!< Device UUID (All ZERO if not present) */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } scan_start; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t uuid[16]; /*!< Device UUID (All ZERO if not present) */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } scan_stop; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t ad_type_filter_count; /*!< Number of AD Types in the ADTypeFilter field */ + uint8_t *ad_type_filter; /*!< List of AD Types to be reported */ + uint8_t uuid[16]; /*!< Device UUID (All ZERO if not present) */ + uint8_t timeout; /*!< Time limit for a scan (in seconds) */ + uint8_t index; /*!< Index of the extended scan instance */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } ext_scan_start; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t uuid[16]; /*!< Device UUID (ZERO if not present)*/ + uint8_t timeout; /*!< Time limit for extended scan (in seconds) */ + uint8_t index; /*!< Index of the extended scan instance */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } ext_scan_stop; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t uuid[16]; /*!< Device UUID (ZERO if not present)*/ + uint8_t status; /*!< Status of Link Open procedure */ + uint8_t timeout; /*!< Time limit for opening a link (in seconds) */ + uint8_t nppi; /*!< Node Provisioning Protocol Interface */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } link_open; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t uuid[16]; /*!< Device UUID (ZERO if not present)*/ + uint8_t nppi; /*!< Node Provisioning Protocol Interface */ + bool close_by_device; /*!< Indicate if the link is closed by the Unprovisioned Device */ + uint8_t reason; /*!< Provisioning bearer link close reason code */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } link_close; + /** + * @brief ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT. TODO: Duplicate with Link Close event? + */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + uint8_t uuid[16]; /*!< Device UUID (ZERO if not present)*/ + uint8_t nppi; /*!< Provisioning bearer link close reason code */ + uint16_t net_idx; /*!< NetKey Index used by Remote Provisioning Client */ + uint16_t rpr_cli_addr; /*!< Unicast address of Remote Provisioning Client */ + } prov_comp; +} esp_ble_mesh_rpr_server_cb_param_t; + +/** This enum value is the event of Remote Provisioning Server model */ +typedef enum { + ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT, + ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT, + ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT, + ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT, + ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT, + ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT, + ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT, + ESP_BLE_MESH_RPR_SERVER_EVT_MAX, +} esp_ble_mesh_rpr_server_cb_event_t; + +/** + * @brief Remote Provisioning client and server model functions. + */ + +/** + * @brief Remote Provisioning Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_rpr_client_cb_t)(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Remote Provisioning Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_rpr_client_callback(esp_ble_mesh_rpr_client_cb_t callback); + +/** + * @brief Get the value of Remote Provisioning Server model state with the corresponding get message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Remote Provisioning Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_rpr_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_rpr_client_msg_t *msg); + +/** + * @brief Remote Provisioning Client model perform related actions, e.g. start remote provisioning. + * + * @param[in] type: Type of the action to be performed. + * @param[in] param: Parameters of the action to be performed. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_rpr_client_action(esp_ble_mesh_rpr_client_act_type_t type, + esp_ble_mesh_rpr_client_act_param_t *param); + +/** + * @brief Remote Provisioning Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_rpr_server_cb_t)(esp_ble_mesh_rpr_server_cb_event_t event, + esp_ble_mesh_rpr_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Remote Provisioning Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_rpr_server_callback(esp_ble_mesh_rpr_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_RPR_MODEL_API_H_ */ 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 new file mode 100644 index 0000000000..74a4b59374 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h @@ -0,0 +1,223 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_SAR_MODEL_API_H_ +#define _ESP_BLE_MESH_SAR_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6C) +#define ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6D) +#define ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6E) +#define ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_GET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x6F) +#define ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_SET ESP_BLE_MESH_MODEL_OP_2(0x80, 0x70) +#define ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x71) + +/** @def ESP_BLE_MESH_MODEL_SAR_SRV + * + * @brief Define a new SAR Configuration Server model. + * + * @note If supported, the model shall be supported by a primary element + * and shall not be supported by any secondary elements. + * + * @param srv_data Pointer to a unique SAR Configuration Server model user_data. + * + * @return New SAR Configuration Server model instance. + */ +#define ESP_BLE_MESH_MODEL_SAR_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SAR_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_SAR_CLI + * + * @brief Define a new SAR Configuration Client model. + * + * @note If supported, the model shall be supported by the primary element + * and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique SAR Configuration Client model user_data. + * + * @return New SAR Configuration Client model instance. + */ +#define ESP_BLE_MESH_MODEL_SAR_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SAR_CLI, \ + NULL, NULL, cli_data) + +/** SAR Configuration Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to SAR Configuration Server model */ +} esp_ble_mesh_sar_srv_t; + +/** Parameters of SAR Transmitter Set */ +typedef struct { + uint8_t sar_segment_interval_step:4, /*!< SAR Segment Interval Step state value */ + sar_unicast_retrans_count:4; /*!< SAR Unicast Retransmissions Count state */ + uint8_t sar_unicast_retrans_without_progress_count:4, /*!< SAR Unicast Retransmissions Without Progress Count state */ + 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 */ +} 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 */ +} esp_ble_mesh_sar_receiver_set_t; + +/** + * @brief SAR Configuration Client model message union + */ +typedef union { + esp_ble_mesh_sar_transmitter_set_t sar_transmitter_set; /*!< For ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_SET */ + esp_ble_mesh_sar_receiver_set_t sar_receiver_set; /*!< For ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_SET */ +} esp_ble_mesh_sar_client_msg_t; + +/** Parameters of SAR Transmitter Status */ +typedef struct { + uint8_t sar_segment_interval_step:4, /*!< SAR Segment Interval Step state value */ + sar_unicast_retrans_count:4; /*!< SAR Unicast Retransmissions Count state */ + uint8_t sar_unicast_retrans_without_progress_count:4, /*!< SAR Unicast Retransmissions Without Progress Count state */ + 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 */ +} 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 */ +} esp_ble_mesh_sar_receiver_status_t; + +/** Result of sending SAR Configuration Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_sar_client_send_cb_t; + +/** + * @brief SAR Configuration Client model received message union + */ +typedef union { + esp_ble_mesh_sar_transmitter_status_t sar_transmitter_status; /*!< For ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_STATUS */ + esp_ble_mesh_sar_receiver_status_t sar_receiver_status; /*!< For ESP_BLE_MESH_MODEL_OP_SAR_RECEIVE_STATUS */ +} esp_ble_mesh_sar_client_recv_cb_t; + +/** SAR Configuration Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of SAR Client callback */ + union { + esp_ble_mesh_sar_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_sar_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_sar_client_cb_param_t; /*!< SAR Configuration Client model callback parameters */ + +/** This enum value is the event of SAR Configuration Client model */ +typedef enum { + ESP_BLE_MESH_SAR_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_SAR_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_SAR_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_SAR_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_SAR_CLIENT_EVT_MAX, +} esp_ble_mesh_sar_client_cb_event_t; + +/** + * @brief SAR Configuration Server model related context. + */ + +/** + * @brief SAR Configuration Server model state change value union + */ +typedef union { + uint8_t dummy; /*!< Event not used currently */ +} esp_ble_mesh_sar_server_state_change_t; + +/** + * @brief SAR Configuration Server model callback value union + */ +typedef union { + esp_ble_mesh_sar_server_state_change_t state_change; /*!< For ESP_BLE_MESH_SAR_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_sar_server_cb_value_t; + +/** SAR Configuration Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_sar_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_sar_server_cb_param_t; + +/** This enum value is the event of SAR Configuration Server model */ +typedef enum { + ESP_BLE_MESH_SAR_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_SAR_SERVER_EVT_MAX, +} esp_ble_mesh_sar_server_cb_event_t; + +/** + * @brief Bluetooth Mesh SAR Configuration client and server model functions. + */ + +/** + * @brief SAR Configuration Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_sar_client_cb_t)(esp_ble_mesh_sar_client_cb_event_t event, + esp_ble_mesh_sar_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh SAR Configuration Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_sar_client_callback(esp_ble_mesh_sar_client_cb_t callback); + +/** + * @brief Get the value of SAR Configuration Server model state with the corresponding get message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to SAR Configuration Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_sar_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sar_client_msg_t *msg); + +/** + * @brief SAR Configuration Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_sar_server_cb_t)(esp_ble_mesh_sar_server_cb_event_t event, + esp_ble_mesh_sar_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh SAR Configuration Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_sar_server_callback(esp_ble_mesh_sar_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_SAR_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h new file mode 100644 index 0000000000..efe60f71d0 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_SRPL_MODEL_API_H_ +#define _ESP_BLE_MESH_SRPL_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_CLEAR ESP_BLE_MESH_MODEL_OP_2(0x80, 0x78) +#define ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_CLEAR_UNACK ESP_BLE_MESH_MODEL_OP_2(0x80, 0x79) +#define ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x80, 0x7A) + +/** @def ESP_BLE_MESH_MODEL_SRPL_SRV + * + * @brief Define a new Solicitation PDU RPL Configuration Server model. + * + * @note The Solicitation PDU RPL Configuration Server model extends + * the On-Demand Private Proxy Server model. + * If the model is supported, the model shall be supported by a + * primary element and shall not be supported by any secondary + * elements. + * + * @param srv_data Pointer to a unique Solicitation PDU RPL Configuration Server + * model user_data. + * + * @return New Solicitation PDU RPL Configuration Server model instance. + */ +#define ESP_BLE_MESH_MODEL_SRPL_SRV(srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SRPL_SRV, \ + NULL, NULL, srv_data) + +/** @def ESP_BLE_MESH_MODEL_SRPL_CLI + * + * @brief Define a new Solicitation PDU RPL Configuration Client model. + * + * @note If supported, the model shall be supported by the primary + * element and shall not be supported by any secondary elements. + * + * @param cli_data Pointer to a unique Solicitation PDU RPL Configuration Client + * model user_data. + * + * @return New Solicitation PDU RPL Configuration Client model instance. + */ +#define ESP_BLE_MESH_MODEL_SRPL_CLI(cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SRPL_CLI, \ + NULL, NULL, cli_data) + +/** Solicitation PDU RPL Configuration Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to Solicitation PDU RPL Configuration Server model */ + + /* This model does not define any states. */ +} esp_ble_mesh_srpl_srv_t; + +/** Parameter of Solicitation PDU RPL Items Clear */ +typedef struct { + esp_ble_mesh_uar_t addr_range; /*!< Unicast address range */ +} esp_ble_mesh_srpl_items_clear_t; + +/** + * @brief Solicitation PDU RPL Configuration Client model message union + */ +typedef union { + esp_ble_mesh_srpl_items_clear_t srpl_items_clear; /*!< For ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_CLEAR */ +} esp_ble_mesh_srpl_client_msg_t; + +/** Parameter of Solicitation PDU RPL Items Clear Status */ +typedef struct { + esp_ble_mesh_uar_t addr_range; /*!< Unicast address range */ +} esp_ble_mesh_srpl_items_status_t; + +/** Result of sending Solicitation PDU RPL Configuration Client messages */ +typedef struct { + int err_code; /*!< Result of sending a message */ +} esp_ble_mesh_srpl_client_send_cb_t; + +/** + * @brief Solicitation PDU RPL Configuration Client model received message union + */ +typedef union { + esp_ble_mesh_srpl_items_status_t srpl_items_status; /*!< For ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_STATUS */ +} esp_ble_mesh_srpl_client_recv_cb_t; + +/** Solicitation PDU RPL Configuration Client model callback parameters */ +typedef struct { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of SRPL Client callback */ + union { + esp_ble_mesh_srpl_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_srpl_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +} esp_ble_mesh_srpl_client_cb_param_t; /*!< Solicitation PDU RPL Configuration Client model callback parameters */ + +/** This enum value is the event of Solicitation PDU RPL Configuration Client model */ +typedef enum { + ESP_BLE_MESH_SRPL_CLIENT_SEND_COMP_EVT, + ESP_BLE_MESH_SRPL_CLIENT_SEND_TIMEOUT_EVT, + ESP_BLE_MESH_SRPL_CLIENT_RECV_RSP_EVT, + ESP_BLE_MESH_SRPL_CLIENT_RECV_PUB_EVT, + ESP_BLE_MESH_SRPL_CLIENT_EVT_MAX, +} esp_ble_mesh_srpl_client_cb_event_t; + +/** + * @brief Solicitation PDU RPL Configuration Server model related context. + */ + +/** + * @brief Solicitation PDU RPL Configuration Server model state change value union + */ +typedef union { + uint8_t dummy; /*!< Currently this event is not used. */ +} esp_ble_mesh_srpl_server_state_change_t; + +/** + * @brief Solicitation PDU RPL Configuration Server model callback value union + */ +typedef union { + esp_ble_mesh_srpl_server_state_change_t state_change; /*!< ESP_BLE_MESH_SRPL_SERVER_STATE_CHANGE_EVT */ +} esp_ble_mesh_srpl_server_cb_value_t; + +/** Solicitation PDU RPL Configuration Server model callback parameters */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the server model structure */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Context of the received message */ + esp_ble_mesh_srpl_server_cb_value_t value; /*!< Value of the received configuration messages */ +} esp_ble_mesh_srpl_server_cb_param_t; + +/** This enum value is the event of Solicitation PDU RPL Configuration Server model */ +typedef enum { + ESP_BLE_MESH_SRPL_SERVER_STATE_CHANGE_EVT, + ESP_BLE_MESH_SRPL_SERVER_EVT_MAX, +} esp_ble_mesh_srpl_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Solicitation PDU RPL Configuration client and server model functions. + */ + +/** + * @brief Solicitation PDU RPL Configuration Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_srpl_client_cb_t)(esp_ble_mesh_srpl_client_cb_event_t event, + esp_ble_mesh_srpl_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Solicitation PDU RPL Configuration Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_srpl_client_callback(esp_ble_mesh_srpl_client_cb_t callback); + +/** + * @brief Set the value of Solicitation PDU RPL Configuration Server model state with the corresponding set message. + * + * @param[in] params: Pointer to BLE Mesh common client parameters. + * @param[in] msg: Pointer to Solicitation PDU RPL Configuration Client message. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_srpl_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_srpl_client_msg_t *msg); + + +/** + * @brief Solicitation PDU RPL Configuration Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_srpl_server_cb_t)(esp_ble_mesh_srpl_server_cb_event_t event, + esp_ble_mesh_srpl_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh Solicitation PDU RPL Configuration Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_srpl_server_callback(esp_ble_mesh_srpl_server_cb_t callback); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_SRPL_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c new file mode 100644 index 0000000000..5760a4ce93 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c @@ -0,0 +1,421 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_mbt_model.h" +#include "esp_ble_mesh_mbt_model_api.h" + +#if CONFIG_BLE_MESH_MBT_CLI + +extern const void *bt_mesh_get_blob_receiver(void *model, uint16_t unicast_addr); +extern const void **bt_mesh_get_active_blob_receiver(void *model); +extern int bt_mesh_get_transfer_progress(void *model, uint16_t unicast_addr, + uint8_t *block_percent, uint8_t *chunk_percent); +extern int bt_mesh_get_blob_reception_progress(void *model, uint8_t *reception_progress); + +esp_err_t esp_ble_mesh_register_blob_transfer_client_callback(esp_ble_mesh_mbt_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_MBT_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL || + (input->unicast_addr_count && input->unicast_addr == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES; + + memcpy(&arg.retrieve_capabilities, input, sizeof(esp_ble_mesh_retrieve_capabilities_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), + btc_ble_mesh_mbt_client_arg_deep_copy, + btc_ble_mesh_mbt_client_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL || + (input->unicast_addr_count && input->unicast_addr == NULL) || + input->blob_data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB; + + memcpy(&arg.transfer_blob, input, sizeof(esp_ble_mesh_transfer_blob_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), + btc_ble_mesh_mbt_client_arg_deep_copy, + btc_ble_mesh_mbt_client_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_BLOCK; + + memcpy(&arg.send_block, input, sizeof(esp_ble_mesh_send_block_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_DATA; + + memcpy(&arg.send_data, input, sizeof(esp_ble_mesh_send_data_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_BLOCK_STATUS; + + memcpy(&arg.determine_block_status, input, sizeof(esp_ble_mesh_determine_block_status_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL || + (input->unicast_addr_count && input->unicast_addr == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS; + + memcpy(&arg.determine_transfer_status, input, sizeof(esp_ble_mesh_determine_transfer_status_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), + btc_ble_mesh_mbt_client_arg_deep_copy, + btc_ble_mesh_mbt_client_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL || + (input->unicast_addr_count && input->unicast_addr == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER; + + memcpy(&arg.cancel_transfer, input, sizeof(esp_ble_mesh_cancel_transfer_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), + btc_ble_mesh_mbt_client_arg_deep_copy, + btc_ble_mesh_mbt_client_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, + uint16_t unicast_addr) +{ + return (const esp_ble_mesh_blob_receiver_t *)bt_mesh_get_blob_receiver((struct bt_mesh_model *)model, + unicast_addr); +} + +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) +{ + return (const esp_ble_mesh_blob_receiver_t **)bt_mesh_get_active_blob_receiver((struct bt_mesh_model *)model); +} + +esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, + uint16_t unicast_addr, + uint8_t *block_percent, + uint8_t *chunk_percent) +{ + return (bt_mesh_get_transfer_progress((struct bt_mesh_model *)model, unicast_addr, + block_percent, chunk_percent) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, + uint8_t transfer_ttl) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_SET_TRANSFER_TTL; + + arg.set_transfer_ttl.model = model; + arg.set_transfer_ttl.transfer_ttl = transfer_ttl; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_TRANSFER_TTL; + + arg.clear_transfer_ttl.model = model; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, + uint16_t app_idx) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_SET_APP_IDX; + + arg.set_app_idx.model = model; + arg.set_app_idx.app_idx = app_idx; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_APP_IDX; + + arg.clear_app_idx.model = model; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, + uint16_t multicast_addr) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_SET_MULTICAST_ADDR; + + arg.set_multicast_addr.model = model; + arg.set_multicast_addr.multicast_addr = multicast_addr; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) +{ + btc_ble_mesh_mbt_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_MULTICAST_ADDR; + + arg.clear_multicast_addr.model = model; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_client_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_MBT_CLI */ + +#if CONFIG_BLE_MESH_MBT_SRV +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_MBT_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) +{ + btc_ble_mesh_mbt_server_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_SERVER; + msg.act = BTC_BLE_MESH_ACT_MBT_SERVER_INITIALIZE_BLOB_RECEIVE; + + memcpy(&arg.initialize_blob_receive, input, sizeof(esp_ble_mesh_initialize_blob_receive_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_server_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) +{ + btc_ble_mesh_mbt_server_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_SERVER; + msg.act = BTC_BLE_MESH_ACT_MBT_SERVER_CANCEL_BLOB_RECEIVE; + + memcpy(&arg.cancel_blob_receive, input, sizeof(esp_ble_mesh_cancel_blob_receive_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_server_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) +{ + btc_ble_mesh_mbt_server_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (input == NULL || input->model == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_MBT_SERVER; + msg.act = BTC_BLE_MESH_ACT_MBT_SERVER_SET_BLOB_CAPABILITIES; + + memcpy(&arg.set_blob_capabilities, input, sizeof(esp_ble_mesh_set_blob_capabilities_t)); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_mbt_server_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, + uint8_t *reception_progress) +{ + return (bt_mesh_get_blob_reception_progress((struct bt_mesh_model *)model, + reception_progress) == 0 ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_MBT_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h new file mode 100644 index 0000000000..87e51948ae --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h @@ -0,0 +1,693 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_MBT_MODEL_API_H_ +#define _ESP_BLE_MESH_MBT_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x00) +#define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x01) +#define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x02) +#define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x03) +#define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x05) +#define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x04) +#define ESP_BLE_MESH_MODEL_OP_BLOB_PARTIAL_BLOCK_REPORT ESP_BLE_MESH_MODEL_OP_1(0x65) +#define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_STATUS ESP_BLE_MESH_MODEL_OP_1(0x67) +#define ESP_BLE_MESH_MODEL_OP_BLOB_CHUNK_TRANSFER ESP_BLE_MESH_MODEL_OP_1(0x66) +#define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x06) +#define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x07) + +#define ESP_BLE_MESH_BLOB_ID_SIZE 8 + +/** @def ESP_BLE_MESH_MODEL_MBT_CLI + * + * @brief Define a new BLOB Transfer Client model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Client model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New BLOB Transfer Client model instance. + */ +#define ESP_BLE_MESH_MODEL_MBT_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_MBT_SRV + * + * @brief Define a new BLOB Transfer Server model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Server model. + * + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * + * @return New BLOB Transfer Server model instance. + */ +#define ESP_BLE_MESH_MODEL_MBT_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_SRV, \ + NULL, srv_pub, srv_data) + +/** BLOB Transfer Server model context */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ +} esp_ble_mesh_mbt_srv_t; + +/** Parameters of BLOB receiver */ +typedef struct { + uint16_t unicast_addr; /*!< Unicast address of the server */ + uint8_t retrieved_transfer_phase; /*!< Retrieved transfer phase of the server */ + uint8_t status:4; /*!< Status of the last operation */ + uint16_t blocks_not_received_len; /*!< Indicates the length which blocks were not received by the server. */ + uint8_t *blocks_not_received; /*!< Indicates which blocks were not received by the server. */ + uint16_t missing_chunks_len; /*!< Indicates which chunks were not received in the current block */ + uint8_t *missing_chunks; /*!< Indicates which chunks were not received by the server in the current block */ +/* The followings are the additional information contained in status messages. */ + uint8_t transfer_mode:2; /*!< BLOB transfer mode */ + uint8_t expected_blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< Expected BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t block_size_log; /*!< Indicates the block size */ + uint16_t transfer_mtu_size; /*!< MTU size in octets */ + bool block_status_recv; /*!< Indicate if Blob Block Status is received as a response. */ +} esp_ble_mesh_blob_receiver_t; /*!< Structure of BLOB receiver */ + +/** Parameters of BLOB Information Status */ +typedef struct { + uint8_t min_block_size_log; /*!< Min Block Size Log */ + uint8_t max_block_size_log; /*!< Max Block Size Log */ + uint16_t max_total_chunks; /*!< Max Total Chunks */ + uint16_t max_chunk_size; /*!< Max Chunk Size */ + uint32_t max_blob_size; /*!< Max BLOB Size */ + uint16_t server_mtu_size; /*!< Server MTU size */ + uint8_t supported_transfer_mode; /*!< Supported Transfer Mode */ +} esp_ble_mesh_blob_capabilities_t; /*!< Parameters of BLOB Information Status */ + +/** Parameters of BLOB retrieve capabilities */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unlicast address list */ +} esp_ble_mesh_retrieve_capabilities_t; /*!< Parameters of BLOB retrieve capabilities */ + +/** Parameters of BLOB transfer */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unlicast address list */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t *blob_data; /*!< BLOB data */ + uint8_t transfer_mode; /*!< BLOB transfer mode */ + uint16_t client_timeout_base; /*!< Time wait for messages from the serve */ +} esp_ble_mesh_transfer_blob_t; /*!< Parameters of BLOB transfer */ + +/** Parameters of BLOB Block Status message */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + + uint16_t block_number; /*!< Block number of the current block */ + uint16_t chunk_size; /*!< Chunk Size (in octets) for the current block */ +} esp_ble_mesh_send_block_t; /*!< BLOB Block Status message structure */ + +/** Parameters of BLOB send message */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_send_data_t; /*!< Parameters of BLOB send message */ + +/** Parameters of determine Block Status message */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_determine_block_status_t; /*!< Parameters of determine Block Status message */ + +/** Parameters of determine Block Status message */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unlicast address list */ +} esp_ble_mesh_determine_transfer_status_t; /*!< Parameters of determine Block Status message */ + +/** Parameters of cancel transfer message */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unlicast address list */ + + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ +} esp_ble_mesh_cancel_transfer_t; /*!< Parameters of cancel transfer message */ + +/** + * @brief BLOB Transfer Client model procedure result + */ +#define ESP_BLE_MESH_MBT_CLIENT_RESULT_COMPLETE 0x00 +#define ESP_BLE_MESH_MBT_CLIENT_RESULT_FAIL 0x01 + +/** + * @brief BLOB Transfer Client model callback values union + */ +typedef union { + /** Retrieve capabilities status */ + struct { + int error_code; /*!< Result of starting Retrieve Capabilities procedure */ + esp_ble_mesh_retrieve_capabilities_t input; /*!< Input of starting Retrieve Capabilities procedure */ + } retrieve_capabilities_status; /*!< Retrieve capabilities status */ + /** Transfer BLOB status */ + struct { + int error_code; /*!< Result of starting Transfer BLOB procedure */ + esp_ble_mesh_transfer_blob_t input; /*!< Input of starting Transfer BLOB procedure */ + } transfer_blob_status; /*!< Transfer BLOB status */ + /** Send block status */ + struct { + int error_code; /*!< Result of starting Send Block sub-procedure */ + esp_ble_mesh_send_block_t input; /*!< Input of starting Send Block sub-procedure */ + } send_block_status; /*!< Send block status */ + /** Send data status */ + struct { + int error_code; /*!< Result of starting Send Data sub-procedure */ + esp_ble_mesh_send_data_t input; /*!< Input of starting Send Data sub-procedure */ + } send_data_status; /*!< Send data status */ + /** Determine block status */ + struct { + int error_code; /*!< Result of starting Determine Block Status sub-procedure */ + esp_ble_mesh_determine_block_status_t input; /*!< Input of starting Determine Block Status sub-procedure */ + } determine_block_status_status; /*!< Determine block status */ + /** Determine transfer status */ + struct { + int error_code; /*!< Result of starting Determine Transfer Status procedure */ + esp_ble_mesh_determine_transfer_status_t input; /*!< Input of starting Determine Transfer Status procedure */ + } determine_transfer_status_status; /*!< Determine transfer status */ + /** Cancel transfer status */ + struct { + int error_code; /*!< Result of starting Cancel Transfer procedure */ + esp_ble_mesh_cancel_transfer_t input; /*!< Input of starting Cancel Transfer procedure */ + } cancel_transfer_status; /*!< Cancel transfer status */ + /** Retrieve capabilities complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Retrieve Capabilities procedure */ + } retrieve_capabilities_comp; /*!< Retrieve capabilities complete */ + /** Transfer BLOB complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Transfer BLOB procedure */ + } transfer_blob_comp; /*!< Transfer BLOB complete */ + /** Send block complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Block sub-procedure */ + } send_block_comp; /*!< Send block complete */ + /** Send data complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Data sub-procedure */ + } send_data_comp; /*!< Send data complete */ + /** Determine block status complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Block Status sub-procedure */ + } determine_block_status_comp; /*!< Determine block status complete */ + /** Determine transfer status complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Transfer Status procedure */ + } determine_transfer_status_comp; /*!< Determine transfer status complete */ + /** Cancel transfer complete */ + struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Cancel Transfer procedure */ + } cancel_transfer_comp; /*!< Cancel transfer complete */ + /** Set transfer TTL */ + struct { + int error_code; /*!< Result of setting Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + } set_transfer_ttl; /*!< Set transfer TTL */ + /** Clear transfer TTL */ + struct { + int error_code; /*!< Result of clearing Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_transfer_ttl; /*!< Clear transfer TTL */ + /** Set application index */ + struct { + int error_code; /*!< Result of setting AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t app_idx; /*!< AppKey Index state */ + } set_app_idx; /*!< Set application index */ + /** Clear application index */ + struct { + int error_code; /*!< Result of clearing AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_app_idx; /*!< Clear application index */ + /** Set multicast address */ + struct { + int error_code; /*!< Result of setting Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t multicast_addr; /*!< Multicast Address state */ + } set_multicast_addr; /*!< Set multicast address */ + /** Clear multicast address */ + struct { + int error_code; /*!< Result of clearing Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_multicast_addr; /*!< Clear multicast address */ +} esp_ble_mesh_mbt_client_cb_value_t; /*!< BLOB Transfer Client model callback values union */ + +/** BLOB Transfer Client model callback parameters */ +typedef struct { + esp_ble_mesh_mbt_client_cb_value_t value; /*!< BLOB Transfer Client model callback values */ +} esp_ble_mesh_mbt_client_cb_param_t; /*!< BLOB Transfer Client model callback parameters */ + +/** + * This enum value is the event of BLOB Transfer Client model. + * Note: The idea of status/complete event comes from HCI Commands. + */ +typedef enum { + ESP_BLE_MESH_MBT_CLIENT_RETRIEVE_CAPABILITIES_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_TRANSFER_BLOB_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_SEND_BLOCK_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_SEND_DATA_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_DETERMINE_BLOCK_STATUS_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_CANCEL_TRANSFER_STATUS_EVT, + ESP_BLE_MESH_MBT_CLIENT_RETRIEVE_CAPABILITIES_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_TRANSFER_BLOB_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_SEND_BLOCK_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_SEND_DATA_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_DETERMINE_BLOCK_STATUS_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_CANCEL_TRANSFER_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_SET_TRANSFER_TTL_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_CLEAR_TRANSFER_TTL_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_SET_APP_IDX_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_CLEAR_APP_IDX_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_SET_MULTICAST_ADDR_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP_EVT, + ESP_BLE_MESH_MBT_CLIENT_EVT_MAX, +} esp_ble_mesh_mbt_client_cb_event_t; + +/** Parameters of initialize BLOB receive */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint16_t timeout; /*!< Timeout */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_initialize_blob_receive_t; /*!< Structure of initialize BLOB receive */ + +/** Parameters of cancel BLOB receive */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ +} esp_ble_mesh_cancel_blob_receive_t;/*!< */ + +/** Parameters of cancel BLOB receive */ +typedef struct { + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + + esp_ble_mesh_blob_capabilities_t caps; /*!< Parameters of BLOB Information Status */ +} esp_ble_mesh_set_blob_capabilities_t;/*!< */ + +/** + * @brief BLOB Transfer Server model callback value union + */ +typedef union { + /** Initialize BLOB receive complete */ + struct { + int error_code; /*!< Result of initializing BLOB receive */ + esp_ble_mesh_initialize_blob_receive_t input; /*!< Input of initializing BLOB receive */ + } initialize_blob_receive_comp; /*!< Initialize BLOB receive complete */ + /** Cancel BLOB receive complete */ + struct { + int error_code; /*!< Result of canceling BLOB receive */ + esp_ble_mesh_cancel_blob_receive_t input; /*!< Input of canceling BLOB receive */ + } cancel_blob_receive_comp; /*!< Cancel BLOB receive complete */ + /** Set BLOB capabilities complete */ + struct { + int error_code; /*!< Result of setting BLOB capabilities */ + esp_ble_mesh_set_blob_capabilities_t input; /*!< Input of setting BLOB capabilities */ + } set_blob_capabilities_comp; /*!< Set BLOB capabilities complete */ + /** BLOB transfer get */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Get message context */ + } blob_transfer_get; /*!< BLOB transfer get */ + /** BLOB transfer start */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Start message context */ + } blob_transfer_start; /*!< BLOB transfer start */ + /** BLOB transfer cancel */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Cancel message context */ + } blob_transfer_cancel; /*!< BLOB transfer cancel */ + /** BLOB block get */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Get message context */ + } blob_block_get; /*!< BLOB block get */ + /** BLOB block start */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Start message context */ + } blob_block_start; /*!< BLOB block start */ + /** BLOB chunk transfer */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Chunk Transfer message context */ + } blob_chunk_transfer; /*!< BLOB chunk transfer */ + /** BLOB information get */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Information Get message context */ + } blob_information_get; /*!< BLOB information get */ + /** Block receive complete */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB block completely */ + } block_receive_comp; /*!< Block receive complete */ + /** BLOB receive complete */ + struct { + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB completely */ + } blob_receive_comp; /*!< BLOB receive complete */ +} esp_ble_mesh_mbt_server_cb_value_t; /*!< BLOB Transfer Server model callback value union */ + +/** BLOB Transfer Server model callback parameters */ +typedef struct { + esp_ble_mesh_mbt_server_cb_value_t value; /*!< Value of the received blob transfer messages */ +} esp_ble_mesh_mbt_server_cb_param_t; /*!< BLOB Transfer Server model callback parameters */ + +/** This enum value is the event of BLOB Transfer Server model */ +typedef enum { + ESP_BLE_MESH_MBT_SERVER_INITIALIZE_BLOB_RECEIVE_COMP_EVT, + ESP_BLE_MESH_MBT_SERVER_CANCEL_BLOB_RECEIVE_COMP_EVT, + ESP_BLE_MESH_MBT_SERVER_SET_BLOB_CAPABILITIES_COMP_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_GET_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_START_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_CANCEL_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_BLOCK_GET_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_BLOCK_START_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_CHUNK_TRANSFER_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_INFORMATION_GET_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOCK_RECEIVE_COMP_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_COMP_EVT, + ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_TIMEOUT_EVT, + ESP_BLE_MESH_MBT_SERVER_EVT_MAX, +} esp_ble_mesh_mbt_server_cb_event_t; + +/** + * @brief BLOB Transfer Client model callback function type + * + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_mbt_client_cb_t)(esp_ble_mesh_mbt_client_cb_event_t event, + esp_ble_mesh_mbt_client_cb_param_t *param); + +/** + * @brief BLOB Transfer Server model callback function type + * + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_mbt_server_cb_t)(esp_ble_mesh_mbt_server_cb_event_t event, + esp_ble_mesh_mbt_server_cb_param_t *param); + +/** + * @brief Register BLE Mesh BLOB Transfer Client model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback); + +/** + * @brief Register BLE Mesh BLOB Transfer Server model callback. + * + * @param[in] callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback); + +/** + * @brief BLOB Transfer Client starts Retrieve Capabilities procedure. + * + * @param[in] input: The input of Retrieve Capabilities procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input); + +/** + * @brief BLOB Transfer Client starts Transfer BLOB procedure. + * + * @param[in] input: The input of Transfer BLOB procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input); + +/** + * @brief BLOB Transfer Client starts Send Block sub-procedure. + * + * @param[in] input: The input of Send Block sub-procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input); + +/** + * @brief BLOB Transfer Client starts Send Data sub-procedure. + * + * @param[in] input: The input of Send Data sub-procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input); + +/** + * @brief BLOB Transfer Client starts Determine Block Status sub-procedure. + * + * @param[in] input: The input of Determine Block Status sub-procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input); + +/** + * @brief BLOB Transfer Client starts Determine Transfer Status procedure. + * + * @param[in] input: The input of Determine Transfer Status procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input); + +/** + * @brief BLOB Transfer Client starts Cancel Transfer procedure. + * + * @param[in] input: The input of Cancel Transfer procedure. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input); + +/** + * @brief BLOB Transfer Client gets BLOB receiver. + * + * @param[in] model: BLOB Transfer Client model. + * @param[in] unicast_addr: Unicast address of the BLOB receiver. + * + * @return BLOB receiver on success or NULL on failure. + * + */ +const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, + uint16_t unicast_addr); + +/** + * @brief BLOB Transfer Client gets active BLOB receiver list. + * + * @param[in] model: BLOB Transfer Client model. + * + * @return Active BLOB receiver list on success or NULL on failure. + * + */ +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model); + +/** + * @brief BLOB Transfer Client gets BLOB transfer progress. + * + * @param[in] model: BLOB Transfer Client model. + * @param[in] unicast_addr: Unicast address of the BLOB receiver. + * @param[in] block_percent: Block reception percent to be updated. + * @param[in] chunk_percent: Chunk reception percent of the current block to be updated. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, + uint16_t unicast_addr, + uint8_t *block_percent, + uint8_t *chunk_percent); + +/** + * @brief BLOB Transfer Client sets Transfer TTL state. + * + * @param[in] model: BLOB Transfer Client model. + * @param[in] transfer_ttl: Transfer TTL state value. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, + uint8_t transfer_ttl); + +/** + * @brief BLOB Transfer Client clear Transfer TTL state. + * + * @param[in] model: BLOB Transfer Client model. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model); + +/** + * @brief BLOB Transfer Client sets AppKey Index state. + * + * @param[in] model: BLOB Transfer Client model. + * @param[in] app_idx: AppKey Index state value. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, + uint16_t app_idx); + +/** + * @brief BLOB Transfer Client clear AppKey Index state. + * + * @param[in] model: BLOB Transfer Client model. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model); + +/** + * @brief BLOB Transfer Client sets Multicast Address state. + * + * @param[in] model: BLOB Transfer Client model. + * @param[in] multicast_addr: Multicast Address state value. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, + uint16_t multicast_addr); + +/** + * @brief BLOB Transfer Client clear Multicast Address state. + * + * @param[in] model: BLOB Transfer Client model. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model); + +/** + * @brief BLOB Transfer Server initializes BLOB receive. + * + * @param[in] input: The input of initializing BLOB receive. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input); + +/** + * @brief BLOB Transfer Server cancels BLOB receive. + * + * @param[in] input: The input of cancelling BLOB receive. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input); + +/** + * @brief BLOB Transfer Server sets BLOB capabilities. + * + * @param[in] input: The input of setting BLOB capabilities. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input); + +/** + * @brief BLOB Transfer Server gets current BLOB reception progress. + * + * @param[in] model: BLOB Transfer Server model. + * @param[in] reception_progress: Reception progress to be updated. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, + uint8_t *reception_progress); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_MBT_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c new file mode 100644 index 0000000000..3da11c10d2 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c @@ -0,0 +1,490 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_agg_model.h" +#include "esp_ble_mesh_agg_model_api.h" + +#if CONFIG_BLE_MESH_AGG_CLI + +extern int bt_mesh_agg_sequence(void *param, void *sequence); + +/* Opcodes Aggregator Client model related functions */ + +static inline void btc_ble_mesh_agg_client_cb_to_app(esp_ble_mesh_agg_client_cb_event_t event, + esp_ble_mesh_agg_client_cb_param_t *param) +{ + esp_ble_mesh_agg_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_AGG_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_agg_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_agg_client_args_t *dst = p_dest; + btc_ble_mesh_agg_client_args_t *src = p_src; + uint16_t length = 0; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_AGG_CLIENT_SEND: + dst->agg_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->agg_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_agg_client_msg_t)); + if (dst->agg_send.params && dst->agg_send.msg) { + memcpy(dst->agg_send.params, src->agg_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->agg_send.msg, src->agg_send.msg, + sizeof(esp_ble_mesh_agg_client_msg_t)); + if (src->agg_send.params->opcode == ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE) { + if (src->agg_send.msg->agg_sequence.items) { + length = src->agg_send.msg->agg_sequence.items->len; + dst->agg_send.msg->agg_sequence.items = bt_mesh_alloc_buf(length); + if (!dst->agg_send.msg->agg_sequence.items) { + BT_ERR("%s, Out of memory", __func__); + break; + } + + net_buf_simple_add_mem(dst->agg_send.msg->agg_sequence.items, + src->agg_send.msg->agg_sequence.items->data, + src->agg_send.msg->agg_sequence.items->len); + } + } + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_agg_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_agg_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_agg_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_AGG_CLIENT_SEND: + if (arg->agg_send.msg) { + if (arg->agg_send.params) { + if (arg->agg_send.params->opcode == ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE) { + bt_mesh_free_buf(arg->agg_send.msg->agg_sequence.items); + } + } + bt_mesh_free(arg->agg_send.msg); + } + if (arg->agg_send.params) { + bt_mesh_free(arg->agg_send.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_agg_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_agg_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_agg_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_AGG_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_AGG_CLIENT_RECV_PUB_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE: + case ESP_BLE_MESH_MODEL_OP_AGG_STATUS: + if (p_src_data->recv.agg_status.items) { + length = p_src_data->recv.agg_status.items->len; + p_dest_data->recv.agg_status.items = bt_mesh_alloc_buf(length); + if (!p_dest_data->recv.agg_status.items) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + net_buf_simple_add_mem(p_dest_data->recv.agg_status.items, + p_src_data->recv.agg_status.items->data, + p_src_data->recv.agg_status.items->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_AGG_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_AGG_CLIENT_SEND_TIMEOUT_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_agg_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_agg_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_agg_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_AGG_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_AGG_CLIENT_RECV_PUB_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE: + case ESP_BLE_MESH_MODEL_OP_AGG_STATUS: + bt_mesh_free_buf(arg->recv.agg_status.items); + break; + default: + break; + } + } + case ESP_BLE_MESH_AGG_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_AGG_CLIENT_SEND_TIMEOUT_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_agg_client_cb(esp_ble_mesh_agg_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_AGG_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_AGG_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_agg_client_cb_param_t), + btc_ble_mesh_agg_client_copy_req_data, + btc_ble_mesh_agg_client_free_req_data); +} + +void bt_mesh_agg_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_agg_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_AGG_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_AGG_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_AGG_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_AGG_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown Opcodes Aggregator client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_agg_client_cb(&cb_params, act); +} + +void btc_ble_mesh_agg_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_agg_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_agg_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_agg_client_msg_t *set) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL || set == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE: + return bt_mesh_agg_sequence(¶m, &set->agg_sequence); + default: + BT_ERR("Invalid Opcodes Aggregator opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_agg_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_agg_client_cb_param_t cb = {0}; + btc_ble_mesh_agg_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_agg_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_AGG_CLIENT_SEND: + cb.params = arg->agg_send.params; + cb.send.err_code = btc_ble_mesh_agg_client_send(arg->agg_send.params, + arg->agg_send.msg); + btc_ble_mesh_agg_client_cb(&cb, + ESP_BLE_MESH_AGG_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_agg_client_arg_deep_free(msg); +} + +void btc_ble_mesh_agg_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_agg_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_agg_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_AGG_CLIENT_EVT_MAX) { + btc_ble_mesh_agg_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_agg_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_AGG_CLI */ + +#if CONFIG_BLE_MESH_AGG_SRV + +/* Opcodes Aggregator Server model related functions */ + +static inline void btc_ble_mesh_agg_server_cb_to_app(esp_ble_mesh_agg_server_cb_event_t event, + esp_ble_mesh_agg_server_cb_param_t *param) +{ + esp_ble_mesh_agg_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_AGG_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_agg_server_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_agg_server_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_agg_server_cb_param_t *p_src_data = p_src; + uint16_t length = 0U; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_AGG_SERVER_RECV_MSG_EVT: + if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE) { + if (p_src_data->recv.agg_sequence.items) { + length = p_src_data->recv.agg_sequence.items->len; + p_dest_data->recv.agg_sequence.items = bt_mesh_alloc_buf(length); + if (!p_dest_data->recv.agg_sequence.items) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + + net_buf_simple_add_mem(p_dest_data->recv.agg_sequence.items, + p_src_data->recv.agg_sequence.items->data, + p_src_data->recv.agg_sequence.items->len); + } + } + break; + default: + break; + } +} + +static void btc_ble_mesh_agg_server_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_agg_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_agg_server_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_AGG_SERVER_RECV_MSG_EVT: + if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_AGG_SEQUENCE) { + bt_mesh_free_buf(arg->recv.agg_sequence.items); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_agg_server_cb( + esp_ble_mesh_agg_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_AGG_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_AGG_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_agg_server_cb_param_t), + btc_ble_mesh_agg_server_copy_req_data, + btc_ble_mesh_agg_server_free_req_data); +} + +void bt_mesh_agg_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len) +{ + esp_ble_mesh_agg_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_AGG_SERVER_RECV_MSG: + act = ESP_BLE_MESH_AGG_SERVER_RECV_MSG_EVT; + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + break; + default: + BT_ERR("Unknown Opcodes Aggregator server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + btc_ble_mesh_agg_server_cb(&cb_params, act); +} + +void btc_ble_mesh_agg_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_agg_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_agg_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_AGG_SERVER_EVT_MAX) { + btc_ble_mesh_agg_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_agg_server_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_AGG_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c new file mode 100644 index 0000000000..36e9446024 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c @@ -0,0 +1,462 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_brc_model.h" +#include "esp_ble_mesh_brc_model_api.h" + +#if CONFIG_BLE_MESH_BRC_CLI + +extern int bt_mesh_subnet_bridge_get(void *param); +extern int bt_mesh_subnet_bridge_set(void *param, uint8_t subnet_bridge); +extern int bt_mesh_bridging_table_add(void *param, void *add); +extern int bt_mesh_bridging_table_remove(void *param, void *remove); +extern int bt_mesh_bridged_subnets_get(void *param, uint8_t bridge_filter, + uint16_t net_idx, uint8_t bridge_start_idx); +extern int bt_mesh_bridging_table_get(void *param, + uint16_t bridge_net_idx_1, + uint16_t bridge_net_idx_2, + uint16_t bridge_start_idx); +extern int bt_mesh_bridging_table_size_get(void *param); + +/* Bridge Configuration Client model related functions */ + +static inline void btc_ble_mesh_brc_client_cb_to_app(esp_ble_mesh_brc_client_cb_event_t event, + esp_ble_mesh_brc_client_cb_param_t *param) +{ + esp_ble_mesh_brc_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_BRC_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_brc_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_brc_client_args_t *dst = p_dest; + btc_ble_mesh_brc_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_BRC_CLIENT_SEND: + dst->brc_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->brc_send.params) { + memcpy(dst->brc_send.params, src->brc_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->brc_send.msg) { + dst->brc_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_brc_client_msg_t)); + if (dst->brc_send.msg) { + memcpy(dst->brc_send.msg, src->brc_send.msg, + sizeof(esp_ble_mesh_brc_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_brc_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_brc_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_brc_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_BRC_CLIENT_SEND: + if (arg->brc_send.msg) { + bt_mesh_free(arg->brc_send.msg); + } + if (arg->brc_send.params) { + bt_mesh_free(arg->brc_send.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_brc_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_brc_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_brc_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_BRC_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_BRC_CLIENT_RECV_PUB_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_LIST: + if (p_src_data->recv.bridged_subnets_list.net_idx_pair) { + length = p_src_data->recv.bridged_subnets_list.bridged_entry_list_size * sizeof(esp_ble_mesh_bridge_net_idx_pair_entry_t); + p_dest_data->recv.bridged_subnets_list.net_idx_pair = bt_mesh_calloc(length); + if (!p_dest_data->recv.bridged_subnets_list.net_idx_pair) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + memcpy(p_dest_data->recv.bridged_subnets_list.net_idx_pair, + p_src_data->recv.bridged_subnets_list.net_idx_pair, length); + } + break; + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_LIST: + if (p_src_data->recv.bridging_table_list.bridged_addr_list) { + length = p_src_data->recv.bridging_table_list.bridged_addr_list_size * sizeof(esp_ble_mesh_bridged_addr_list_entry_t); + p_dest_data->recv.bridging_table_list.bridged_addr_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.bridging_table_list.bridged_addr_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + memcpy(p_dest_data->recv.bridging_table_list.bridged_addr_list, + p_src_data->recv.bridging_table_list.bridged_addr_list, length); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_BRC_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_BRC_CLIENT_SEND_TIMEOUT_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_brc_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_brc_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_brc_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_BRC_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_BRC_CLIENT_RECV_PUB_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_LIST: + bt_mesh_free(arg->recv.bridged_subnets_list.net_idx_pair); + break; + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_LIST: + bt_mesh_free(arg->recv.bridging_table_list.bridged_addr_list); + break; + default: + break; + } + } + case ESP_BLE_MESH_BRC_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_BRC_CLIENT_SEND_TIMEOUT_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_brc_client_cb(esp_ble_mesh_brc_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_BRC_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_BRC_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_brc_client_cb_param_t), + btc_ble_mesh_brc_client_copy_req_data, + btc_ble_mesh_brc_client_free_req_data); +} + +void bt_mesh_brc_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_brc_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_BRC_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_BRC_CLIENT_RECV_PUB_EVT; + break; + case BTC_BLE_MESH_EVT_BRC_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_BRC_CLIENT_SEND_TIMEOUT_EVT; + break; + default: + BT_ERR("Unknown Bridge Config client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_brc_client_cb(&cb_params, act); +} + +void btc_ble_mesh_brc_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_brc_client_cb_evt_to_btc(opcode, + ESP_BLE_MESH_BRC_CLIENT_RECV_PUB_EVT, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_brc_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_brc_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET: + case ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_SET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_ADD: + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_REMOVE: + if (msg == NULL) { + BT_ERR("Invalid Bridge Config message, opcode 0x%04x", params->opcode); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_GET: + return bt_mesh_subnet_bridge_get(¶m); + case ESP_BLE_MESH_MODEL_OP_BRIDGED_SUBNETS_GET: + return bt_mesh_bridged_subnets_get(¶m, msg->bridged_subnets_get.bridge_filter, msg->bridged_subnets_get.bridge_net_idx, msg->bridged_subnets_get.bridge_start_idx); + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_GET: + return bt_mesh_bridging_table_get(¶m, msg->bridging_table_get.bridge_net_idx_1, msg->bridging_table_get.bridge_net_idx_2, msg->bridging_table_get.bridge_start_idx); + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_SIZE_GET: + return bt_mesh_bridging_table_size_get(¶m); + case ESP_BLE_MESH_MODEL_OP_SUBNET_BRIDGE_SET: + return bt_mesh_subnet_bridge_set(¶m, msg->subnet_bridge_set.subnet_bridge); + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_ADD: + return bt_mesh_bridging_table_add(¶m, &msg->bridging_table_add); + case ESP_BLE_MESH_MODEL_OP_BRIDGING_TABLE_REMOVE: + return bt_mesh_bridging_table_remove(¶m, &msg->bridging_table_remove); + default: + BT_ERR("Invalid Bridge Config opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_brc_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_brc_client_cb_param_t cb = {0}; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + btc_ble_mesh_brc_client_args_t *arg = (btc_ble_mesh_brc_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_BRC_CLIENT_SEND: + cb.params = arg->brc_send.params; + cb.send.err_code = btc_ble_mesh_brc_client_send(arg->brc_send.params, + arg->brc_send.msg); + btc_ble_mesh_brc_client_cb(&cb, + ESP_BLE_MESH_BRC_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_brc_client_arg_deep_free(msg); +} + +void btc_ble_mesh_brc_client_cb_handler(btc_msg_t *msg) +{ + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + esp_ble_mesh_brc_client_cb_param_t *arg = (esp_ble_mesh_brc_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_BRC_CLIENT_EVT_MAX) { + btc_ble_mesh_brc_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_brc_client_free_req_data(msg); +} +#endif /* CONFIG_BLE_MESH_BRC_CLI */ + +#if CONFIG_BLE_MESH_BRC_SRV + +/* Bridge Config Server model related functions */ +static inline void btc_ble_mesh_brc_server_cb_to_app(esp_ble_mesh_brc_server_cb_event_t event, + esp_ble_mesh_brc_server_cb_param_t *param) +{ + esp_ble_mesh_brc_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_BRC_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_brc_server_cb(esp_ble_mesh_brc_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_BRC_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_BRC_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_brc_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_brc_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_brc_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_BRC_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_BRC_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown Bridge Config server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_brc_server_cb(&cb_params, act); +} + +void btc_ble_mesh_brc_server_cb_handler(btc_msg_t *msg) +{ + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + esp_ble_mesh_brc_server_cb_param_t *arg = (esp_ble_mesh_brc_server_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_BRC_SERVER_EVT_MAX) { + btc_ble_mesh_brc_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} +#endif /* CONFIG_BLE_MESH_BRC_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c new file mode 100644 index 0000000000..aa4cadad11 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c @@ -0,0 +1,711 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_df_model.h" +#include "esp_ble_mesh_df_model_api.h" + +#if CONFIG_BLE_MESH_DF_CLI + +extern int bt_mesh_directed_control_get(void *param, uint16_t net_idx); +extern int bt_mesh_directed_control_set(void *param, void *set); +extern int bt_mesh_path_metric_get(void *param, uint16_t net_idx); +extern int bt_mesh_path_metric_set(void *param, void *set); +extern int bt_mesh_discovery_table_caps_get(void *param, uint16_t net_idx); +extern int bt_mesh_discovery_table_caps_set(void *param, void *set); +extern int bt_mesh_forwarding_table_add(void *param, void *add); +extern int bt_mesh_forwarding_table_del(void *param, void *del); +extern int bt_mesh_forwarding_table_deps_add(void *param, void *add); +extern int bt_mesh_forwarding_table_deps_del(void *param, void *del); +extern int bt_mesh_forwarding_table_entries_cnt_get(void *param, uint16_t net_idx); +extern int bt_mesh_forwarding_table_entries_get(void *param, void *get); +extern int bt_mesh_forwarding_table_deps_get(void *param, void *get); +extern int bt_mesh_wanted_lanes_get(void *param, uint16_t net_idx); +extern int bt_mesh_wanted_lanes_set(void *param, uint16_t net_idx, uint8_t wanted_lanes); +extern int bt_mesh_two_way_path_get(void *param, uint16_t net_idx); +extern int bt_mesh_two_way_path_set(void *param, uint16_t net_idx, uint8_t two_way_path); +extern int bt_mesh_path_echo_interval_get(void *param, uint16_t net_idx); +extern int bt_mesh_path_echo_interval_set(void *param, uint16_t net_idx, + uint8_t unicast_echo_interval, + uint8_t multicast_echo_interval); +extern int bt_mesh_directed_net_transmit_get(void *param); +extern int bt_mesh_directed_net_transmit_set(void *param, uint8_t transmit); +extern int bt_mesh_directed_relay_retransmit_get(void *param); +extern int bt_mesh_directed_relay_retransmit_set(void *param, uint8_t retransmit); +extern int bt_mesh_rssi_threshold_get(void *param); +extern int bt_mesh_rssi_threshold_set(void *param, uint8_t rssi_margin); +extern int bt_mesh_directed_paths_get(void *param); +extern int bt_mesh_directed_pub_policy_get(void *param, void *get); +extern int bt_mesh_directed_pub_policy_set(void *param, void *set); +extern int bt_mesh_path_discovery_timing_ctl_get(void *param); +extern int bt_mesh_path_discovery_timing_ctl_set(void *param, void *set); +extern int bt_mesh_directed_ctl_net_transmit_get(void *param); +extern int bt_mesh_directed_ctl_net_transmit_set(void *param, uint8_t transmit); +extern int bt_mesh_directed_ctl_relay_retransmit_get(void *param); +extern int bt_mesh_directed_ctl_relay_retransmit_set(void *param, uint8_t retransmit); + +/* Directed Forwarding Config Client model related functions */ + +static inline void btc_ble_mesh_df_client_cb_to_app(esp_ble_mesh_df_client_cb_event_t event, + esp_ble_mesh_df_client_cb_param_t *param) +{ + esp_ble_mesh_df_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_DF_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_df_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_df_client_args_t *dst = p_dest; + btc_ble_mesh_df_client_args_t *src = p_src; + uint16_t length = 0; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DF_CLIENT_GET_STATE: { + dst->df_get.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->df_get.params) { + memcpy(dst->df_get.params, src->df_get.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->df_get.get) { + dst->df_get.get = bt_mesh_calloc(sizeof(esp_ble_mesh_df_client_get_t)); + if (dst->df_get.get) { + memcpy(dst->df_get.get, src->df_get.get, + sizeof(esp_ble_mesh_df_client_get_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + } + case BTC_BLE_MESH_ACT_DF_CLIENT_SET_STATE: { + dst->df_set.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->df_set.set = bt_mesh_calloc(sizeof(esp_ble_mesh_df_client_set_t)); + if (dst->df_set.params && dst->df_set.set) { + memcpy(dst->df_set.params, src->df_set.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->df_set.set, src->df_set.set, + sizeof(esp_ble_mesh_df_client_set_t)); + + switch (src->df_set.params->opcode) { + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_ADD: + if (src->df_set.set->forwarding_table_deps_add.dep_origin_uar_list && + src->df_set.set->forwarding_table_deps_add.dep_origin_uar_list_size) { + length = src->df_set.set->forwarding_table_deps_add.dep_origin_uar_list_size * sizeof(esp_ble_mesh_uar_t); + dst->df_set.set->forwarding_table_deps_add.dep_origin_uar_list = bt_mesh_calloc(length); + if (!dst->df_set.set->forwarding_table_deps_add.dep_origin_uar_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(dst->df_set.set->forwarding_table_deps_add.dep_origin_uar_list, + src->df_set.set->forwarding_table_deps_add.dep_origin_uar_list, + length); + } + if (src->df_set.set->forwarding_table_deps_add.dep_target_uar_list && + src->df_set.set->forwarding_table_deps_add.dep_target_uar_list_size) { + length = src->df_set.set->forwarding_table_deps_add.dep_target_uar_list_size * sizeof(esp_ble_mesh_uar_t); + dst->df_set.set->forwarding_table_deps_add.dep_target_uar_list = bt_mesh_calloc(length); + if (!dst->df_set.set->forwarding_table_deps_add.dep_target_uar_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(dst->df_set.set->forwarding_table_deps_add.dep_target_uar_list, + src->df_set.set->forwarding_table_deps_add.dep_target_uar_list, + length); + } + break; + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_DEL: + if (src->df_set.set->forwarding_table_deps_del.dep_origin_list && + src->df_set.set->forwarding_table_deps_del.dep_origin_list_size) { + length = src->df_set.set->forwarding_table_deps_del.dep_origin_list_size * 2; + dst->df_set.set->forwarding_table_deps_del.dep_origin_list = bt_mesh_calloc(length); + if (!dst->df_set.set->forwarding_table_deps_del.dep_origin_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(dst->df_set.set->forwarding_table_deps_del.dep_origin_list, + src->df_set.set->forwarding_table_deps_del.dep_origin_list, + length); + } + if (src->df_set.set->forwarding_table_deps_del.dep_target_list && + src->df_set.set->forwarding_table_deps_del.dep_target_list_size) { + length = src->df_set.set->forwarding_table_deps_del.dep_target_list_size * 2; + dst->df_set.set->forwarding_table_deps_del.dep_target_list = bt_mesh_calloc(length); + if (!dst->df_set.set->forwarding_table_deps_del.dep_target_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(dst->df_set.set->forwarding_table_deps_del.dep_target_list, + src->df_set.set->forwarding_table_deps_del.dep_target_list, + length); + } + break; + default: + break; + } + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + } + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_df_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_df_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_df_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DF_CLIENT_GET_STATE: + if (arg->df_get.params) { + bt_mesh_free(arg->df_get.params); + } + if (arg->df_get.get) { + bt_mesh_free(arg->df_get.get); + } + break; + case BTC_BLE_MESH_ACT_DF_CLIENT_SET_STATE: + if (arg->df_set.set) { + if (arg->df_set.params) { + switch (arg->df_set.params->opcode) { + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_ADD: + bt_mesh_free(arg->df_set.set->forwarding_table_deps_add.dep_origin_uar_list); + bt_mesh_free(arg->df_set.set->forwarding_table_deps_add.dep_target_uar_list); + break; + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_DEL: + bt_mesh_free(arg->df_set.set->forwarding_table_deps_del.dep_origin_list); + bt_mesh_free(arg->df_set.set->forwarding_table_deps_del.dep_target_list); + break; + default: + break; + } + } + bt_mesh_free(arg->df_set.set); + } + if (arg->df_set.params) { + bt_mesh_free(arg->df_set.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_df_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_df_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_df_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_DF_CLIENT_RECV_GET_RSP_EVT: + case ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT: + case ESP_BLE_MESH_DF_CLIENT_RECV_PUB_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_STATUS: + if (p_src_data->recv.forwarding_table_entries_status.entry_list) { + length = p_src_data->recv.forwarding_table_entries_status.entry_list_size * sizeof(esp_ble_mesh_forwarding_table_entry_t); + p_dest_data->recv.forwarding_table_entries_status.entry_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.forwarding_table_entries_status.entry_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->recv.forwarding_table_entries_status.entry_list, + p_src_data->recv.forwarding_table_entries_status.entry_list, + length); + } + break; + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET_STATUS: + if (p_src_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list) { + length = p_src_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list_size * sizeof(esp_ble_mesh_uar_t); + p_dest_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list, + p_src_data->recv.forwarding_table_deps_get_status.dep_origin_uar_list, + length); + } + if (p_src_data->recv.forwarding_table_deps_get_status.dep_target_uar_list) { + length = p_src_data->recv.forwarding_table_deps_get_status.dep_target_uar_list_size * sizeof(esp_ble_mesh_uar_t); + p_dest_data->recv.forwarding_table_deps_get_status.dep_target_uar_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.forwarding_table_deps_get_status.dep_target_uar_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->recv.forwarding_table_deps_get_status.dep_target_uar_list, + p_src_data->recv.forwarding_table_deps_get_status.dep_target_uar_list, + length); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_DF_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_df_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_df_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_df_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_DF_CLIENT_RECV_GET_RSP_EVT: + case ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT: + case ESP_BLE_MESH_DF_CLIENT_RECV_PUB_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_STATUS: + bt_mesh_free(arg->recv.forwarding_table_entries_status.entry_list); + break; + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET_STATUS: + bt_mesh_free(arg->recv.forwarding_table_deps_get_status.dep_origin_uar_list); + bt_mesh_free(arg->recv.forwarding_table_deps_get_status.dep_target_uar_list); + break; + default: + break; + } + } + case ESP_BLE_MESH_DF_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_df_client_cb(esp_ble_mesh_df_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DF_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DF_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_df_client_cb_param_t), + btc_ble_mesh_df_client_copy_req_data, + btc_ble_mesh_df_client_free_req_data); +} + +void bt_mesh_df_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_df_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DF_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_DF_CLIENT_RECV_GET_RSP: + act = ESP_BLE_MESH_DF_CLIENT_RECV_GET_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_DF_CLIENT_RECV_SET_RSP: + act = ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_DF_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_DF_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown Directed Forward Config client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_df_client_cb(&cb_params, act); +} + +void btc_ble_mesh_df_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_df_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_DF_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_df_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_get_t *get) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_GET: + case ESP_BLE_MESH_MODEL_OP_PATH_METRIC_GET: + case ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET: + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET: + case ESP_BLE_MESH_MODEL_OP_WANTED_LANES_GET: + case ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_GET: + case ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_GET: + case ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_GET: + if (get == NULL) { + BT_ERR("Invalid Directed Forward Config Get"); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_GET: + return bt_mesh_directed_control_get(¶m, get->directed_control_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_PATH_METRIC_GET: + return bt_mesh_path_metric_get(¶m, get->path_metric_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_GET: + return bt_mesh_discovery_table_caps_get(¶m, get->disc_table_caps_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_CNT_GET: + return bt_mesh_forwarding_table_entries_cnt_get(¶m, get->forwarding_table_entries_cnt_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ENTRIES_GET: + return bt_mesh_forwarding_table_entries_get(¶m, &get->forwarding_table_entries_get); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_GET: + return bt_mesh_forwarding_table_deps_get(¶m, &get->forwarding_table_deps_get); + case ESP_BLE_MESH_MODEL_OP_WANTED_LANES_GET: + return bt_mesh_wanted_lanes_get(¶m, get->wanted_lanes_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_GET: + return bt_mesh_two_way_path_get(¶m, get->two_way_path_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_GET: + return bt_mesh_path_echo_interval_get(¶m, get->path_echo_interval_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_GET: + return bt_mesh_directed_net_transmit_get(¶m); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_GET: + return bt_mesh_directed_relay_retransmit_get(¶m); + case ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_GET: + return bt_mesh_rssi_threshold_get(¶m); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_PATHS_GET: + return bt_mesh_directed_paths_get(¶m); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_GET: + return bt_mesh_directed_pub_policy_get(¶m, &get->directed_pub_policy_get); + case ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_GET: + return bt_mesh_path_discovery_timing_ctl_get(¶m); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_GET: + return bt_mesh_directed_ctl_net_transmit_get(¶m); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_GET: + return bt_mesh_directed_ctl_relay_retransmit_get(¶m); + default: + BT_ERR("Invalid Directed Forward Config Get opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +static int btc_ble_mesh_df_client_set_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_df_client_set_t *set) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL || set == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET: + return bt_mesh_directed_control_set(¶m, &set->directed_control_set); + case ESP_BLE_MESH_MODEL_OP_PATH_METRIC_SET: + return bt_mesh_path_metric_set(¶m, &set->path_metric_set); + case ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_SET: + return bt_mesh_discovery_table_caps_set(¶m, &set->disc_table_caps_set); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_ADD: + return bt_mesh_forwarding_table_add(¶m, &set->forwarding_table_add); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEL: + return bt_mesh_forwarding_table_del(¶m, &set->forwarding_table_del); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_ADD: + return bt_mesh_forwarding_table_deps_add(¶m, &set->forwarding_table_deps_add); + case ESP_BLE_MESH_MODEL_OP_FORWARDING_TABLE_DEPS_DEL: + return bt_mesh_forwarding_table_deps_del(¶m, &set->forwarding_table_deps_del); + case ESP_BLE_MESH_MODEL_OP_WANTED_LANES_SET: + return bt_mesh_wanted_lanes_set(¶m, set->wanted_lanes_set.net_idx, + set->wanted_lanes_set.wanted_lanes); + case ESP_BLE_MESH_MODEL_OP_TWO_WAY_PATH_SET: + return bt_mesh_two_way_path_set(¶m, set->two_way_path_set.net_idx, + set->two_way_path_set.two_way_path); + case ESP_BLE_MESH_MODEL_OP_PATH_ECHO_INTERVAL_SET: + return bt_mesh_path_echo_interval_set(¶m, set->path_echo_interval_set.net_idx, + set->path_echo_interval_set.unicast_echo_interval, + set->path_echo_interval_set.multicast_echo_interval); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_NET_TRANSMIT_SET: + return bt_mesh_directed_net_transmit_set(¶m, set->directed_net_transmit_set.net_transmit); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_RELAY_RETRANSMIT_SET: + return bt_mesh_directed_relay_retransmit_set(¶m, set->directed_relay_retransmit_set.relay_retransmit); + case ESP_BLE_MESH_MODEL_OP_RSSI_THRESHOLD_SET: + return bt_mesh_rssi_threshold_set(¶m, set->rssi_threshold_set.rssi_margin); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_PUB_POLICY_SET: + return bt_mesh_directed_pub_policy_set(¶m, &set->directed_pub_policy_set); + case ESP_BLE_MESH_MODEL_OP_PATH_DISCOVERY_TIMING_CTL_SET: + return bt_mesh_path_discovery_timing_ctl_set(¶m, &set->path_disc_timing_ctl_set); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_NET_TRANSMIT_SET: + return bt_mesh_directed_ctl_net_transmit_set(¶m, set->directed_ctl_net_transmit_set.net_transmit); + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CTL_RELAY_RETRANSMIT_SET: + return bt_mesh_directed_ctl_relay_retransmit_set(¶m, set->directed_ctl_relay_retransmit_set.relay_retransmit); + default: + BT_ERR("Invalid Directed Forward Config Set opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_df_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_df_client_cb_param_t cb = {0}; + btc_ble_mesh_df_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_df_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DF_CLIENT_GET_STATE: + cb.params = arg->df_get.params; + cb.send.err_code = btc_ble_mesh_df_client_get_state(arg->df_get.params, + arg->df_get.get); + btc_ble_mesh_df_client_cb(&cb, + ESP_BLE_MESH_DF_CLIENT_SEND_COMP_EVT); + break; + case BTC_BLE_MESH_ACT_DF_CLIENT_SET_STATE: + cb.params = arg->df_set.params; + cb.send.err_code = btc_ble_mesh_df_client_set_state(arg->df_set.params, + arg->df_set.set); + btc_ble_mesh_df_client_cb(&cb, + ESP_BLE_MESH_DF_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_df_client_arg_deep_free(msg); +} + +void btc_ble_mesh_df_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_df_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_df_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_DF_CLIENT_EVT_MAX) { + btc_ble_mesh_df_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_df_client_free_req_data(msg); +} +#endif /* CONFIG_BLE_MESH_DF_CLI */ + +#if CONFIG_BLE_MESH_DF_SRV + +/* Directed Forwarding Config Server model related functions */ + +static inline void btc_ble_mesh_df_server_cb_to_app(esp_ble_mesh_df_server_cb_event_t event, + esp_ble_mesh_df_server_cb_param_t *param) +{ + esp_ble_mesh_df_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_DF_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_df_server_cb( + esp_ble_mesh_df_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DF_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DF_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_df_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_df_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_df_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DF_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_DF_SERVER_STATE_CHANGE_EVT; + break; + case BTC_BLE_MESH_EVT_DF_SERVER_TABLE_CHANGE: + act = ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown Directed Forward Config server event type %d", event); + return; + } + + if (model) { + cb_params.model = (esp_ble_mesh_model_t *)model; + } + + if (ctx) { + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + } + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_df_server_cb(&cb_params, act); +} + +void btc_ble_mesh_df_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_df_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_df_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_DF_SERVER_EVT_MAX) { + btc_ble_mesh_df_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} +#endif /* CONFIG_BLE_MESH_DF_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c new file mode 100644 index 0000000000..25fc238032 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c @@ -0,0 +1,435 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_lcd_model.h" +#include "esp_ble_mesh_lcd_model_api.h" + +#if CONFIG_BLE_MESH_LCD_CLI + +extern int bt_mesh_large_comp_data_get(void *param, uint8_t page, uint16_t offset); +extern int bt_mesh_models_metadata_get(void *param, uint8_t metadata_page, uint16_t offset); + +/* Large Composition Data Client model related functions */ + +static inline void btc_ble_mesh_lcd_client_cb_to_app(esp_ble_mesh_lcd_client_cb_event_t event, + esp_ble_mesh_lcd_client_cb_param_t *param) +{ + esp_ble_mesh_lcd_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_LCD_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_lcd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_lcd_client_args_t *dst = p_dest; + btc_ble_mesh_lcd_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LCD_CLIENT_SEND: + dst->lcd_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->lcd_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_lcd_client_msg_t)); + if (dst->lcd_send.params && dst->lcd_send.msg) { + memcpy(dst->lcd_send.params, src->lcd_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->lcd_send.msg, src->lcd_send.msg, + sizeof(esp_ble_mesh_lcd_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_lcd_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_lcd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_lcd_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LCD_CLIENT_SEND: + if (arg->lcd_send.msg) { + bt_mesh_free(arg->lcd_send.msg); + } + if (arg->lcd_send.params) { + bt_mesh_free(arg->lcd_send.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_lcd_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_lcd_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_lcd_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_LCD_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_LCD_CLIENT_RECV_PUB_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_GET: + case ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_STATUS: + if (p_src_data->recv.large_comp_data_status.data) { + length = p_src_data->recv.large_comp_data_status.data->len; + p_dest_data->recv.large_comp_data_status.data = bt_mesh_alloc_buf(length); + if (!p_dest_data->recv.large_comp_data_status.data) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + net_buf_simple_add_mem(p_dest_data->recv.large_comp_data_status.data, + p_src_data->recv.large_comp_data_status.data->data, + p_src_data->recv.large_comp_data_status.data->len); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_GET: + case ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_STATUS: + if (p_src_data->recv.models_metadata_status.data) { + length = p_src_data->recv.models_metadata_status.data->len; + p_dest_data->recv.models_metadata_status.data = bt_mesh_alloc_buf(length); + if (!p_dest_data->recv.models_metadata_status.data) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + net_buf_simple_add_mem(p_dest_data->recv.models_metadata_status.data, + p_src_data->recv.models_metadata_status.data->data, + p_src_data->recv.models_metadata_status.data->len); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_LCD_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_LCD_CLIENT_SEND_TIMEOUT_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_lcd_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_lcd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_lcd_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_LCD_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_LCD_CLIENT_RECV_PUB_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_GET: + case ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_STATUS: + bt_mesh_free_buf(arg->recv.large_comp_data_status.data); + break; + case ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_GET: + case ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_STATUS: + bt_mesh_free_buf(arg->recv.models_metadata_status.data); + break; + default: + break; + } + } + case ESP_BLE_MESH_LCD_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_LCD_CLIENT_SEND_TIMEOUT_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_lcd_client_cb(esp_ble_mesh_lcd_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_LCD_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_LCD_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_lcd_client_cb_param_t), + btc_ble_mesh_lcd_client_copy_req_data, + btc_ble_mesh_lcd_client_free_req_data); +} + +void bt_mesh_lcd_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len) +{ + esp_ble_mesh_lcd_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_LCD_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_LCD_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_LCD_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_LCD_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown Large Comp Data client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_lcd_client_cb(&cb_params, act); +} + +void btc_ble_mesh_lcd_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_lcd_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_lcd_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_lcd_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL || msg == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_LARGE_COMP_DATA_GET: + return bt_mesh_large_comp_data_get(¶m, msg->large_comp_data_get.page, + msg->large_comp_data_get.offset); + case ESP_BLE_MESH_MODEL_OP_MODELS_METADATA_GET: + return bt_mesh_models_metadata_get(¶m, msg->models_metadata_get.metadata_page, + msg->models_metadata_get.offset); + default: + BT_ERR("Invalid Large Comp Data Set opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_lcd_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_lcd_client_cb_param_t cb = {0}; + btc_ble_mesh_lcd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_lcd_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_LCD_CLIENT_SEND: + cb.params = arg->lcd_send.params; + cb.send.err_code = btc_ble_mesh_lcd_client_send(arg->lcd_send.params, + arg->lcd_send.msg); + btc_ble_mesh_lcd_client_cb(&cb, ESP_BLE_MESH_LCD_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_lcd_client_arg_deep_free(msg); +} + +void btc_ble_mesh_lcd_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_lcd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_lcd_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_LCD_CLIENT_EVT_MAX) { + btc_ble_mesh_lcd_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_lcd_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_LCD_CLI */ + +#if CONFIG_BLE_MESH_LCD_SRV + +/* Large Comp Data Server model related functions */ + +static inline void btc_ble_mesh_lcd_server_cb_to_app(esp_ble_mesh_lcd_server_cb_event_t event, + esp_ble_mesh_lcd_server_cb_param_t *param) +{ + esp_ble_mesh_lcd_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_LCD_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_lcd_server_cb( + esp_ble_mesh_lcd_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_LCD_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_LCD_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_lcd_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_lcd_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len) +{ + esp_ble_mesh_lcd_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_LCD_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_LCD_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown Large Comp Data server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_lcd_server_cb(&cb_params, act); +} + +void btc_ble_mesh_lcd_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_lcd_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_lcd_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_LCD_SERVER_EVT_MAX) { + btc_ble_mesh_lcd_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_LCD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c new file mode 100644 index 0000000000..430bd31eee --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c @@ -0,0 +1,600 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_mbt_model.h" +#include "esp_ble_mesh_mbt_model_api.h" + +#if CONFIG_BLE_MESH_MBT_CLI + +extern int bt_mesh_retrieve_capabilities(void *input); +extern int bt_mesh_transfer_blob(void *input); +extern int bt_mesh_send_block(void *input); +extern int bt_mesh_send_data(void *input); +extern int bt_mesh_determine_block_status(void *input); +extern int bt_mesh_determine_transfer_status(void *input); +extern int bt_mesh_cancel_transfer(void *input); +extern int bt_mesh_set_transfer_ttl_state(void *model, uint8_t transfer_ttl); +extern int bt_mesh_clear_transfer_ttl_state(void *model); +extern int bt_mesh_set_app_idx_state(void *model, uint16_t app_idx); +extern int bt_mesh_clear_app_idx_state(void *model); +extern int bt_mesh_set_multicast_addr_state(void *model, uint16_t multicast_addr); +extern int bt_mesh_clear_multicast_addr_state(void *model); +extern int bt_mesh_initialize_blob_receive(void *input); +extern int bt_mesh_cancel_blob_receive(void *input); +extern int bt_mesh_set_blob_capabilities(void *model, void *input); + +static inline void btc_ble_mesh_blob_trans_client_cb_to_app(esp_ble_mesh_mbt_client_cb_event_t event, + esp_ble_mesh_mbt_client_cb_param_t *param) +{ + esp_ble_mesh_mbt_client_cb_t btc_ble_mesh_cb = + (esp_ble_mesh_mbt_client_cb_t)btc_profile_cb_get(BTC_PID_MBT_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_mbt_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_mbt_client_args_t *dst = (btc_ble_mesh_mbt_client_args_t *)p_dest; + btc_ble_mesh_mbt_client_args_t *src = (btc_ble_mesh_mbt_client_args_t *)p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES: + if (src->retrieve_capabilities.unicast_addr_count && src->retrieve_capabilities.unicast_addr) { + dst->retrieve_capabilities.unicast_addr = bt_mesh_calloc(src->retrieve_capabilities.unicast_addr_count * 2); + if (dst->retrieve_capabilities.unicast_addr) { + memcpy(dst->retrieve_capabilities.unicast_addr, src->retrieve_capabilities.unicast_addr, + src->retrieve_capabilities.unicast_addr_count * 2); + dst->retrieve_capabilities.unicast_addr_count = src->retrieve_capabilities.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB: + if (src->transfer_blob.unicast_addr_count && src->transfer_blob.unicast_addr) { + dst->transfer_blob.unicast_addr = bt_mesh_calloc(src->transfer_blob.unicast_addr_count * 2); + if (dst->transfer_blob.unicast_addr) { + memcpy(dst->transfer_blob.unicast_addr, src->transfer_blob.unicast_addr, + src->transfer_blob.unicast_addr_count * 2); + dst->transfer_blob.unicast_addr_count = src->transfer_blob.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS: + if (src->determine_transfer_status.unicast_addr_count && src->determine_transfer_status.unicast_addr) { + dst->determine_transfer_status.unicast_addr = bt_mesh_calloc(src->determine_transfer_status.unicast_addr_count * 2); + if (dst->determine_transfer_status.unicast_addr) { + memcpy(dst->determine_transfer_status.unicast_addr, src->determine_transfer_status.unicast_addr, + src->determine_transfer_status.unicast_addr_count * 2); + dst->determine_transfer_status.unicast_addr_count = src->determine_transfer_status.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER: + if (src->cancel_transfer.unicast_addr_count && src->cancel_transfer.unicast_addr) { + dst->cancel_transfer.unicast_addr = bt_mesh_calloc(src->cancel_transfer.unicast_addr_count * 2); + if (dst->cancel_transfer.unicast_addr) { + memcpy(dst->cancel_transfer.unicast_addr, src->cancel_transfer.unicast_addr, + src->cancel_transfer.unicast_addr_count * 2); + dst->cancel_transfer.unicast_addr_count = src->cancel_transfer.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_mbt_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_mbt_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_mbt_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES: + bt_mesh_free(arg->retrieve_capabilities.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB: + bt_mesh_free(arg->transfer_blob.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS: + bt_mesh_free(arg->determine_transfer_status.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER: + bt_mesh_free(arg->cancel_transfer.unicast_addr); + break; + default: + break; + } +} + +static void btc_ble_mesh_blob_trans_client_copy_req_data(btc_msg_t *msg, void *p_dst, void *p_src) +{ + esp_ble_mesh_mbt_client_cb_param_t *dst = (esp_ble_mesh_mbt_client_cb_param_t *)p_dst; + esp_ble_mesh_mbt_client_cb_param_t *src = (esp_ble_mesh_mbt_client_cb_param_t *)p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES: + if (src->value.retrieve_capabilities_status.input.unicast_addr_count && + src->value.retrieve_capabilities_status.input.unicast_addr) { + dst->value.retrieve_capabilities_status.input.unicast_addr = bt_mesh_calloc(src->value.retrieve_capabilities_status.input.unicast_addr_count * 2); + if (dst->value.retrieve_capabilities_status.input.unicast_addr) { + memcpy(dst->value.retrieve_capabilities_status.input.unicast_addr, src->value.retrieve_capabilities_status.input.unicast_addr, + src->value.retrieve_capabilities_status.input.unicast_addr_count * 2); + dst->value.retrieve_capabilities_status.input.unicast_addr_count = src->value.retrieve_capabilities_status.input.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB: + if (src->value.transfer_blob_status.input.unicast_addr_count && + src->value.transfer_blob_status.input.unicast_addr) { + dst->value.transfer_blob_status.input.unicast_addr = bt_mesh_calloc(src->value.transfer_blob_status.input.unicast_addr_count * 2); + if (dst->value.transfer_blob_status.input.unicast_addr) { + memcpy(dst->value.transfer_blob_status.input.unicast_addr, src->value.transfer_blob_status.input.unicast_addr, + src->value.transfer_blob_status.input.unicast_addr_count * 2); + dst->value.transfer_blob_status.input.unicast_addr_count = src->value.transfer_blob_status.input.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS: + if (src->value.determine_transfer_status_status.input.unicast_addr_count && + src->value.determine_transfer_status_status.input.unicast_addr) { + dst->value.determine_transfer_status_status.input.unicast_addr = bt_mesh_calloc(src->value.determine_transfer_status_status.input.unicast_addr_count * 2); + if (dst->value.determine_transfer_status_status.input.unicast_addr) { + memcpy(dst->value.determine_transfer_status_status.input.unicast_addr, src->value.determine_transfer_status_status.input.unicast_addr, + src->value.determine_transfer_status_status.input.unicast_addr_count * 2); + dst->value.determine_transfer_status_status.input.unicast_addr_count = src->value.determine_transfer_status_status.input.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER: + if (src->value.cancel_transfer_status.input.unicast_addr_count && + src->value.cancel_transfer_status.input.unicast_addr) { + dst->value.cancel_transfer_status.input.unicast_addr = bt_mesh_calloc(src->value.cancel_transfer_status.input.unicast_addr_count * 2); + if (dst->value.cancel_transfer_status.input.unicast_addr) { + memcpy(dst->value.cancel_transfer_status.input.unicast_addr, src->value.cancel_transfer_status.input.unicast_addr, + src->value.cancel_transfer_status.input.unicast_addr_count * 2); + dst->value.cancel_transfer_status.input.unicast_addr_count = src->value.cancel_transfer_status.input.unicast_addr_count; + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +static void btc_ble_mesh_blob_trans_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_mbt_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_mbt_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES: + bt_mesh_free(arg->value.retrieve_capabilities_status.input.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB: + bt_mesh_free(arg->value.transfer_blob_status.input.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS: + bt_mesh_free(arg->value.determine_transfer_status_status.input.unicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER: + bt_mesh_free(arg->value.cancel_transfer_status.input.unicast_addr); + break; + default: + break; + } +} + +static void btc_ble_mesh_blob_trans_client_callback(esp_ble_mesh_mbt_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_MBT_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MBT_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_mbt_client_cb_param_t), + btc_ble_mesh_blob_trans_client_copy_req_data, + btc_ble_mesh_blob_trans_client_free_req_data); +} + +void bt_mesh_mbt_client_cb_evt_to_btc(uint8_t event, uint8_t result, + struct bt_mesh_model *model) +{ + esp_ble_mesh_mbt_client_cb_param_t cb_params = {0}; + uint8_t cb_event = 0; + + if (model == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_MBT_CLIENT_RETRIEVE_CAPABILITIES_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_RETRIEVE_CAPABILITIES_COMP_EVT; + cb_params.value.retrieve_capabilities_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.retrieve_capabilities_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_TRANSFER_BLOB_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_TRANSFER_BLOB_COMP_EVT; + cb_params.value.transfer_blob_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.transfer_blob_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_BLOCK_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_SEND_BLOCK_COMP_EVT; + cb_params.value.send_block_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.send_block_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_DATA_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_SEND_DATA_COMP_EVT; + cb_params.value.send_data_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.send_data_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_BLOCK_STATUS_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_DETERMINE_BLOCK_STATUS_COMP_EVT; + cb_params.value.determine_block_status_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.determine_block_status_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_COMP_EVT; + cb_params.value.determine_transfer_status_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.determine_transfer_status_comp.result = result; + break; + case BTC_BLE_MESH_EVT_MBT_CLIENT_CANCEL_TRANSFER_COMP: + cb_event = ESP_BLE_MESH_MBT_CLIENT_CANCEL_TRANSFER_COMP_EVT; + cb_params.value.cancel_transfer_comp.model = (esp_ble_mesh_model_t *)model; + cb_params.value.cancel_transfer_comp.result = result; + break; + default: + BT_ERR("Unknown Blob Transfer Client event type %d", event); + return; + } + + btc_ble_mesh_blob_trans_client_callback(&cb_params, cb_event); +} + +void btc_ble_mesh_mbt_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + /* TBD */ +} + +void btc_ble_mesh_mbt_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_mbt_client_cb_param_t cb = {0}; + btc_ble_mesh_mbt_client_args_t *arg = NULL; + uint8_t event = 0; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_mbt_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES: + event = ESP_BLE_MESH_MBT_CLIENT_RETRIEVE_CAPABILITIES_STATUS_EVT; + memcpy(&cb.value.retrieve_capabilities_status.input, + &arg->retrieve_capabilities, sizeof(arg->retrieve_capabilities)); + cb.value.retrieve_capabilities_status.error_code = + bt_mesh_retrieve_capabilities(&arg->retrieve_capabilities); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB: + event = ESP_BLE_MESH_MBT_CLIENT_TRANSFER_BLOB_STATUS_EVT; + memcpy(&cb.value.transfer_blob_status.input, &arg->transfer_blob, sizeof(arg->transfer_blob)); + cb.value.transfer_blob_status.error_code = bt_mesh_transfer_blob(&arg->transfer_blob); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_BLOCK: + event = ESP_BLE_MESH_MBT_CLIENT_SEND_BLOCK_STATUS_EVT; + memcpy(&cb.value.send_block_status.input, &arg->send_block, sizeof(arg->send_block)); + cb.value.send_block_status.error_code = bt_mesh_send_block(&arg->send_block); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_DATA: + event = ESP_BLE_MESH_MBT_CLIENT_SEND_DATA_STATUS_EVT; + memcpy(&cb.value.send_data_status.input, &arg->send_data, sizeof(arg->send_data)); + cb.value.send_data_status.error_code = bt_mesh_send_data(&arg->send_data); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_BLOCK_STATUS: + event = ESP_BLE_MESH_MBT_CLIENT_DETERMINE_BLOCK_STATUS_STATUS_EVT; + memcpy(&cb.value.determine_block_status_status.input, + &arg->determine_block_status, sizeof(arg->determine_block_status)); + cb.value.determine_block_status_status.error_code = + bt_mesh_determine_block_status(&arg->determine_block_status); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS: + event = ESP_BLE_MESH_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_STATUS_EVT; + memcpy(&cb.value.determine_transfer_status_status.input, + &arg->determine_transfer_status, sizeof(arg->determine_transfer_status)); + cb.value.determine_transfer_status_status.error_code = + bt_mesh_determine_transfer_status(&arg->determine_transfer_status); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER: + event = ESP_BLE_MESH_MBT_CLIENT_CANCEL_TRANSFER_STATUS_EVT; + memcpy(&cb.value.cancel_transfer_status.input, &arg->cancel_transfer, sizeof(arg->cancel_transfer)); + cb.value.cancel_transfer_status.error_code = bt_mesh_cancel_transfer(&arg->cancel_transfer); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_SET_TRANSFER_TTL: + event = ESP_BLE_MESH_MBT_CLIENT_SET_TRANSFER_TTL_COMP_EVT; + cb.value.set_transfer_ttl.model = arg->set_transfer_ttl.model; + cb.value.set_transfer_ttl.transfer_ttl = arg->set_transfer_ttl.transfer_ttl; + cb.value.set_transfer_ttl.error_code = + bt_mesh_set_transfer_ttl_state((struct bt_mesh_model *)arg->set_transfer_ttl.model, + arg->set_transfer_ttl.transfer_ttl); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_TRANSFER_TTL: + event = ESP_BLE_MESH_MBT_CLIENT_CLEAR_TRANSFER_TTL_COMP_EVT; + cb.value.clear_transfer_ttl.model = arg->clear_transfer_ttl.model; + cb.value.clear_transfer_ttl.error_code = + bt_mesh_clear_transfer_ttl_state((struct bt_mesh_model *)arg->clear_transfer_ttl.model); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_SET_APP_IDX: + event = ESP_BLE_MESH_MBT_CLIENT_SET_APP_IDX_COMP_EVT; + cb.value.set_app_idx.model = arg->set_app_idx.model; + cb.value.set_app_idx.app_idx = arg->set_app_idx.app_idx; + cb.value.set_app_idx.error_code = + bt_mesh_set_app_idx_state((struct bt_mesh_model *)arg->set_app_idx.model, + arg->set_app_idx.app_idx); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_APP_IDX: + event = ESP_BLE_MESH_MBT_CLIENT_CLEAR_APP_IDX_COMP_EVT; + cb.value.clear_app_idx.model = arg->clear_app_idx.model; + cb.value.clear_app_idx.error_code = + bt_mesh_clear_app_idx_state((struct bt_mesh_model *)arg->clear_app_idx.model); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_SET_MULTICAST_ADDR: + event = ESP_BLE_MESH_MBT_CLIENT_SET_MULTICAST_ADDR_COMP_EVT; + cb.value.set_multicast_addr.model = arg->set_multicast_addr.model; + cb.value.set_multicast_addr.multicast_addr = arg->set_multicast_addr.multicast_addr; + cb.value.set_multicast_addr.error_code = + bt_mesh_set_multicast_addr_state((struct bt_mesh_model *)arg->set_multicast_addr.model, + arg->set_multicast_addr.multicast_addr); + break; + case BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_MULTICAST_ADDR: + event = ESP_BLE_MESH_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP_EVT; + cb.value.clear_multicast_addr.model = arg->clear_multicast_addr.model; + cb.value.clear_multicast_addr.error_code = + bt_mesh_clear_multicast_addr_state((struct bt_mesh_model *)arg->clear_multicast_addr.model); + break; + default: + BT_ERR("Unknown BLOB Transfer Client act %d", msg->act); + return; + } + + btc_ble_mesh_blob_trans_client_callback(&cb, event); + + btc_ble_mesh_mbt_client_arg_deep_free(msg); +} + +void btc_ble_mesh_mbt_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_mbt_client_cb_param_t *param = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_mbt_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_MBT_CLIENT_EVT_MAX) { + btc_ble_mesh_blob_trans_client_cb_to_app(msg->act, param); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_blob_trans_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_MBT_CLI */ + +#if CONFIG_BLE_MESH_MBT_SRV + +static inline void btc_ble_mesh_blob_trans_server_cb_to_app(esp_ble_mesh_mbt_server_cb_event_t event, + esp_ble_mesh_mbt_server_cb_param_t *param) +{ + esp_ble_mesh_mbt_server_cb_t btc_ble_mesh_cb = + (esp_ble_mesh_mbt_server_cb_t)btc_profile_cb_get(BTC_PID_MBT_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_blob_trans_server_callback(esp_ble_mesh_mbt_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_MBT_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_MBT_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_mbt_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_mbt_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + esp_ble_mesh_mbt_server_cb_param_t cb_params = {0}; + uint8_t cb_event = 0; + + if (model == NULL || (ctx == NULL && + event != BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_TIMEOUT)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_GET: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_GET_EVT; + memcpy(&cb_params.value.blob_transfer_get.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_START: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_START_EVT; + memcpy(&cb_params.value.blob_transfer_start.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_CANCEL: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_TRANSFER_CANCEL_EVT; + memcpy(&cb_params.value.blob_transfer_cancel.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_GET: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_BLOCK_GET_EVT; + memcpy(&cb_params.value.blob_block_get.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_START: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_BLOCK_START_EVT; + memcpy(&cb_params.value.blob_block_start.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_CHUNK_TRANSFER: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_CHUNK_TRANSFER_EVT; + memcpy(&cb_params.value.blob_chunk_transfer.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_INFORMATION_GET: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_INFORMATION_GET_EVT; + memcpy(&cb_params.value.blob_information_get.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOCK_RECEIVE_COMP: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOCK_RECEIVE_COMP_EVT; + memcpy(&cb_params.value.block_receive_comp.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_COMP: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_COMP_EVT; + memcpy(&cb_params.value.blob_receive_comp.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + break; + case BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_TIMEOUT: + cb_event = ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_TIMEOUT_EVT; + break; + default: + BT_ERR("Unknown Blob Transfer server event type %d", event); + return; + } + + btc_ble_mesh_blob_trans_server_callback(&cb_params, cb_event); +} + +void btc_ble_mesh_mbt_server_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_mbt_server_cb_param_t cb = {0}; + btc_ble_mesh_mbt_server_args_t *arg = NULL; + uint8_t event = 0; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_mbt_server_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_MBT_SERVER_INITIALIZE_BLOB_RECEIVE: + event = ESP_BLE_MESH_MBT_SERVER_INITIALIZE_BLOB_RECEIVE_COMP_EVT; + memcpy(&cb.value.initialize_blob_receive_comp.input, + &arg->initialize_blob_receive, sizeof(arg->initialize_blob_receive)); + cb.value.initialize_blob_receive_comp.error_code = + bt_mesh_initialize_blob_receive(&arg->initialize_blob_receive); + break; + case BTC_BLE_MESH_ACT_MBT_SERVER_CANCEL_BLOB_RECEIVE: + event = ESP_BLE_MESH_MBT_SERVER_CANCEL_BLOB_RECEIVE_COMP_EVT; + memcpy(&cb.value.cancel_blob_receive_comp.input, + &arg->cancel_blob_receive, sizeof(arg->cancel_blob_receive)); + cb.value.cancel_blob_receive_comp.error_code = + bt_mesh_cancel_blob_receive(&arg->cancel_blob_receive); + break; + case BTC_BLE_MESH_ACT_MBT_SERVER_SET_BLOB_CAPABILITIES: + event = ESP_BLE_MESH_MBT_SERVER_SET_BLOB_CAPABILITIES_COMP_EVT; + memcpy(&cb.value.set_blob_capabilities_comp.input, + &arg->set_blob_capabilities, sizeof(arg->set_blob_capabilities)); + cb.value.set_blob_capabilities_comp.error_code = + bt_mesh_set_blob_capabilities((struct bt_mesh_model *)arg->set_blob_capabilities.model, + &arg->set_blob_capabilities.caps); + break; + default: + BT_ERR("Unknown BLOB Transfer Server act %d", msg->act); + return; + } + + btc_ble_mesh_blob_trans_server_callback(&cb, event); +} + +void btc_ble_mesh_mbt_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_mbt_server_cb_param_t *param = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + param = (esp_ble_mesh_mbt_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_MBT_SERVER_EVT_MAX) { + btc_ble_mesh_blob_trans_server_cb_to_app(msg->act, param); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_MBT_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c new file mode 100644 index 0000000000..52d89880a6 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c @@ -0,0 +1,380 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_odp_model.h" +#include "esp_ble_mesh_odp_model_api.h" + +#if CONFIG_BLE_MESH_ODP_CLI + +extern int bt_mesh_odp_get(void *param); +extern int bt_mesh_odp_set(void *param, uint8_t on_demand_private_gatt_proxy); + +/* On-Demand Private Proxy Configuration Client model related functions */ + +static inline void btc_ble_mesh_odp_client_cb_to_app(esp_ble_mesh_odp_client_cb_event_t event, + esp_ble_mesh_odp_client_cb_param_t *param) +{ + esp_ble_mesh_odp_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_ODP_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_odp_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_odp_client_args_t *dst = p_dest; + btc_ble_mesh_odp_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_ODP_CLIENT_SEND: + dst->odp_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->odp_send.params) { + memcpy(dst->odp_send.params, src->odp_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->odp_send.msg) { + dst->odp_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_odp_client_msg_t)); + if (dst->odp_send.msg) { + memcpy(dst->odp_send.msg, src->odp_send.msg, + sizeof(esp_ble_mesh_odp_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_odp_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_odp_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_odp_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_ODP_CLIENT_SEND: + if (arg->odp_send.params) { + bt_mesh_free(arg->odp_send.params); + } + if (arg->odp_send.msg) { + bt_mesh_free(arg->odp_send.msg); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_odp_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_odp_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_odp_client_cb_param_t *p_src_data = p_src; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } +} + +static void btc_ble_mesh_odp_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_odp_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_odp_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_ODP_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_ODP_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_ODP_CLIENT_RECV_PUB_EVT: + case ESP_BLE_MESH_ODP_CLIENT_SEND_TIMEOUT_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_odp_client_cb(esp_ble_mesh_odp_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_ODP_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_ODP_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_odp_client_cb_param_t), + btc_ble_mesh_odp_client_copy_req_data, + btc_ble_mesh_odp_client_free_req_data); +} + +void bt_mesh_odp_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_odp_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_ODP_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_ODP_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_ODP_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_ODP_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown On-Demand Private Proxy client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_odp_client_cb(&cb_params, act); +} + +void btc_ble_mesh_odp_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_odp_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_odp_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_odp_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (params->opcode == ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_SET && msg == NULL) { + BT_ERR("Invalid On-Demand Private Proxy message, opcode 0x%04x", params->opcode); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_GET: + return bt_mesh_odp_get(¶m); + case ESP_BLE_MESH_MODEL_OP_OD_PRIV_PROXY_SET: + return bt_mesh_odp_set(¶m, msg->od_priv_proxy_set.gatt_proxy); + default: + BT_ERR("Invalid On-Demand Private Proxy opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_odp_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_odp_client_cb_param_t cb = {0}; + btc_ble_mesh_odp_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_odp_client_args_t *)msg->arg; + + if (msg->act == BTC_BLE_MESH_ACT_ODP_CLIENT_SEND) { + cb.params = arg->odp_send.params; + cb.send.err_code = btc_ble_mesh_odp_client_send(arg->odp_send.params, + arg->odp_send.msg); + btc_ble_mesh_odp_client_cb(&cb, + ESP_BLE_MESH_ODP_CLIENT_SEND_COMP_EVT); + } + + btc_ble_mesh_odp_client_arg_deep_free(msg); +} + +void btc_ble_mesh_odp_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_odp_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_odp_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_ODP_CLIENT_EVT_MAX) { + btc_ble_mesh_odp_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_odp_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_ODP_CLI */ + +#if CONFIG_BLE_MESH_ODP_SRV + +/* On-Demand Private Proxy Config Server model related functions */ + +static inline void btc_ble_mesh_odp_server_cb_to_app(esp_ble_mesh_odp_server_cb_event_t event, + esp_ble_mesh_odp_server_cb_param_t *param) +{ + esp_ble_mesh_odp_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_ODP_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_odp_server_cb(esp_ble_mesh_odp_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_ODP_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_ODP_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_odp_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_odp_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_odp_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_ODP_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_ODP_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown On-Demand Private Proxy server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_odp_server_cb(&cb_params, act); +} + +void btc_ble_mesh_odp_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_odp_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_odp_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_ODP_SERVER_EVT_MAX) { + btc_ble_mesh_odp_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_ODP_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_prb_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_prb_model.c new file mode 100644 index 0000000000..837fc79b57 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_prb_model.c @@ -0,0 +1,404 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_prb_model.h" +#include "esp_ble_mesh_prb_model_api.h" + +#if CONFIG_BLE_MESH_PRB_CLI + +extern int bt_mesh_private_beacon_get(void *param); +extern int bt_mesh_private_beacon_set(void *param, void *set); +extern int bt_mesh_private_gatt_proxy_get(void *param); +extern int bt_mesh_private_gatt_proxy_set(void *param, uint8_t private_gatt_proxy); +extern int bt_mesh_private_node_identity_get(void *param, uint16_t net_idx); +extern int bt_mesh_private_node_identity_set(void *param, uint16_t net_idx, + uint8_t private_node_id); + +/* Private Beacon Client Model related functions */ + +static inline void btc_ble_mesh_prb_client_cb_to_app(esp_ble_mesh_prb_client_cb_event_t event, + esp_ble_mesh_prb_client_cb_param_t *param) +{ + esp_ble_mesh_prb_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_PRB_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_prb_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_prb_client_args_t *dst = p_dest; + btc_ble_mesh_prb_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_PRB_CLIENT_SEND: + dst->prb_send.params = bt_mesh_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->prb_send.params) { + memcpy(dst->prb_send.params, src->prb_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->prb_send.msg) { + dst->prb_send.msg = bt_mesh_malloc(sizeof(esp_ble_mesh_prb_client_msg_t)); + if (dst->prb_send.msg) { + memcpy(dst->prb_send.msg, src->prb_send.msg, + sizeof(esp_ble_mesh_prb_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_prb_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_prb_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_prb_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_PRB_CLIENT_SEND: + if (arg->prb_send.params) { + bt_mesh_free(arg->prb_send.params); + } + if (arg->prb_send.msg) { + bt_mesh_free(arg->prb_send.msg); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_prb_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_prb_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_prb_client_cb_param_t *p_src_data = p_src; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_malloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } +} + +static void btc_ble_mesh_prb_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_prb_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_prb_client_cb_param_t *)(msg->arg); + + switch (msg->act) { + case ESP_BLE_MESH_PRB_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_PRB_CLIENT_SEND_TIMEOUT_EVT: + case ESP_BLE_MESH_PRB_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_PRB_CLIENT_RECV_PUB_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_prb_client_cb(esp_ble_mesh_prb_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t btc_msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_PRB_CLIENT)) { + return; + } + + btc_msg.sig = BTC_SIG_API_CB; + btc_msg.pid = BTC_PID_PRB_CLIENT; + btc_msg.act = act; + + btc_transfer_context(&btc_msg, cb_params, sizeof(esp_ble_mesh_prb_client_cb_param_t), + btc_ble_mesh_prb_client_copy_req_data, + btc_ble_mesh_prb_client_free_req_data); +} + +void bt_mesh_prb_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, uint16_t len) +{ + esp_ble_mesh_prb_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0U; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case BTC_BLE_MESH_EVT_PRB_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_PRB_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_PRB_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_PRB_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown Private Beacon client event type %d", evt_type); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_prb_client_cb(&cb_params, act); +} + +void btc_ble_mesh_prb_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_prb_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_prb_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_prb_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_SET: + case ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_SET: + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_GET: + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_SET: + if (msg == NULL) { + BT_ERR("Invalid Mesh Private Beacon message, opcode 0x%04x", params->opcode); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_GET: + return bt_mesh_private_beacon_get(¶m); + case ESP_BLE_MESH_MODEL_OP_PRIV_BEACON_SET: + return bt_mesh_private_beacon_set(¶m, &msg->priv_beacon_set); + case ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_GET: + return bt_mesh_private_gatt_proxy_get(¶m); + case ESP_BLE_MESH_MODEL_OP_PRIV_GATT_PROXY_SET: + return bt_mesh_private_gatt_proxy_set(¶m, msg->priv_gatt_proxy_set.private_gatt_proxy); + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_GET: + return bt_mesh_private_node_identity_get(¶m, msg->priv_node_id_get.net_idx); + case ESP_BLE_MESH_MODEL_OP_PRIV_NODE_IDENTITY_SET: + return bt_mesh_private_node_identity_set(¶m, msg->priv_node_id_set.net_idx , msg->priv_node_id_set.private_node_id); + default: + BT_ERR("Invalid Private Beacon opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_prb_client_call_handler(btc_msg_t *msg) +{ + btc_ble_mesh_prb_client_args_t *arg = NULL; + esp_ble_mesh_prb_client_cb_param_t cb = {0}; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_prb_client_args_t *)(msg->arg); + + switch (msg->act) { + case BTC_BLE_MESH_ACT_PRB_CLIENT_SEND: + cb.params = arg->prb_send.params; + cb.send.err_code = btc_ble_mesh_prb_client_send(arg->prb_send.params, + arg->prb_send.msg); + btc_ble_mesh_prb_client_cb(&cb, + ESP_BLE_MESH_PRB_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_prb_client_arg_deep_free(msg); +} + +void btc_ble_mesh_prb_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_prb_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_prb_client_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_PRB_CLIENT_EVT_MAX) { + btc_ble_mesh_prb_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_prb_client_free_req_data(msg); +} +#endif /* CONFIG_BLE_MESH_PRB_CLI */ + +#if CONFIG_BLE_MESH_PRB_SRV +/* Private Beacon Server Model related functions */ + +static inline void btc_ble_mesh_prb_server_cb_to_app(esp_ble_mesh_prb_server_cb_event_t event, + esp_ble_mesh_prb_server_cb_param_t *param) +{ + esp_ble_mesh_prb_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_PRB_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_prb_server_cb( + esp_ble_mesh_prb_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_PRB_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PRB_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_prb_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_prb_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_prb_server_cb_param_t cb_params = {0}; + uint8_t act = 0U; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (evt_type) { + case BTC_BLE_MESH_EVT_PRB_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_PRB_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown Private Beacon server event type %d", evt_type); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_prb_server_cb(&cb_params, act); +} + +void btc_ble_mesh_prb_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_prb_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_prb_server_cb_param_t *)(msg->arg); + + if (msg->act < ESP_BLE_MESH_PRB_SERVER_EVT_MAX) { + btc_ble_mesh_prb_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} +#endif /* CONFIG_BLE_MESH_PRB_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c new file mode 100644 index 0000000000..5e4437f4b1 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c @@ -0,0 +1,543 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_rpr_model.h" +#include "esp_ble_mesh_rpr_model_api.h" + +#if CONFIG_BLE_MESH_RPR_CLI + +extern int bt_mesh_rpr_scan_caps_get(void *param); +extern int bt_mesh_rpr_scan_get(void *param); +extern int bt_mesh_rpr_scan_start(void *param, void *start); +extern int bt_mesh_rpr_scan_stop(void *param); +extern int bt_mesh_rpr_ext_scan_start(void *param, void *start); +extern int bt_mesh_rpr_link_get(void *param); +extern int bt_mesh_rpr_link_open(void *param, void *open); +extern int bt_mesh_rpr_link_close(void *param, uint8_t reason); +extern int bt_mesh_rpr_start_prov(void *model, uint16_t rp_srv_addr); + +/* Remote Provisioning Client model related functions */ + +static inline void btc_ble_mesh_rpr_client_cb_to_app(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param) +{ + esp_ble_mesh_rpr_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_RPR_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_rpr_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_rpr_client_args_t *dst = p_dest; + btc_ble_mesh_rpr_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_RPR_CLIENT_SEND: + dst->rpr_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->rpr_send.msg = src->rpr_send.msg ? bt_mesh_calloc(sizeof(esp_ble_mesh_rpr_client_msg_t)) : NULL; + if (dst->rpr_send.params) { + memcpy(dst->rpr_send.params, src->rpr_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->rpr_send.msg) { + memcpy(dst->rpr_send.msg, src->rpr_send.msg, + sizeof(esp_ble_mesh_rpr_client_msg_t)); + } + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + case BTC_BLE_MESH_ACT_RPR_CLIENT_ACT: + dst->rpr_act.param = bt_mesh_calloc(sizeof(esp_ble_mesh_rpr_client_act_param_t)); + if (dst->rpr_act.param) { + memcpy(dst->rpr_act.param, src->rpr_act.param, + sizeof(esp_ble_mesh_rpr_client_act_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_rpr_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_rpr_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_rpr_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_RPR_CLIENT_SEND: + if (arg->rpr_send.params) { + bt_mesh_free(arg->rpr_send.params); + } + break; + case BTC_BLE_MESH_ACT_RPR_CLIENT_ACT: + if (arg->rpr_act.param) { + bt_mesh_free(arg->rpr_act.param); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_rpr_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_rpr_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_rpr_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_RPR_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_RPR_CLIENT_SEND_TIMEOUT_EVT: + if (p_src_data->send.params) { + p_dest_data->send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->send.params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->send.params, p_src_data->send.params, sizeof(esp_ble_mesh_client_common_param_t)); + } + break; + case ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT: + if (p_src_data->recv.params) { + p_dest_data->recv.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->recv.params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->recv.params, p_src_data->recv.params, sizeof(esp_ble_mesh_client_common_param_t)); + + /* Remote Provisioning Extended Scan Start is an unacknowledged message, + * so the corresponding report could only be received through the recv + * publish event. + */ + if (msg->act == ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT && + p_src_data->recv.params->opcode == ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_REPORT) { + if (p_src_data->recv.val.ext_scan_report.adv_structures) { + length = p_src_data->recv.val.ext_scan_report.adv_structures->len; + p_dest_data->recv.val.ext_scan_report.adv_structures = bt_mesh_alloc_buf(length); + if (!p_dest_data->recv.val.ext_scan_report.adv_structures) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + net_buf_simple_add_mem(p_dest_data->recv.val.ext_scan_report.adv_structures, + p_src_data->recv.val.ext_scan_report.adv_structures->data, + p_src_data->recv.val.ext_scan_report.adv_structures->len); + } + } + } + break; + case ESP_BLE_MESH_RPR_CLIENT_ACT_COMP_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_rpr_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_rpr_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_rpr_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_RPR_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_RPR_CLIENT_SEND_TIMEOUT_EVT: + if (arg->send.params) { + bt_mesh_free(arg->send.params); + } + break; + case ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT: + if (arg->recv.params && + msg->act == ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT && + arg->recv.params->opcode == ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_REPORT) { + bt_mesh_free_buf(arg->recv.val.ext_scan_report.adv_structures); + } + if (arg->recv.params) { + bt_mesh_free(arg->recv.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_rpr_client_cb(esp_ble_mesh_rpr_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_RPR_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_RPR_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_rpr_client_cb_param_t), + btc_ble_mesh_rpr_client_copy_req_data, + btc_ble_mesh_rpr_client_free_req_data); +} + +void bt_mesh_rpr_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len) +{ + esp_ble_mesh_rpr_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (model == NULL || ctx == NULL || + ((event == BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_RSP || + event == BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_PUB) && + (len > sizeof(cb_params.recv.val)))) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + switch (event) { + case BTC_BLE_MESH_EVT_RPR_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_RPR_CLIENT_SEND_TIMEOUT_EVT; + cb_params.send.params = ¶ms; + break; + case BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT; + cb_params.recv.params = ¶ms; + if (val && len) { + memcpy(&cb_params.recv.val, val, len); + } + break; + case BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT; + cb_params.recv.params = ¶ms; + if (val && len) { + memcpy(&cb_params.recv.val, val, len); + } + break; + default: + BT_ERR("Unknown Remote Provisioning client event type %d", event); + return; + } + + btc_ble_mesh_rpr_client_cb(&cb_params, act); +} + +void btc_ble_mesh_rpr_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_rpr_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +void btc_ble_mesh_rpr_client_link_close_cb(struct bt_mesh_model *model, + uint16_t rpr_srv_addr, uint8_t reason) +{ + esp_ble_mesh_rpr_client_cb_param_t cb_params = {0}; + + cb_params.link_close.model = (esp_ble_mesh_model_t *)model; + cb_params.link_close.rpr_srv_addr = rpr_srv_addr; + cb_params.link_close.reason = reason; + + btc_ble_mesh_rpr_client_cb(&cb_params, ESP_BLE_MESH_RPR_CLIENT_LINK_CLOSE_EVT); +} + +void btc_ble_mesh_rpr_client_prov_comp_cb(struct bt_mesh_model *model, uint16_t rpr_srv_addr, + uint8_t nppi, uint16_t index, uint8_t uuid[16], + uint16_t unicast_addr, uint8_t element_num, + uint16_t net_idx) +{ + esp_ble_mesh_rpr_client_cb_param_t cb_params = {0}; + + cb_params.prov.model = (esp_ble_mesh_model_t *)model; + cb_params.prov.rpr_srv_addr = rpr_srv_addr; + cb_params.prov.nppi = nppi; + cb_params.prov.index = index; + cb_params.prov.unicast_addr = unicast_addr; + cb_params.prov.element_num = element_num; + cb_params.prov.net_idx = net_idx; + memcpy(cb_params.prov.uuid, uuid, 16); + + btc_ble_mesh_rpr_client_cb(&cb_params, ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT); +} + +static int btc_ble_mesh_rpr_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_rpr_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + switch (params->opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START: + case ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_START: + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE: + if (msg == NULL) { + BT_ERR("Invalid Remote Provisioning message opcode 0x%04x", params->opcode); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_GET: + return bt_mesh_rpr_scan_caps_get(¶m); + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET: + return bt_mesh_rpr_scan_get(¶m); + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START: + return bt_mesh_rpr_scan_start(¶m, &msg->scan_start); + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STOP: + return bt_mesh_rpr_scan_stop(¶m); + case ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_START: + return bt_mesh_rpr_ext_scan_start(¶m, &msg->ext_scan_start); + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET: + return bt_mesh_rpr_link_get(¶m); + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: + return bt_mesh_rpr_link_open(¶m, &msg->link_open); + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE: + return bt_mesh_rpr_link_close(¶m, msg->link_close.reason); + case ESP_BLE_MESH_MODEL_OP_RPR_PDU_SEND: + BT_WARN("Remote Provisioning PDU Send will be sent internally"); + return 0; + default: + BT_ERR("Invalid Remote Provisioning msg opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +static int btc_ble_mesh_rpr_client_act(esp_ble_mesh_rpr_client_act_type_t type, + esp_ble_mesh_rpr_client_act_param_t *param, + esp_ble_mesh_rpr_client_cb_param_t *cb) +{ + if (param == NULL || cb == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + switch (type) { + case ESP_BLE_MESH_RPR_CLIENT_ACT_START_RPR: + cb->act.sub_evt = ESP_BLE_MESH_START_RPR_COMP_SUB_EVT; + cb->act.start_rpr_comp.model = param->start_rpr.model; + cb->act.start_rpr_comp.rpr_srv_addr = param->start_rpr.rpr_srv_addr; + cb->act.start_rpr_comp.err_code = + bt_mesh_rpr_start_prov((struct bt_mesh_model *)param->start_rpr.model, + param->start_rpr.rpr_srv_addr); + break; + default: + BT_ERR("Invalid Remote Provisioning action 0x%02x", type); + return -EINVAL; + } + + return 0; +} + +void btc_ble_mesh_rpr_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_rpr_client_cb_param_t cb = {0}; + btc_ble_mesh_rpr_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_rpr_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_RPR_CLIENT_SEND: + cb.send.params = arg->rpr_send.params; + cb.send.err_code = btc_ble_mesh_rpr_client_send(arg->rpr_send.params, + arg->rpr_send.msg); + btc_ble_mesh_rpr_client_cb(&cb, ESP_BLE_MESH_RPR_CLIENT_SEND_COMP_EVT); + break; + case BTC_BLE_MESH_ACT_RPR_CLIENT_ACT: + btc_ble_mesh_rpr_client_act(arg->rpr_act.type, + arg->rpr_act.param, &cb); + btc_ble_mesh_rpr_client_cb(&cb, ESP_BLE_MESH_RPR_CLIENT_ACT_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_rpr_client_arg_deep_free(msg); +} + +void btc_ble_mesh_rpr_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_rpr_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_rpr_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_RPR_CLIENT_EVT_MAX) { + btc_ble_mesh_rpr_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_rpr_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_RPR_CLI */ + +#if CONFIG_BLE_MESH_RPR_SRV + +/* Remote Provisioning Server model related functions */ + +static inline void btc_ble_mesh_rpr_server_cb_to_app(esp_ble_mesh_rpr_server_cb_event_t event, + esp_ble_mesh_rpr_server_cb_param_t *param) +{ + esp_ble_mesh_rpr_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_RPR_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_rpr_server_cb(esp_ble_mesh_rpr_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_RPR_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_RPR_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_rpr_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_rpr_server_cb_evt_to_btc(uint8_t event, const void *val, size_t len) +{ + esp_ble_mesh_rpr_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (len > sizeof(cb_params)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_START: + act = ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_STOP: + act = ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_START: + act = ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_STOP: + act = ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_LINK_OPEN: + act = ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_LINK_CLOSE: + act = ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT; + break; + case BTC_BLE_MESH_EVT_RPR_SERVER_PROV_COMP: + act = ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT; + break; + default: + BT_ERR("Unknown Remote Provisioning server event type %d", event); + return; + } + + if (val && len) { + memcpy(&cb_params, val, len); + } + + btc_ble_mesh_rpr_server_cb(&cb_params, act); +} + +void btc_ble_mesh_rpr_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_rpr_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_rpr_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_RPR_SERVER_EVT_MAX) { + btc_ble_mesh_rpr_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_RPR_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c new file mode 100644 index 0000000000..536d219cc0 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c @@ -0,0 +1,389 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_sar_model.h" +#include "esp_ble_mesh_sar_model_api.h" + +#if CONFIG_BLE_MESH_SAR_CLI + +extern int bt_mesh_sar_transmitter_get(void *param); +extern int bt_mesh_sar_transmitter_set(void *param, void *set); +extern int bt_mesh_sar_receiver_get(void *param); +extern int bt_mesh_sar_receiver_set(void *param, void *set); + +/* SAR Configuration Client model related functions */ + +static inline void btc_ble_mesh_sar_client_cb_to_app(esp_ble_mesh_sar_client_cb_event_t event, + esp_ble_mesh_sar_client_cb_param_t *param) +{ + esp_ble_mesh_sar_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_SAR_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_sar_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_sar_client_args_t *dst = p_dest; + btc_ble_mesh_sar_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SAR_CLIENT_SEND: + dst->sar_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->sar_send.params) { + memcpy(dst->sar_send.params, src->sar_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->sar_send.msg) { + dst->sar_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_sar_client_msg_t)); + if (dst->sar_send.msg) { + memcpy(dst->sar_send.msg, src->sar_send.msg, + sizeof(esp_ble_mesh_sar_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_sar_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_sar_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_sar_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SAR_CLIENT_SEND: + if (arg->sar_send.params) { + bt_mesh_free(arg->sar_send.params); + } + if (arg->sar_send.msg) { + bt_mesh_free(arg->sar_send.msg); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_sar_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_sar_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_sar_client_cb_param_t *p_src_data = p_src; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } +} + +static void btc_ble_mesh_sar_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_sar_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_sar_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_SAR_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_SAR_CLIENT_SEND_TIMEOUT_EVT: + case ESP_BLE_MESH_SAR_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_SAR_CLIENT_RECV_PUB_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_sar_client_cb(esp_ble_mesh_sar_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_SAR_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_SAR_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_sar_client_cb_param_t), + btc_ble_mesh_sar_client_copy_req_data, + btc_ble_mesh_sar_client_free_req_data); +} + +void bt_mesh_sar_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_sar_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_SAR_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_SAR_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_SAR_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_SAR_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown SAR Config client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_sar_client_cb(&cb_params, act); +} + +void btc_ble_mesh_sar_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_sar_client_cb_evt_to_btc(opcode, BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_sar_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_sar_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if ((params->opcode == ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_SET || + params->opcode == ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_SET) && msg == NULL) { + BT_ERR("Invalid SAR Config message, opcode 0x%04x", params->opcode); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, true); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_GET: + return bt_mesh_sar_transmitter_get(¶m); + case ESP_BLE_MESH_MODEL_OP_SAR_TRANSMITTER_SET: + return bt_mesh_sar_transmitter_set(¶m, &msg->sar_transmitter_set); + case ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_GET: + return bt_mesh_sar_receiver_get(¶m); + case ESP_BLE_MESH_MODEL_OP_SAR_RECEIVER_SET: + return bt_mesh_sar_receiver_set(¶m, &msg->sar_receiver_set); + default: + BT_ERR("Invalid SAR Config opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_sar_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_sar_client_cb_param_t cb = {0}; + btc_ble_mesh_sar_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_sar_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SAR_CLIENT_SEND: + cb.params = arg->sar_send.params; + cb.send.err_code = btc_ble_mesh_sar_client_send(arg->sar_send.params, + arg->sar_send.msg); + btc_ble_mesh_sar_client_cb(&cb, ESP_BLE_MESH_SAR_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_sar_client_arg_deep_free(msg); +} + +void btc_ble_mesh_sar_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_sar_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_sar_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_SAR_CLIENT_EVT_MAX) { + btc_ble_mesh_sar_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_sar_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_SAR_CLI */ + +#if CONFIG_BLE_MESH_SAR_SRV + +/* SAR Config Server model related functions */ + +static inline void btc_ble_mesh_sar_server_cb_to_app(esp_ble_mesh_sar_server_cb_event_t event, + esp_ble_mesh_sar_server_cb_param_t *param) +{ + esp_ble_mesh_sar_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_SAR_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_sar_server_cb(esp_ble_mesh_sar_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_SAR_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_SAR_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_sar_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_sar_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_sar_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_SAR_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_SAR_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown SAR Config server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_sar_server_cb(&cb_params, act); +} + +void btc_ble_mesh_sar_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_sar_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_sar_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_SAR_SERVER_EVT_MAX) { + btc_ble_mesh_sar_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_SAR_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c new file mode 100644 index 0000000000..568c255cdb --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c @@ -0,0 +1,370 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_srpl_model.h" +#include "esp_ble_mesh_srpl_model_api.h" + +#if CONFIG_BLE_MESH_SRPL_CLI + +extern int bt_mesh_solic_pdu_rpl_items_clear(void *param, void *uar); + +/* Solicitation PDU RPL Configuration Client model related functions */ + +static inline void btc_ble_mesh_srpl_client_cb_to_app(esp_ble_mesh_srpl_client_cb_event_t event, + esp_ble_mesh_srpl_client_cb_param_t *param) +{ + esp_ble_mesh_srpl_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_SRPL_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_srpl_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_srpl_client_args_t *dst = p_dest; + btc_ble_mesh_srpl_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SRPL_CLIENT_SEND: + dst->srpl_send.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + dst->srpl_send.msg = bt_mesh_calloc(sizeof(esp_ble_mesh_srpl_client_msg_t)); + if (dst->srpl_send.params && dst->srpl_send.msg) { + memcpy(dst->srpl_send.params, src->srpl_send.params, + sizeof(esp_ble_mesh_client_common_param_t)); + memcpy(dst->srpl_send.msg, src->srpl_send.msg, + sizeof(esp_ble_mesh_srpl_client_msg_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + break; + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_srpl_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_srpl_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_srpl_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SRPL_CLIENT_SEND: + if (arg->srpl_send.msg) { + bt_mesh_free(arg->srpl_send.msg); + } + if (arg->srpl_send.params) { + bt_mesh_free(arg->srpl_send.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_srpl_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_srpl_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_srpl_client_cb_param_t *p_src_data = p_src; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } +} + +static void btc_ble_mesh_srpl_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_srpl_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_srpl_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_SRPL_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_SRPL_CLIENT_SEND_TIMEOUT_EVT: + case ESP_BLE_MESH_SRPL_CLIENT_RECV_RSP_EVT: + case ESP_BLE_MESH_SRPL_CLIENT_RECV_PUB_EVT: + if (arg->params) { + bt_mesh_free(arg->params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_srpl_client_cb(esp_ble_mesh_srpl_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_SRPL_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_SRPL_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_srpl_client_cb_param_t), + btc_ble_mesh_srpl_client_copy_req_data, + btc_ble_mesh_srpl_client_free_req_data); +} + +void bt_mesh_srpl_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_srpl_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_SRPL_CLIENT_SEND_TIMEOUT: + act = ESP_BLE_MESH_SRPL_CLIENT_SEND_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_SRPL_CLIENT_RECV_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_PUB: + act = ESP_BLE_MESH_SRPL_CLIENT_RECV_PUB_EVT; + break; + default: + BT_ERR("Unknown Solicitation PDU RPL Config client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_srpl_client_cb(&cb_params, act); +} + +void btc_ble_mesh_srpl_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + bt_mesh_srpl_client_cb_evt_to_btc(opcode, + BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_PUB, + model, ctx, buf->data, buf->len); +} + +static int btc_ble_mesh_srpl_client_send(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_srpl_client_msg_t *msg) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL || msg == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (param.opcode) { + case ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_CLEAR: + case ESP_BLE_MESH_MODEL_OP_SRPL_ITEMS_CLEAR_UNACK: + return bt_mesh_solic_pdu_rpl_items_clear(¶m, &msg->srpl_items_clear.addr_range); + default: + BT_ERR("Invalid Solicitation PDU RPL Config Set opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_srpl_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_srpl_client_cb_param_t cb = {0}; + btc_ble_mesh_srpl_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_srpl_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_SRPL_CLIENT_SEND: + cb.params = arg->srpl_send.params; + cb.send.err_code = btc_ble_mesh_srpl_client_send(arg->srpl_send.params, + arg->srpl_send.msg); + btc_ble_mesh_srpl_client_cb(&cb, + ESP_BLE_MESH_SRPL_CLIENT_SEND_COMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_srpl_client_arg_deep_free(msg); +} + +void btc_ble_mesh_srpl_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_srpl_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_srpl_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_SRPL_CLIENT_EVT_MAX) { + btc_ble_mesh_srpl_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_srpl_client_free_req_data(msg); +} + +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ + +#if CONFIG_BLE_MESH_SRPL_SRV + +/* Solicitation PDU RPL Config Server model related functions */ + +static inline void btc_ble_mesh_srpl_server_cb_to_app(esp_ble_mesh_srpl_server_cb_event_t event, + esp_ble_mesh_srpl_server_cb_param_t *param) +{ + esp_ble_mesh_srpl_server_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_SRPL_SERVER); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static void btc_ble_mesh_srpl_server_cb(esp_ble_mesh_srpl_server_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_SRPL_SERVER)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_SRPL_SERVER; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_srpl_server_cb_param_t), NULL, NULL); +} + +void bt_mesh_srpl_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_srpl_server_cb_param_t cb_params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.value)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_SRPL_SERVER_STATE_CHANGE: + act = ESP_BLE_MESH_SRPL_SERVER_STATE_CHANGE_EVT; + break; + default: + BT_ERR("Unknown Solicitation PDU RPL Config server event type %d", event); + return; + } + + cb_params.model = (esp_ble_mesh_model_t *)model; + cb_params.ctx.net_idx = ctx->net_idx; + cb_params.ctx.app_idx = ctx->app_idx; + cb_params.ctx.addr = ctx->addr; + cb_params.ctx.recv_ttl = ctx->recv_ttl; + cb_params.ctx.recv_op = ctx->recv_op; + cb_params.ctx.recv_dst = ctx->recv_dst; + cb_params.ctx.recv_rssi = ctx->recv_rssi; + cb_params.ctx.send_ttl = ctx->send_ttl; + + if (val && len) { + memcpy(&cb_params.value, val, len); + } + + btc_ble_mesh_srpl_server_cb(&cb_params, act); +} + +void btc_ble_mesh_srpl_server_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_srpl_server_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_srpl_server_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_SRPL_SERVER_EVT_MAX) { + btc_ble_mesh_srpl_server_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } +} + +#endif /* CONFIG_BLE_MESH_SRPL_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_agg_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_agg_model.h new file mode 100644 index 0000000000..14e4dcecd3 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_agg_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_AGG_MODEL_H_ +#define _BTC_BLE_MESH_AGG_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_agg_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_AGG_CLIENT_SEND, + BTC_BLE_MESH_ACT_AGG_CLIENT_MAX, +} btc_ble_mesh_agg_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_agg_client_msg_t *msg; + } agg_send; +} btc_ble_mesh_agg_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_AGG_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_AGG_CLIENT_MAX, +} btc_ble_mesh_agg_client_evt_t; + +void btc_ble_mesh_agg_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_agg_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_agg_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_agg_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_agg_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_agg_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_AGG_SERVER_RECV_MSG, + BTC_BLE_MESH_EVT_AGG_SERVER_MAX, +} btc_ble_mesh_agg_server_evt_t; + +void btc_ble_mesh_agg_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_agg_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_AGG_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_brc_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_brc_model.h new file mode 100644 index 0000000000..ab601fa2b5 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_brc_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_BRC_MODEL_H_ +#define _BTC_BLE_MESH_BRC_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_brc_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_BRC_CLIENT_SEND, + BTC_BLE_MESH_ACT_BRC_CLIENT_MAX, +} btc_ble_mesh_brc_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_brc_client_msg_t *msg; + } brc_send; +} btc_ble_mesh_brc_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_BRC_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_BRC_CLIENT_MAX, +} btc_ble_mesh_brc_client_evt_t; + +void btc_ble_mesh_brc_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_brc_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_brc_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_brc_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_brc_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_brc_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_BRC_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_BRC_SERVER_MAX, +} btc_ble_mesh_brc_server_evt_t; + +void btc_ble_mesh_brc_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_brc_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_BRC_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_df_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_df_model.h new file mode 100644 index 0000000000..b0b8531f80 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_df_model.h @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_DF_MODEL_H_ +#define _BTC_BLE_MESH_DF_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_df_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_DF_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_DF_CLIENT_SET_STATE, + BTC_BLE_MESH_ACT_DF_CLIENT_MAX, +} btc_ble_mesh_df_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_df_client_get_t *get; + } df_get; + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_df_client_set_t *set; + } df_set; +} btc_ble_mesh_df_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_DF_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_DF_CLIENT_RECV_GET_RSP, + BTC_BLE_MESH_EVT_DF_CLIENT_RECV_SET_RSP, + BTC_BLE_MESH_EVT_DF_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_DF_CLIENT_MAX, +} btc_ble_mesh_df_client_evt_t; + +void btc_ble_mesh_df_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_df_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_df_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_df_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_df_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_df_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_DF_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_DF_SERVER_TABLE_CHANGE, + BTC_BLE_MESH_EVT_DF_SERVER_MAX, +} btc_ble_mesh_df_server_evt_t; + +void btc_ble_mesh_df_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_df_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_DF_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_lcd_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_lcd_model.h new file mode 100644 index 0000000000..d25ae77f70 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_lcd_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_LCD_MODEL_H_ +#define _BTC_BLE_MESH_LCD_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_lcd_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_LCD_CLIENT_SEND, + BTC_BLE_MESH_ACT_LCD_CLIENT_MAX, +} btc_ble_mesh_lcd_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_lcd_client_msg_t *msg; + } lcd_send; +} btc_ble_mesh_lcd_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_LCD_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_LCD_CLIENT_MAX, +} btc_ble_mesh_lcd_client_evt_t; + +void btc_ble_mesh_lcd_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_lcd_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_lcd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_lcd_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_lcd_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_lcd_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_LCD_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_LCD_SERVER_MAX, +} btc_ble_mesh_lcd_server_evt_t; + +void btc_ble_mesh_lcd_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_lcd_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_LCD_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h new file mode 100644 index 0000000000..070888ca55 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_MBT_MODEL_H_ +#define _BTC_BLE_MESH_MBT_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_mbt_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES, + BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB, + BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_BLOCK, + BTC_BLE_MESH_ACT_MBT_CLIENT_SEND_DATA, + BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_BLOCK_STATUS, + BTC_BLE_MESH_ACT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS, + BTC_BLE_MESH_ACT_MBT_CLIENT_CANCEL_TRANSFER, + BTC_BLE_MESH_ACT_MBT_CLIENT_SET_TRANSFER_TTL, + BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_TRANSFER_TTL, + BTC_BLE_MESH_ACT_MBT_CLIENT_SET_APP_IDX, + BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_APP_IDX, + BTC_BLE_MESH_ACT_MBT_CLIENT_SET_MULTICAST_ADDR, + BTC_BLE_MESH_ACT_MBT_CLIENT_CLEAR_MULTICAST_ADDR, + BTC_BLE_MESH_ACT_MBT_CLIENT_MAX, +} btc_ble_mesh_mbt_client_act_t; + +typedef union { + esp_ble_mesh_retrieve_capabilities_t retrieve_capabilities; + esp_ble_mesh_transfer_blob_t transfer_blob; + esp_ble_mesh_send_block_t send_block; + esp_ble_mesh_send_data_t send_data; + esp_ble_mesh_determine_block_status_t determine_block_status; + esp_ble_mesh_determine_transfer_status_t determine_transfer_status; + esp_ble_mesh_cancel_transfer_t cancel_transfer; + struct { + esp_ble_mesh_model_t *model; + uint8_t transfer_ttl; + } set_transfer_ttl; + struct { + esp_ble_mesh_model_t *model; + } clear_transfer_ttl; + struct { + esp_ble_mesh_model_t *model; + uint16_t app_idx; + } set_app_idx; + struct { + esp_ble_mesh_model_t *model; + } clear_app_idx; + struct { + esp_ble_mesh_model_t *model; + uint16_t multicast_addr; + } set_multicast_addr; + struct { + esp_ble_mesh_model_t *model; + } clear_multicast_addr; +} btc_ble_mesh_mbt_client_args_t; + +#define BTC_BLE_MESH_MBT_CLIENT_RESULT_COMPLETE 0x00 +#define BTC_BLE_MESH_MBT_CLIENT_RESULT_FAIL 0x01 + +typedef enum { + BTC_BLE_MESH_EVT_MBT_CLIENT_RETRIEVE_CAPABILITIES_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_TRANSFER_BLOB_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_BLOCK_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_DATA_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_BLOCK_STATUS_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_CANCEL_TRANSFER_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_SET_TRANSFER_TTL_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_TRANSFER_TTL_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_SET_APP_IDX_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_APP_IDX_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_SET_MULTICAST_ADDR_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP, + BTC_BLE_MESH_EVT_MBT_CLIENT_MAX, +} btc_ble_mesh_mbt_client_evt_t; + +void btc_ble_mesh_mbt_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_mbt_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_mbt_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_mbt_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_mbt_client_publish_callback(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_mbt_client_cb_evt_to_btc(uint8_t event, uint8_t result, + struct bt_mesh_model *model); + +typedef enum { + BTC_BLE_MESH_ACT_MBT_SERVER_INITIALIZE_BLOB_RECEIVE, + BTC_BLE_MESH_ACT_MBT_SERVER_CANCEL_BLOB_RECEIVE, + BTC_BLE_MESH_ACT_MBT_SERVER_SET_BLOB_CAPABILITIES, + BTC_BLE_MESH_ACT_MBT_SERVER_MAX, +} btc_ble_mesh_mbt_server_act_t; + +typedef union { + esp_ble_mesh_initialize_blob_receive_t initialize_blob_receive; + esp_ble_mesh_cancel_blob_receive_t cancel_blob_receive; + esp_ble_mesh_set_blob_capabilities_t set_blob_capabilities; +} btc_ble_mesh_mbt_server_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_MBT_SERVER_INITIALIZE_BLOB_RECEIVE_COMP, + BTC_BLE_MESH_EVT_MBT_SERVER_CANCEL_BLOB_RECEIVE_COMP, + BTC_BLE_MESH_EVT_MBT_SERVER_SET_BLOB_CAPABILITIES_COMP, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_GET, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_START, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_CANCEL, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_GET, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_START, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_CHUNK_TRANSFER, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_INFORMATION_GET, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOCK_RECEIVE_COMP, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_COMP, + BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_TIMEOUT, + BTC_BLE_MESH_EVT_MBT_SERVER_MAX, +} btc_ble_mesh_mbt_server_evt_t; + +void btc_ble_mesh_mbt_server_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_mbt_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_mbt_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_MBT_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_odp_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_odp_model.h new file mode 100644 index 0000000000..032c357756 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_odp_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_ODP_MODEL_H_ +#define _BTC_BLE_MESH_ODP_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_odp_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_ODP_CLIENT_SEND, + BTC_BLE_MESH_ACT_ODP_CLIENT_MAX, +} btc_ble_mesh_odp_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_odp_client_msg_t *msg; + } odp_send; +} btc_ble_mesh_odp_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_ODP_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_ODP_CLIENT_MAX, +} btc_ble_mesh_odp_client_evt_t; + +void btc_ble_mesh_odp_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_odp_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_odp_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_odp_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_odp_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_odp_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_ODP_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_ODP_SERVER_MAX, +} btc_ble_mesh_odp_server_evt_t; + +void btc_ble_mesh_odp_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_odp_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_ODP_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_prb_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_prb_model.h new file mode 100644 index 0000000000..feef97013a --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_prb_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_PRB_MODEL_H_ +#define _BTC_BLE_MESH_PRB_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_prb_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_PRB_CLIENT_SEND, + BTC_BLE_MESH_ACT_PRB_CLIENT_MAX, +} btc_ble_mesh_prb_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_prb_client_msg_t *msg; + } prb_send; +} btc_ble_mesh_prb_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_PRB_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_PRB_CLIENT_MAX, +} btc_ble_mesh_prb_client_evt_t; + +void btc_ble_mesh_prb_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_prb_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_prb_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_prb_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_prb_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_prb_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, uint16_t len); + +typedef enum { + BTC_BLE_MESH_EVT_PRB_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_PRB_SERVER_MAX, +} btc_ble_mesh_prb_server_evt_t; + +void btc_ble_mesh_prb_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_prb_server_cb_evt_to_btc(uint8_t evt_type, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_PRB_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_rpr_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_rpr_model.h new file mode 100644 index 0000000000..e521778221 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_rpr_model.h @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_RPR_MODEL_H_ +#define _BTC_BLE_MESH_RPR_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_rpr_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_RPR_CLIENT_SEND, + BTC_BLE_MESH_ACT_RPR_CLIENT_ACT, + BTC_BLE_MESH_ACT_RPR_CLIENT_MAX, +} btc_ble_mesh_rpr_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_rpr_client_msg_t *msg; + } rpr_send; + struct { + esp_ble_mesh_rpr_client_act_type_t type; + esp_ble_mesh_rpr_client_act_param_t *param; + } rpr_act; +} btc_ble_mesh_rpr_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_RPR_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_RPR_CLIENT_MAX, +} btc_ble_mesh_rpr_client_evt_t; + +void btc_ble_mesh_rpr_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_rpr_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_rpr_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_rpr_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_rpr_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void btc_ble_mesh_rpr_client_link_close_cb(struct bt_mesh_model *model, + uint16_t rpr_srv_addr, uint8_t reason); + +void btc_ble_mesh_rpr_client_prov_comp_cb(struct bt_mesh_model *model, uint16_t rpr_srv_addr, + uint8_t nppi, uint16_t index, uint8_t uuid[16], + uint16_t unicast_addr, uint8_t element_num, + uint16_t net_idx); + +void bt_mesh_rpr_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const void *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_START, + BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_STOP, + BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_START, + BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_STOP, + BTC_BLE_MESH_EVT_RPR_SERVER_LINK_OPEN, + BTC_BLE_MESH_EVT_RPR_SERVER_LINK_CLOSE, + BTC_BLE_MESH_EVT_RPR_SERVER_PROV_COMP, + BTC_BLE_MESH_EVT_RPR_SERVER_MAX, +} btc_ble_mesh_rpr_server_evt_t; + +void btc_ble_mesh_rpr_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_rpr_server_cb_evt_to_btc(uint8_t event, const void *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_RPR_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_sar_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_sar_model.h new file mode 100644 index 0000000000..433c4a02f9 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_sar_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_SAR_MODEL_H_ +#define _BTC_BLE_MESH_SAR_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_sar_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_SAR_CLIENT_SEND, + BTC_BLE_MESH_ACT_SAR_CLIENT_MAX, +} btc_ble_mesh_sar_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_sar_client_msg_t *msg; + } sar_send; +} btc_ble_mesh_sar_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_SAR_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_SAR_CLIENT_MAX, +} btc_ble_mesh_sar_client_evt_t; + +void btc_ble_mesh_sar_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_sar_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_sar_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_sar_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_sar_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_sar_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +void btc_ble_mesh_sar_server_cb_handler(btc_msg_t *msg); + +typedef enum { + BTC_BLE_MESH_EVT_SAR_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_SAR_SERVER_MAX, +} btc_ble_mesh_sar_server_evt_t; + +void bt_mesh_sar_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_SAR_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_srpl_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_srpl_model.h new file mode 100644 index 0000000000..8d2f0c3d0d --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_srpl_model.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_SRPL_MODEL_H_ +#define _BTC_BLE_MESH_SRPL_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_srpl_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BTC_BLE_MESH_ACT_SRPL_CLIENT_SEND, + BTC_BLE_MESH_ACT_SRPL_CLIENT_MAX, +} btc_ble_mesh_srpl_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_srpl_client_msg_t *msg; + } srpl_send; +} btc_ble_mesh_srpl_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_SRPL_CLIENT_SEND_TIMEOUT, + BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_PUB, + BTC_BLE_MESH_EVT_SRPL_CLIENT_MAX, +} btc_ble_mesh_srpl_client_evt_t; + +void btc_ble_mesh_srpl_client_call_handler(btc_msg_t *msg); + +void btc_ble_mesh_srpl_client_cb_handler(btc_msg_t *msg); + +void btc_ble_mesh_srpl_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +void btc_ble_mesh_srpl_client_arg_deep_free(btc_msg_t *msg); + +void btc_ble_mesh_srpl_client_recv_pub_cb(uint32_t opcode, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + +void bt_mesh_srpl_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +typedef enum { + BTC_BLE_MESH_EVT_SRPL_SERVER_STATE_CHANGE, + BTC_BLE_MESH_EVT_SRPL_SERVER_MAX, +} btc_ble_mesh_srpl_server_evt_t; + +void btc_ble_mesh_srpl_server_cb_handler(btc_msg_t *msg); + +void bt_mesh_srpl_server_cb_evt_to_btc(uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_SRPL_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/ext.c b/components/bt/esp_ble_mesh/v1.1/ext.c new file mode 100644 index 0000000000..b6d30d7a0e --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/ext.c @@ -0,0 +1,4836 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#if CONFIG_BT_BLUEDROID_ENABLED +#include "bta/bta_api.h" +#endif + +#include "btc_ble_mesh_agg_model.h" +#include "btc_ble_mesh_brc_model.h" +#include "btc_ble_mesh_df_model.h" +#include "btc_ble_mesh_lcd_model.h" +#include "btc_ble_mesh_mbt_model.h" +#include "btc_ble_mesh_odp_model.h" +#include "btc_ble_mesh_prb_model.h" +#include "btc_ble_mesh_rpr_model.h" +#include "btc_ble_mesh_sar_model.h" +#include "btc_ble_mesh_srpl_model.h" + +#include "adv.h" +#include "net.h" +#include "scan.h" +#include "crypto.h" +#include "access.h" +#include "beacon.h" +#include "friend.h" +#include "lpn.h" +#include "rpl.h" +#include "foundation.h" +#include +#include +#include "mesh/buf.h" +#include "mesh/slist.h" +#include "mesh/config.h" +#include "mesh/adapter.h" +#include "mesh/main.h" +#include "mesh/timer.h" +#include "mesh/mutex.h" +#include "mesh/common.h" +#include "mesh/access.h" +#include "prov_common.h" +#include "prov_node.h" +#include "prov_pvnr.h" +#include "pvnr_mgmt.h" +#include "transport.h" +#include "proxy_client.h" +#include "proxy_server.h" +#include "settings.h" +#include "settings_nvs.h" +#include "mesh/model_common.h" +#include "mesh/client_common.h" + +#include "mesh_v1.1/utils.h" + +#define NET_BUF(a) ((struct net_buf *)(a)) +#define k_WORK(a) ((struct k_work *)(a)) +#define COMP(a) ((const struct bt_mesh_comp *)(a)) +#define ELEM(a) ((struct bt_mesh_elem *)(a)) +#define MODEL(a) ((struct bt_mesh_model *)(a)) +#define APP_KEY(a) ((struct bt_mesh_app_key *)(a)) +#define NODE(a) ((struct bt_mesh_node *)(a)) +#define LINK(a) ((struct bt_mesh_prov_link *)(a)) +#define PROXY_CLI(a) ((struct bt_mesh_proxy_client *)(a)) +#define PROXY_CFG(a) ((struct bt_mesh_proxy_cfg_pdu *)(a)) +#define FRIEND(a) ((struct bt_mesh_friend *)(a)) +#define SUBNET(a) ((struct bt_mesh_subnet *)(a)) +#define NET_TX(a) ((struct bt_mesh_net_tx *)(a)) +#define NET_RX(a) ((struct bt_mesh_net_rx *)(a)) +#define MSG_CTX(a) ((struct bt_mesh_msg_ctx *)(a)) +#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 VOID(a) ((void *)(a)) + +/* Sys utilities */ +void bt_mesh_ext_put_be16(uint16_t val, uint8_t dst[2]) +{ + sys_put_be16(val, dst); +} + +void bt_mesh_ext_put_be24(uint32_t val, uint8_t dst[3]) +{ + sys_put_be24(val, dst); +} + +void bt_mesh_ext_put_be32(uint32_t val, uint8_t dst[4]) +{ + sys_put_be32(val, dst); +} + +void bt_mesh_ext_put_be48(uint64_t val, uint8_t dst[6]) +{ + sys_put_be48(val, dst); +} + +void bt_mesh_ext_put_be64(uint64_t val, uint8_t dst[8]) +{ + sys_put_be64(val, dst); +} + +void bt_mesh_ext_put_le16(uint16_t val, uint8_t dst[2]) +{ + sys_put_le16(val, dst); +} + +void bt_mesh_ext_put_le24(uint32_t val, uint8_t dst[3]) +{ + sys_put_le24(val, dst); +} + +void bt_mesh_ext_put_le32(uint32_t val, uint8_t dst[4]) +{ + sys_put_le32(val, dst); +} + +void bt_mesh_ext_put_le48(uint64_t val, uint8_t dst[6]) +{ + sys_put_le48(val, dst); +} + +void bt_mesh_ext_put_le64(uint64_t val, uint8_t dst[8]) +{ + sys_put_le64(val, dst); +} + +uint16_t bt_mesh_ext_get_be16(const uint8_t src[2]) +{ + return sys_get_be16(src); +} + +uint32_t bt_mesh_ext_get_be24(const uint8_t src[3]) +{ + return sys_get_be24(src); +} + +uint32_t bt_mesh_ext_get_be32(const uint8_t src[4]) +{ + return sys_get_be32(src); +} + +uint64_t bt_mesh_ext_get_be48(const uint8_t src[6]) +{ + return sys_get_be48(src); +} + +uint64_t bt_mesh_ext_get_be64(const uint8_t src[8]) +{ + return sys_get_be64(src); +} + +uint16_t bt_mesh_ext_get_le16(const uint8_t src[2]) +{ + return sys_get_le16(src); +} + +uint32_t bt_mesh_ext_get_le24(const uint8_t src[3]) +{ + return sys_get_le24(src); +} + +uint32_t bt_mesh_ext_get_le32(const uint8_t src[4]) +{ + return sys_get_le32(src); +} + +uint64_t bt_mesh_ext_get_le48(const uint8_t src[6]) +{ + return sys_get_le48(src); +} + +uint64_t bt_mesh_ext_get_le64(const uint8_t src[8]) +{ + return sys_get_le64(src); +} + +void bt_mesh_ext_memcpy_swap(void *dst, const void *src, size_t length) +{ + sys_memcpy_swap(dst, src, length); +} + +void bt_mesh_ext_mem_swap(void *buf, size_t length) +{ + sys_mem_swap(buf, length); +} + +/* Net buf */ +void bt_mesh_ext_buf_simple_init(struct net_buf_simple *buf, size_t reserve_head) +{ + net_buf_simple_init(buf, reserve_head); +} + +void bt_mesh_ext_buf_simple_init_with_data(struct net_buf_simple *buf, void *data, size_t size) +{ + net_buf_simple_init_with_data(buf, data, size); +} + +void bt_mesh_ext_buf_simple_reset(struct net_buf_simple *buf) +{ + net_buf_simple_reset(buf); +} + +void bt_mesh_ext_buf_simple_clone(const struct net_buf_simple *original, struct net_buf_simple *clone) +{ + net_buf_simple_clone(original, clone); +} + +void *bt_mesh_ext_buf_simple_add(struct net_buf_simple *buf, size_t len) +{ + return net_buf_simple_add(buf, len); +} + +void *bt_mesh_ext_buf_simple_add_mem(struct net_buf_simple *buf, const void *mem, size_t len) +{ + return net_buf_simple_add_mem(buf, mem, len); +} + +uint8_t *bt_mesh_ext_buf_simple_add_u8(struct net_buf_simple *buf, uint8_t val) +{ + return net_buf_simple_add_u8(buf, val); +} + +void bt_mesh_ext_buf_simple_add_le16(struct net_buf_simple *buf, uint16_t val) +{ + net_buf_simple_add_le16(buf, val); +} + +void bt_mesh_ext_buf_simple_add_be16(struct net_buf_simple *buf, uint16_t val) +{ + net_buf_simple_add_be16(buf, val); +} + +void bt_mesh_ext_buf_simple_add_le24(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_add_le24(buf, val); +} + +void bt_mesh_ext_buf_simple_add_be24(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_add_be24(buf, val); +} + +void bt_mesh_ext_buf_simple_add_le32(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_add_le32(buf, val); +} + +void bt_mesh_ext_buf_simple_add_be32(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_add_be32(buf, val); +} + +void bt_mesh_ext_buf_simple_add_le48(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_add_le48(buf, val); +} + +void bt_mesh_ext_buf_simple_add_be48(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_add_be48(buf, val); +} + +void bt_mesh_ext_buf_simple_add_le64(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_add_le64(buf, val); +} + +void bt_mesh_ext_buf_simple_add_be64(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_add_be64(buf, val); +} + +void *bt_mesh_ext_buf_simple_push(struct net_buf_simple *buf, size_t len) +{ + return net_buf_simple_push(buf, len); +} + +void bt_mesh_ext_buf_simple_push_le16(struct net_buf_simple *buf, uint16_t val) +{ + net_buf_simple_push_le16(buf, val); +} + +void bt_mesh_ext_buf_simple_push_be16(struct net_buf_simple *buf, uint16_t val) +{ + net_buf_simple_push_be16(buf, val); +} + +void bt_mesh_ext_buf_simple_push_u8(struct net_buf_simple *buf, uint8_t val) +{ + net_buf_simple_push_u8(buf, val); +} + +void bt_mesh_ext_buf_simple_push_le24(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_push_le24(buf, val); +} + +void bt_mesh_ext_buf_simple_push_be24(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_push_be24(buf, val); +} + +void bt_mesh_ext_buf_simple_push_le32(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_push_le32(buf, val); +} + +void bt_mesh_ext_buf_simple_push_be32(struct net_buf_simple *buf, uint32_t val) +{ + net_buf_simple_push_be32(buf, val); +} + +void bt_mesh_ext_buf_simple_push_le48(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_push_le48(buf, val); +} + +void bt_mesh_ext_buf_simple_push_be48(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_push_be48(buf, val); +} + +void bt_mesh_ext_buf_simple_push_le64(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_push_le64(buf, val); +} + +void bt_mesh_ext_buf_simple_push_be64(struct net_buf_simple *buf, uint64_t val) +{ + net_buf_simple_push_be64(buf, val); +} + +void *bt_mesh_ext_buf_simple_pull(struct net_buf_simple *buf, size_t len) +{ + return net_buf_simple_pull(buf, len); +} + +void *bt_mesh_ext_buf_simple_pull_mem(struct net_buf_simple *buf, size_t len) +{ + return net_buf_simple_pull_mem(buf, len); +} + +uint8_t bt_mesh_ext_buf_simple_pull_u8(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_u8(buf); +} + +uint16_t bt_mesh_ext_buf_simple_pull_le16(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_le16(buf); +} + +uint16_t bt_mesh_ext_buf_simple_pull_be16(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_be16(buf); +} + +uint32_t bt_mesh_ext_buf_simple_pull_le24(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_le24(buf); +} + +uint32_t bt_mesh_ext_buf_simple_pull_be24(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_be24(buf); +} + +uint32_t bt_mesh_ext_buf_simple_pull_le32(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_le32(buf); +} + +uint32_t bt_mesh_ext_buf_simple_pull_be32(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_be32(buf); +} + +uint64_t bt_mesh_ext_buf_simple_pull_le48(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_le48(buf); +} + +uint64_t bt_mesh_ext_buf_simple_pull_be48(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_be48(buf); +} + +uint64_t bt_mesh_ext_buf_simple_pull_le64(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_le64(buf); +} + +uint64_t bt_mesh_ext_buf_simple_pull_be64(struct net_buf_simple *buf) +{ + return net_buf_simple_pull_be64(buf); +} + +uint8_t *bt_mesh_ext_buf_simple_tail(struct net_buf_simple *buf) +{ + return net_buf_simple_tail(buf); +} + +size_t bt_mesh_ext_buf_simple_headroom(struct net_buf_simple *buf) +{ + return net_buf_simple_headroom(buf); +} + +size_t bt_mesh_ext_buf_simple_tailroom(struct net_buf_simple *buf) +{ + return net_buf_simple_tailroom(buf); +} + +void bt_mesh_ext_buf_simple_save(struct net_buf_simple *buf, struct net_buf_simple_state *state) +{ + net_buf_simple_save(buf, state); +} + +void bt_mesh_ext_buf_simple_restore(struct net_buf_simple *buf, struct net_buf_simple_state *state) +{ + net_buf_simple_restore(buf, state); +} + +void bt_mesh_ext_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve) +{ + net_buf_simple_reserve(buf, reserve); +} + +struct net_buf_simple *bt_mesh_ext_buf_get_simple(void *buf) +{ + return &NET_BUF(buf)->b; +} + +void *bt_mesh_ext_buf_add_mem(void *buf, const void *mem, size_t len) +{ + return net_buf_simple_add_mem(&NET_BUF(buf)->b, mem, len); +} + +uint8_t *bt_mesh_ext_buf_add_u8(void *buf, uint8_t val) +{ + return net_buf_simple_add_u8(&NET_BUF(buf)->b, val); +} + +void bt_mesh_ext_buf_add_le16(void *buf, uint16_t val) +{ + net_buf_simple_add_le16(&NET_BUF(buf)->b, val); +} + +void bt_mesh_ext_buf_unref(void *buf) +{ + net_buf_unref(buf); +} + +/* Memory */ +void *bt_mesh_ext_malloc(size_t size) +{ + return bt_mesh_malloc(size); +} + +void *bt_mesh_ext_calloc(size_t size) +{ + return bt_mesh_calloc(size); +} + +void bt_mesh_ext_free(void *ptr) +{ + bt_mesh_free(ptr); +} + +struct net_buf_simple *bt_mesh_ext_alloc_buf(uint16_t size) +{ + return bt_mesh_alloc_buf(size); +} + +void bt_mesh_ext_free_buf(struct net_buf_simple *buf) +{ + bt_mesh_free_buf(buf); +} + +/* Utilities */ +int bt_mesh_ext_rand(void *buf, size_t len) +{ + return bt_mesh_rand(buf, len); +} + +int32_t bt_mesh_ext_ceil(float num) +{ + return bt_mesh_ceil(num); +} + +float bt_mesh_ext_log2(float num) +{ + return bt_mesh_log2(num); +} + +/* Crypto */ +bool bt_mesh_ext_s1(const char *m, uint8_t salt[16]) +{ + return bt_mesh_s1(m, salt); +} + +int bt_mesh_ext_aes_cmac(const uint8_t key[16], void *sg, size_t sg_len, uint8_t mac[16]) +{ + return bt_mesh_aes_cmac(key, sg, sg_len, mac); +} + +int bt_mesh_ext_id128(const uint8_t n[16], const char *s, uint8_t out[16]) +{ + return bt_mesh_id128(n, s, out); +} + +int bt_mesh_ext_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], uint8_t enc_data[16]) +{ + return bt_mesh_encrypt_be(key, plaintext, enc_data); +} + +int bt_mesh_ext_net_obfuscate(uint8_t *pdu, uint32_t iv_index, const uint8_t privacy_key[16]) +{ + return bt_mesh_net_obfuscate(pdu, iv_index, privacy_key); +} + +int bt_mesh_ext_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, + uint32_t iv_index, bool proxy, bool proxy_solic) +{ + return bt_mesh_net_encrypt(key, buf, iv_index, proxy, proxy_solic); +} + +int bt_mesh_ext_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, + uint32_t iv_index, bool proxy, bool proxy_solic) +{ + return bt_mesh_net_decrypt(key, buf, iv_index, proxy, proxy_solic); +} + +int bt_mesh_ext_tc_hmac_set_key(void *ctx, const uint8_t *key, unsigned int key_size) +{ + return tc_hmac_set_key(ctx, key, key_size); +} + +int bt_mesh_ext_tc_hmac_init(void *ctx) +{ + return tc_hmac_init(ctx); +} + +int bt_mesh_ext_tc_hmac_update(void *ctx, const void *data, unsigned int data_length) +{ + return tc_hmac_update(ctx, data, data_length); +} + +int bt_mesh_ext_tc_hmac_final(uint8_t *tag, unsigned int taglen, void *ctx) +{ + return tc_hmac_final(tag, taglen, ctx); +} + +/* Mutex */ +void bt_mesh_ext_mutex_create(void *mutex) +{ + bt_mesh_mutex_create(mutex); +} + +void bt_mesh_ext_mutex_free(void *mutex) +{ + bt_mesh_mutex_free(mutex); +} + +void bt_mesh_ext_mutex_lock(void *mutex) +{ + bt_mesh_mutex_lock(mutex); +} + +void bt_mesh_ext_mutex_unlock(void *mutex) +{ + bt_mesh_mutex_unlock(mutex); +} + +void bt_mesh_ext_r_mutex_create(void *mutex) +{ + bt_mesh_r_mutex_create(mutex); +} + +void bt_mesh_ext_r_mutex_free(void *mutex) +{ + bt_mesh_r_mutex_free(mutex); +} + +void bt_mesh_ext_r_mutex_lock(void *mutex) +{ + bt_mesh_r_mutex_lock(mutex); +} + +void bt_mesh_ext_r_mutex_unlock(void *mutex) +{ + bt_mesh_r_mutex_unlock(mutex); +} + +/* Timer */ +int bt_mesh_ext_timer_init(void *work, void (*timeout_cb)(void *work)) +{ + return k_delayed_work_init(work, VOID(timeout_cb)); +} + +int bt_mesh_ext_timer_free(void *work) +{ + return k_delayed_work_free(work); +} + +int bt_mesh_ext_timer_submit(void *work, int32_t delay) +{ + return k_delayed_work_submit(work, delay); +} + +int bt_mesh_ext_timer_cancel(void *work) +{ + return k_delayed_work_cancel(work); +} + +int32_t bt_mesh_ext_timer_remaining_get(void *work) +{ + return k_delayed_work_remaining_get(work); +} + +uint32_t bt_mesh_ext_timer_get_32(void) +{ + return k_uptime_get_32(); +} + +void *bt_mesh_ext_timer_get_with_work(void *work) +{ + return CONTAINER_OF(work, struct k_delayed_work, work); +} + +void *bt_mesh_ext_timer_get_user_data(void *work) +{ + return k_WORK(work)->user_data; +} + +void bt_mesh_ext_timer_set_user_data(void *work, void *user_data) +{ + k_WORK(work)->user_data = user_data; +} + +/* Atomic */ +int bt_mesh_ext_atomic_inc(int *target) +{ + return bt_mesh_atomic_inc(target); +} + +int bt_mesh_ext_atomic_dec(int *target) +{ + return bt_mesh_atomic_dec(target); +} + +int bt_mesh_ext_atomic_get(const int *target) +{ + return bt_mesh_atomic_get(target); +} + +int bt_mesh_ext_atomic_set(int *target, int value) +{ + return bt_mesh_atomic_set(target, value); +} + +int bt_mesh_ext_atomic_or(int *target, int value) +{ + return bt_mesh_atomic_or(target, value); +} + +int bt_mesh_ext_atomic_and(int *target, int value) +{ + return bt_mesh_atomic_and(target, value); +} + +int bt_mesh_ext_atomic_test_bit(const int *target, int bit) +{ + return bt_mesh_atomic_test_bit(target, bit); +} + +int bt_mesh_ext_atomic_test_and_clear_bit(int *target, int bit) +{ + return bt_mesh_atomic_test_and_clear_bit(target, bit); +} + +int bt_mesh_ext_atomic_test_and_set_bit(int *target, int bit) +{ + return bt_mesh_atomic_test_and_set_bit(target, bit); +} + +void bt_mesh_ext_atomic_clear_bit(int *target, int bit) +{ + return bt_mesh_atomic_clear_bit(target, bit); +} + +void bt_mesh_ext_atomic_set_bit(int *target, int bit) +{ + return bt_mesh_atomic_set_bit(target, bit); +} + +void bt_mesh_ext_atomic_set_bit_to(int *target, int bit, bool val) +{ + return bt_mesh_atomic_set_bit_to(target, bit, val); +} + +/* Access */ +void bt_mesh_ext_comp_provision(uint16_t addr) +{ + bt_mesh_comp_provision(addr); +} + +int bt_mesh_ext_get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) +{ + return bt_mesh_get_opcode(buf, opcode, pull_buf); +} + +size_t bt_mesh_ext_rx_netkey_size(void) +{ + return bt_mesh_rx_netkey_size(); +} + +void *bt_mesh_ext_rx_netkey_get(size_t index) +{ + return bt_mesh_rx_netkey_get(index); +} + +uint16_t bt_mesh_ext_primary_addr(void) +{ + return bt_mesh_primary_addr(); +} + +const void *bt_mesh_ext_comp_get(void) +{ + return bt_mesh_comp_get(); +} + +size_t bt_mesh_ext_comp_get_elem_count(const void *comp) +{ + return COMP(comp)->elem_count; +} + +void *bt_mesh_ext_comp_get_elem(const void *comp, uint8_t index) +{ + return &COMP(comp)->elem[index]; +} + +uint16_t bt_mesh_ext_comp_get_cid(const void *comp) +{ + return COMP(comp)->cid; +} + +uint16_t bt_mesh_ext_comp_get_pid(const void *comp) +{ + return COMP(comp)->pid; +} + +uint16_t bt_mesh_ext_comp_get_vid(const void *comp) +{ + return COMP(comp)->vid; +} + +void *bt_mesh_ext_elem_find(uint16_t addr) +{ + return bt_mesh_elem_find(addr); +} + +uint8_t bt_mesh_ext_elem_count(void) +{ + return bt_mesh_elem_count(); +} + +uint16_t bt_mesh_ext_elem_get_loc(void *elem) +{ + return ELEM(elem)->loc; +} + +uint8_t bt_mesh_ext_elem_get_model_count(void *elem) +{ + return ELEM(elem)->model_count; +} + +void *bt_mesh_ext_elem_get_model(void *elem, uint8_t index) +{ + return &ELEM(elem)->models[index]; +} + +uint8_t bt_mesh_ext_elem_get_vnd_model_count(void *elem) +{ + return ELEM(elem)->vnd_model_count; +} + +void *bt_mesh_ext_elem_get_vnd_model(void *elem, uint8_t index) +{ + return &ELEM(elem)->vnd_models[index]; +} + +bool bt_mesh_ext_model_in_primary(const void *model) +{ + return bt_mesh_model_in_primary(model); +} + +void *bt_mesh_ext_model_elem(void *mod) +{ + return bt_mesh_model_elem(mod); +} + +void *bt_mesh_ext_model_find(void *elem, uint16_t id) +{ + return bt_mesh_model_find(elem, id); +} + +void *bt_mesh_ext_model_find_vnd(void *elem, uint16_t company, uint16_t id) +{ + return bt_mesh_model_find_vnd(elem, company, id); +} + +void bt_mesh_ext_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) +{ + bt_mesh_model_msg_init(msg, opcode); +} + +int bt_mesh_ext_model_send(void *model, void *ctx, struct net_buf_simple *msg, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + return bt_mesh_model_send(model, ctx, msg, cb, cb_data); +} + +uint16_t bt_mesh_ext_model_get_id(void *model) +{ + return MODEL(model)->id; +} + +uint16_t bt_mesh_ext_model_get_vnd_id(void *model) +{ + return MODEL(model)->vnd.id; +} + +uint16_t bt_mesh_ext_model_get_vnd_cid(void *model) +{ + return MODEL(model)->vnd.company; +} + +void *bt_mesh_ext_model_get_pub(void *model) +{ + return MODEL(model)->pub; +} + +uint16_t bt_mesh_ext_model_get_pub_addr(void *model) +{ + return MODEL(model)->pub->addr; +} + +uint16_t bt_mesh_ext_model_get_pub_key(void *model) +{ + return MODEL(model)->pub->key; +} + +uint8_t bt_mesh_ext_model_get_pub_directed_pub_policy(void *model) +{ +#if CONFIG_BLE_MESH_DF_SRV + return MODEL(model)->pub->directed_pub_policy; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_model_set_pub_directed_pub_policy(void *model, uint8_t directed_pub_policy) +{ +#if CONFIG_BLE_MESH_DF_SRV + MODEL(model)->pub->directed_pub_policy = directed_pub_policy; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_model_get_pub_msg(void *model) +{ + return MODEL(model)->pub->msg; +} + +uint8_t bt_mesh_ext_model_get_keys_count(void *model) +{ + return ARRAY_SIZE(MODEL(model)->keys); +} + +uint16_t bt_mesh_ext_model_get_keys_size(void *model) +{ + return sizeof(MODEL(model)->keys); +} + +uint16_t bt_mesh_ext_model_get_key(void *model, uint8_t index) +{ + return MODEL(model)->keys[index]; +} + +void bt_mesh_ext_model_set_key(void *model, uint8_t index, uint16_t key) +{ + MODEL(model)->keys[index] = key; +} + +uint8_t bt_mesh_ext_model_get_groups_count(void *model) +{ + return ARRAY_SIZE(MODEL(model)->groups); +} + +uint16_t bt_mesh_ext_model_get_groups_size(void *model) +{ + return sizeof(MODEL(model)->groups); +} + +uint16_t bt_mesh_ext_model_get_group(void *model, uint8_t index) +{ + return MODEL(model)->groups[index]; +} + +void bt_mesh_ext_model_set_group(void *model, uint8_t index, uint16_t group) +{ + MODEL(model)->groups[index] = group; +} + +void *bt_mesh_ext_model_get_user_data(void *model) +{ + return MODEL(model)->user_data; +} + +void bt_mesh_ext_model_set_user_data(void *model, void *user_data) +{ + MODEL(model)->user_data = user_data; +} + +void bt_mesh_ext_model_free_user_data(void *model) +{ + assert(MODEL(model)->user_data); + bt_mesh_free(MODEL(model)->user_data); + MODEL(model)->user_data = NULL; +} + +void bt_mesh_ext_model_set_user_data_model(void *model, void *mod) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + client->model = mod; +} + +void bt_mesh_ext_model_set_user_data_op_pair_size(void *model, uint32_t op_pair_size) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + client->op_pair_size = op_pair_size; +} + +void bt_mesh_ext_model_set_user_data_op_pair(void *model, const void *op_pair) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + client->op_pair = op_pair; +} + +void *bt_mesh_ext_model_get_user_data_internal_data(void *model) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + return client->internal_data; +} + +void bt_mesh_ext_model_set_user_data_internal_data(void *model, void *internal_data) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + client->internal_data = internal_data; +} + +void bt_mesh_ext_model_free_user_data_internal_data(void *model) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + assert(client->internal_data); + bt_mesh_free(client->internal_data); + client->internal_data = NULL; +} + +void *bt_mesh_ext_model_get_user_data_internal_data_queue(void *model) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + bt_mesh_client_internal_data_t *internal = client->internal_data; + assert(internal); + return &internal->queue; +} + +void *bt_mesh_ext_model_get_user_data_vendor_data(void *model) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + return client->vendor_data; +} + +void bt_mesh_ext_model_set_user_data_vendor_data(void *model, void *vendor_data) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + client->vendor_data = vendor_data; +} + +void bt_mesh_ext_model_free_user_data_vendor_data(void *model) +{ + bt_mesh_client_user_data_t *client = MODEL(model)->user_data; + assert(client); + assert(client->vendor_data); + bt_mesh_free(client->vendor_data); + client->vendor_data = NULL; +} + +bool bt_mesh_ext_model_is_opcode_belongs(void *models, uint8_t model_count, uint32_t opcode) +{ + const struct bt_mesh_model_op *op = NULL; + struct bt_mesh_model *model = NULL; + + for (size_t i = 0; i < model_count; i++) { + model = models + i; + for (op = model->op; op->func; op++) { + if (op->opcode == opcode) { + return true; + } + } + } + + return false; +} + +/* Transport */ +void *bt_mesh_ext_app_key_get(uint16_t app_idx) +{ + return bt_mesh_app_key_get(app_idx); +} + +uint16_t bt_mesh_ext_app_key_get_net_idx(void *key) +{ + return APP_KEY(key)->net_idx; +} + +int bt_mesh_ext_ctl_send(void *tx, uint8_t ctl_op, void *data, size_t data_len, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + return bt_mesh_ctl_send(tx, ctl_op, data, data_len, cb, cb_data); +} + +uint16_t bt_mesh_ext_get_tx_sdu_max(void) +{ + return BLE_MESH_TX_SDU_MAX; +} + +void bt_mesh_ext_tx_reset(void) +{ + bt_mesh_tx_reset(); +} + +void bt_mesh_ext_rx_reset(void) +{ + bt_mesh_rx_reset(); +} + +/* Net */ +void *bt_mesh_ext_subnet_get(uint16_t net_idx) +{ + return bt_mesh_subnet_get(net_idx); +} + +int bt_mesh_ext_net_encode(void *tx, struct net_buf_simple *buf, bool proxy) +{ + return bt_mesh_net_encode(tx, buf, proxy); +} + +uint8_t bt_mesh_ext_net_flags(void *sub) +{ + return bt_mesh_net_flags(sub); +} + +bool bt_mesh_ext_net_iv_update(uint32_t iv_index, bool iv_update) +{ + return bt_mesh_net_iv_update(iv_index, iv_update); +} + +bool bt_mesh_ext_kr_update(void *sub, uint8_t new_kr, bool new_key) +{ + return bt_mesh_kr_update(sub, new_kr, new_key); +} + +void bt_mesh_ext_net_sec_update(void *sub) +{ + bt_mesh_net_sec_update(sub); +} + +int bt_mesh_ext_net_pdu_decrypt(void *sub, const uint8_t *enc, + const uint8_t *priv, + const uint8_t *data, + size_t data_len, void *rx, + struct net_buf_simple *buf) +{ + extern int net_decrypt(struct bt_mesh_subnet *sub, + const uint8_t *enc, const uint8_t *priv, + const uint8_t *data, size_t data_len, + void *rx, + struct net_buf_simple *buf); + return net_decrypt(sub, enc, priv, data, data_len, rx, buf); +} + +uint16_t bt_mesh_ext_net_get_sub_net_idx(uint8_t index) +{ + return bt_mesh.sub[index].net_idx; +} + +uint8_t bt_mesh_ext_net_get_sub_count(void) +{ + return ARRAY_SIZE(bt_mesh.sub); +} + +void *bt_mesh_ext_net_get_sub(uint8_t index) +{ + return &bt_mesh.sub[index]; +} + +uint32_t bt_mesh_ext_net_get_iv_index(void) +{ + return bt_mesh.iv_index; +} + +void bt_mesh_ext_net_set_seq(uint32_t seq) +{ + bt_mesh.seq = seq; +} + +uint8_t *bt_mesh_ext_net_get_dev_key(void) +{ + return bt_mesh.dev_key; +} + +uint8_t *bt_mesh_ext_net_get_dev_key_ca(void) +{ + return bt_mesh.dev_key_ca; +} + +uint8_t bt_mesh_ext_net_get_rpl_count(void) +{ + return ARRAY_SIZE(bt_mesh.rpl); +} + +uint16_t bt_mesh_ext_net_get_rpl_src(uint8_t index) +{ + return bt_mesh.rpl[index].src; +} + +void bt_mesh_ext_net_reset_rpl(uint8_t index) +{ + memset(&bt_mesh.rpl[index], 0, sizeof(bt_mesh.rpl[index])); +} + +int bt_mesh_ext_net_is_ivu_initiator(void) +{ + return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR); +} + +int bt_mesh_ext_net_is_ivu_in_progress(void) +{ + return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); +} + +bool bt_mesh_ext_primary_subnet_exist(void) +{ + return bt_mesh_primary_subnet_exist(); +} + +/* Beacon */ +int bt_mesh_ext_net_secure_beacon_update(void *sub) +{ + return bt_mesh_net_secure_beacon_update(sub); +} + +uint8_t *bt_mesh_ext_net_get_sub_mpb_rand(uint8_t index) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return bt_mesh.sub[index].mpb_random; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void *bt_mesh_ext_beacon_cache_check(uint8_t data[21], bool private_beacon) +{ + extern struct bt_mesh_subnet *cache_check(uint8_t data[21], + bool private_beacon); + return cache_check(data, private_beacon); +} + +void bt_mesh_ext_beacon_cache_add(uint8_t data[21], void *sub, bool private_beacon) +{ + extern void cache_add(uint8_t data[21], + struct bt_mesh_subnet *sub, + bool private_beacon); + cache_add(data, sub, private_beacon); +} + +void bt_mesh_ext_beacon_update_observation(bool private_beacon) +{ + extern void update_beacon_observation(bool private_beacon); + update_beacon_observation(private_beacon); +} + +void bt_mesh_ext_beacon_ivu_initiator(bool enable) +{ + bt_mesh_beacon_ivu_initiator(enable); +} + +/* Foundation */ +uint8_t bt_mesh_ext_net_transmit_get(void) +{ + return bt_mesh_net_transmit_get(); +} + +uint8_t bt_mesh_ext_relay_get(void) +{ + return bt_mesh_relay_get(); +} + +uint8_t bt_mesh_ext_friend_get(void) +{ + return bt_mesh_friend_get(); +} + +uint8_t bt_mesh_ext_relay_retransmit_get(void) +{ + return bt_mesh_relay_retransmit_get(); +} + +uint8_t bt_mesh_ext_secure_beacon_get(void) +{ + return bt_mesh_secure_beacon_get(); +} + +uint8_t bt_mesh_ext_gatt_proxy_get(void) +{ + return bt_mesh_gatt_proxy_get(); +} + +uint8_t bt_mesh_ext_default_ttl_get(void) +{ + return bt_mesh_default_ttl_get(); +} + +void bt_mesh_ext_key_idx_pack(struct net_buf_simple *buf, + uint16_t idx1, uint16_t idx2) +{ + return key_idx_pack(buf, idx1, idx2); +} + +void bt_mesh_ext_key_idx_unpack(struct net_buf_simple *buf, + uint16_t *idx1, uint16_t *idx2) +{ + return key_idx_unpack(buf, idx1, idx2); +} + +/* Provisioning */ +const void *bt_mesh_ext_prov_get(void) +{ + return bt_mesh_prov_get(); +} + +uint8_t bt_mesh_ext_prov_buf_headroom(void) +{ + return PROV_BUF_HEADROOM; +} + +void bt_mesh_ext_prov_buf_init(struct net_buf_simple *buf, uint8_t type) +{ + bt_mesh_prov_buf_init(buf, type); +} + +bool bt_mesh_ext_prov_pdu_check(uint8_t type, uint16_t length, uint8_t *reason) +{ + return bt_mesh_prov_pdu_check(type, length, reason); +} + +int bt_mesh_ext_prov_send(void *link, struct net_buf_simple *buf) +{ + return bt_mesh_prov_send(link, buf); +} + +int bt_mesh_ext_prov_send_adv(void *link, struct net_buf_simple *msg) +{ + return bt_mesh_prov_send_adv(link, msg); +} + +int bt_mesh_ext_prov_bearer_ctl_send(void *link, uint8_t op, + void *data, uint8_t data_len) +{ + return bt_mesh_prov_bearer_ctl_send(link, op, data, data_len); +} + +void bt_mesh_ext_prov_clear_tx(void *link, bool cancel) +{ + bt_mesh_prov_clear_tx(link, cancel); +} + +uint8_t bt_mesh_ext_prov_node_next_xact_id(void *link) +{ +#if CONFIG_BLE_MESH_NODE + extern uint8_t node_next_xact_id(struct bt_mesh_prov_link *link); + return node_next_xact_id(link); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_NODE */ +} + +void *bt_mesh_ext_prov_node_get_link(void) +{ +#if CONFIG_BLE_MESH_NODE + extern struct bt_mesh_prov_link *bt_mesh_prov_node_get_link(void); + return bt_mesh_prov_node_get_link(); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_NODE */ +} + +void bt_mesh_ext_prov_node_close_link(uint8_t reason) +{ +#if CONFIG_BLE_MESH_NODE + extern void bt_mesh_prov_node_close_link(uint8_t reason); + return bt_mesh_prov_node_close_link(reason); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_NODE */ +} + +const uint8_t *bt_mesh_ext_prov_node_get_uuid(void) +{ +#if CONFIG_BLE_MESH_NODE + assert(bt_mesh_prov_get()); + return bt_mesh_prov_get()->uuid; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_NODE */ +} + +uint16_t bt_mesh_ext_prov_node_get_oob_info(void) +{ +#if CONFIG_BLE_MESH_NODE + assert(bt_mesh_prov_get()); + return bt_mesh_prov_get()->oob_info; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_NODE */ +} + +const char *bt_mesh_ext_prov_node_get_uri(void) +{ +#if CONFIG_BLE_MESH_NODE + assert(bt_mesh_prov_get()); + return bt_mesh_prov_get()->uri; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_NODE */ +} + +uint8_t bt_mesh_ext_prov_pvnr_next_xact_id(void *link) +{ +#if CONFIG_BLE_MESH_PB_ADV + extern uint8_t pvnr_next_xact_id(struct bt_mesh_prov_link *link); + return pvnr_next_xact_id(link); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PB_ADV */ +} + +void *bt_mesh_ext_prov_pvnr_get_link(void) +{ +#if CONFIG_BLE_MESH_PROVISIONER + extern struct bt_mesh_prov_link *bt_mesh_prov_pvnr_get_link(void); + return bt_mesh_prov_pvnr_get_link(); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +uint8_t bt_mesh_ext_prov_pvnr_get_link_count(void) +{ +#if CONFIG_BLE_MESH_PROVISIONER + extern uint8_t bt_mesh_prov_pvnr_get_link_count(void); + return bt_mesh_prov_pvnr_get_link_count(); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +void bt_mesh_ext_prov_pvnr_send_invite(void *link) +{ +#if CONFIG_BLE_MESH_PROVISIONER + extern void bt_mesh_prov_pvnr_send_invite(struct bt_mesh_prov_link *link); + bt_mesh_prov_pvnr_send_invite(link); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +void bt_mesh_ext_prov_pvnr_close_link(void *link, uint8_t reason) +{ +#if CONFIG_BLE_MESH_PROVISIONER + extern void bt_mesh_prov_pvnr_close_link(struct bt_mesh_prov_link *link, uint8_t reason); + bt_mesh_prov_pvnr_close_link(link, reason); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +void *bt_mesh_ext_pvnr_get_node_with_addr(uint16_t unicast_addr) +{ +#if CONFIG_BLE_MESH_PROVISIONER + return bt_mesh_provisioner_get_node_with_addr(unicast_addr); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +void bt_mesh_ext_pvnr_records_list_get_cb(uint16_t link_idx, struct net_buf_simple *data) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + assert(bt_mesh_prov_get()); + if (bt_mesh_prov_get()->records_list_get) { + bt_mesh_prov_get()->records_list_get(link_idx, data); + } +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +void bt_mesh_ext_pvnr_records_recv_comp_cb(uint8_t status, uint16_t link_idx, + uint16_t record_id, uint16_t frag_offset, + uint16_t total_len, uint8_t *record) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + assert(bt_mesh_prov_get()); + if (bt_mesh_prov_get()->prov_record_recv_comp) { + bt_mesh_prov_get()->prov_record_recv_comp(status, link_idx, record_id, + frag_offset, total_len, record); + } +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +uint8_t *bt_mesh_ext_pvnr_get_node_uuid(void *node) +{ +#if CONFIG_BLE_MESH_PROVISIONER + return NODE(node)->dev_uuid; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +int bt_mesh_ext_prov_link_test_bit(void *link, int bit) +{ + return bt_mesh_atomic_test_bit(LINK(link)->flags, bit); +} + +void bt_mesh_ext_prov_link_clear_bit(void *link, int bit) +{ + bt_mesh_atomic_clear_bit(LINK(link)->flags, bit); +} + +void bt_mesh_ext_prov_link_set_bit(void *link, int bit) +{ + bt_mesh_atomic_set_bit(LINK(link)->flags, bit); +} + +void bt_mesh_ext_prov_link_set_expect(void *link, uint8_t val) +{ + LINK(link)->expect = val; +} + +uint8_t bt_mesh_ext_prov_link_get_pub_key_type(void *link) +{ + return LINK(link)->public_key; +} + +uint8_t bt_mesh_ext_prov_link_get_auth_method(void *link) +{ + return LINK(link)->auth_method; +} + +void *bt_mesh_ext_prov_link_get_addr(void *link) +{ + return &LINK(link)->addr; +} + +uint8_t *bt_mesh_ext_prov_link_get_uuid(void *link) +{ +#if CONFIG_BLE_MESH_PROVISIONER + return LINK(link)->uuid; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +uint8_t bt_mesh_ext_prov_link_get_elem_num(void *link) +{ +#if CONFIG_BLE_MESH_PROVISIONER + return LINK(link)->element_num; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +uint16_t bt_mesh_ext_prov_link_get_unicast_addr(void *link) +{ +#if CONFIG_BLE_MESH_PROVISIONER + return LINK(link)->unicast_addr; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PROVISIONER */ +} + +uint16_t bt_mesh_ext_prov_link_get_record_id_expect(void *link) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + return LINK(link)->record_id_expect; +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +void bt_mesh_ext_prov_link_set_record_id_expect(void *link, uint16_t record_id_expect) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + LINK(link)->record_id_expect = record_id_expect; +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +uint16_t bt_mesh_ext_prov_link_get_offset_expect(void *link) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + return LINK(link)->offset_expect; +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +void bt_mesh_ext_prov_link_set_offset_expect(void *link, uint16_t offset_expect) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + LINK(link)->offset_expect = offset_expect; +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +uint16_t bt_mesh_ext_prov_link_get_max_size(void *link) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + return LINK(link)->max_size; +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +void bt_mesh_ext_prov_link_set_max_size(void *link, uint16_t max_size) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + LINK(link)->max_size = max_size; +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +void *bt_mesh_ext_prov_link_get_conn(void *link) +{ +#if CONFIG_BLE_MESH_PB_GATT + return LINK(link)->conn; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PB_GATT */ +} + +uint32_t *bt_mesh_ext_prov_link_get_link_id(void *link) +{ +#if CONFIG_BLE_MESH_PB_ADV + return &LINK(link)->link_id; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PB_ADV */ +} + +uint8_t *bt_mesh_ext_prov_link_get_pb_remote_uuid(void *link) +{ + return LINK(link)->pb_remote_uuid; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_timeout(void *link) +{ + return LINK(link)->pb_remote_timeout; +} + +void bt_mesh_ext_prov_link_set_pb_remote_timeout(void *link, uint8_t pb_remote_timeout) +{ + LINK(link)->pb_remote_timeout = pb_remote_timeout; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_nppi(void *link) +{ + return LINK(link)->pb_remote_nppi; +} + +void bt_mesh_ext_prov_link_set_pb_remote_nppi(void *link, uint8_t pb_remote_nppi) +{ + LINK(link)->pb_remote_nppi = pb_remote_nppi; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_pub_key(void *link) +{ + return LINK(link)->pb_remote_pub_key; +} + +void bt_mesh_ext_prov_link_set_pb_remote_pub_key(void *link, uint8_t pb_remote_pub_key) +{ + LINK(link)->pb_remote_pub_key = pb_remote_pub_key; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_cbd(void *link) +{ + return LINK(link)->pb_remote_cbd; +} + +void bt_mesh_ext_prov_link_set_pb_remote_cbd(void *link, uint8_t pb_remote_cbd) +{ + LINK(link)->pb_remote_cbd = pb_remote_cbd; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_csp(void *link) +{ + return LINK(link)->pb_remote_csp; +} + +void bt_mesh_ext_prov_link_set_pb_remote_csp(void *link, uint8_t pb_remote_csp) +{ + LINK(link)->pb_remote_csp = pb_remote_csp; +} + +uint8_t bt_mesh_ext_prov_link_get_pb_remote_reset(void *link) +{ + return LINK(link)->pb_remote_reset; +} + +void bt_mesh_ext_prov_link_set_pb_remote_reset(void *link, uint8_t pb_remote_reset) +{ + LINK(link)->pb_remote_reset = pb_remote_reset; +} + +void *bt_mesh_ext_prov_link_get_pb_remote_data(void *link) +{ + return LINK(link)->pb_remote_data; +} + +void bt_mesh_ext_prov_link_set_pb_remote_data(void *link, void *data) +{ + LINK(link)->pb_remote_data = data; +} + +void bt_mesh_ext_prov_link_free_pb_remote_data(void *link) +{ + assert(LINK(link)->pb_remote_data); + bt_mesh_free(LINK(link)->pb_remote_data); + LINK(link)->pb_remote_data = NULL; +} + +uint8_t *bt_mesh_ext_prov_link_get_record(void *link, uint16_t id) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + return LINK(link)->records[id]; +#else + assert(0); + return NULL; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +uint8_t *bt_mesh_ext_prov_link_alloc_record(void *link, uint16_t id, uint16_t len) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) + LINK(link)->records[id] = bt_mesh_calloc(len * sizeof(uint8_t)); + return LINK(link)->records[id]; +#else + assert(0); + return NULL; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_CERT_BASED_PROV) */ +} + +bool bt_mesh_ext_prov_link_pb_gatt_exist(void *link) +{ +#if CONFIG_BLE_MESH_PB_GATT + return !!LINK(link)->pb_gatt_send; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_PB_GATT */ +} + +int bt_mesh_ext_prov_link_pb_gatt_send(void *link, struct net_buf_simple *msg) +{ +#if CONFIG_BLE_MESH_PB_GATT + assert(LINK(link)->pb_gatt_send); + return LINK(link)->pb_gatt_send(link, msg); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PB_GATT */ +} + +void bt_mesh_ext_prov_link_set_pb_remote_close(void *link, void (*pb_remote_close)(void *link, uint8_t reason)) +{ + LINK(link)->pb_remote_close = VOID(pb_remote_close); +} + +void bt_mesh_ext_prov_link_pb_remote_close(void *link, uint8_t reason) +{ + if (LINK(link)->pb_remote_close) { + LINK(link)->pb_remote_close(link, reason); + } +} + +void bt_mesh_ext_prov_link_set_pb_remote_send(void *link, int (*pb_remote_send)(void *link, struct net_buf_simple *buf)) +{ + LINK(link)->pb_remote_send = VOID(pb_remote_send); +} + +void bt_mesh_ext_prov_link_set_next_xact_id(void *link, uint8_t (*next_xact_id)(void *link)) +{ +#if CONFIG_BLE_MESH_PB_ADV + LINK(link)->next_xact_id = VOID(next_xact_id); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PB_ADV */ +} + +/* Proxy Server */ +uint8_t bt_mesh_ext_proxy_server_get_all_client_type(void) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return bt_mesh_proxy_server_get_all_client_type(); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +int bt_mesh_ext_proxy_server_segment_send(void *conn, uint8_t type, + struct net_buf_simple *msg) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return bt_mesh_proxy_server_segment_send(conn, type, msg); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +bool bt_mesh_ext_proxy_server_find_client_by_addr(uint16_t addr) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return bt_mesh_proxy_server_find_client_by_addr(addr); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +void bt_mesh_ext_proxy_server_update_net_id_rand_stop(void) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) + bt_mesh_proxy_server_update_net_id_rand_stop(); +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) */ +} + +void *bt_mesh_ext_proxy_server_get_client(uint8_t index) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + extern struct bt_mesh_proxy_client *bt_mesh_proxy_server_get_client(uint8_t index); + return bt_mesh_proxy_server_get_client(index); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +uint8_t bt_mesh_ext_proxy_server_get_client_count(void) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + extern uint8_t bt_mesh_proxy_server_get_client_count(void); + return bt_mesh_proxy_server_get_client_count(); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +void bt_mesh_ext_proxy_server_update_net_id_rand(void) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) + bt_mesh_proxy_server_update_net_id_rand(); +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) */ +} + +bool bt_mesh_ext_proxy_server_is_node_id_enable(void) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) + return bt_mesh_proxy_server_is_node_id_enable(); +#else + assert(0); + return false; +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) */ +} + +void bt_mesh_ext_proxy_server_private_identity_start(void *sub) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) + bt_mesh_proxy_server_private_identity_start(sub); +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) */ +} + +void bt_mesh_ext_proxy_server_private_identity_stop(void *sub) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) + bt_mesh_proxy_server_private_identity_stop(sub); +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV) */ +} + +uint8_t bt_mesh_ext_proxy_server_get_filter_type(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->filter_type; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +uint8_t bt_mesh_ext_proxy_server_get_filter_count(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return ARRAY_SIZE(PROXY_CLI(client)->filter); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +uint16_t bt_mesh_ext_proxy_server_get_filter_size(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return sizeof(PROXY_CLI(client)->filter); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +uint16_t bt_mesh_ext_proxy_server_get_filter_addr(void *client, uint8_t index) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->filter[index].addr; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +bool bt_mesh_ext_proxy_server_filter_is_client(void *client, uint8_t index) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->filter[index].proxy_client; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +uint8_t bt_mesh_ext_proxy_server_get_client_type(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->proxy_client_type; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +bool bt_mesh_ext_proxy_server_is_proxy_msg_recv(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->proxy_msg_recv; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +void *bt_mesh_ext_proxy_server_get_conn(void *client) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + return PROXY_CLI(client)->conn; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +void bt_mesh_ext_proxy_server_set_client_type(void *client, uint8_t type) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + PROXY_CLI(client)->proxy_client_type = type; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +void bt_mesh_ext_proxy_server_set_msg_recv(void *client, uint8_t val) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER + PROXY_CLI(client)->proxy_msg_recv = !!val; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +/* Proxy Client */ +bool bt_mesh_ext_proxy_client_beacon_send(void *sub, bool private) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + return bt_mesh_proxy_client_beacon_send(sub, private); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +} + +uint8_t bt_mesh_ext_proxy_client_get_opcode(void *cfg) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + return PROXY_CFG(cfg)->opcode; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +} + +uint8_t bt_mesh_ext_proxy_client_get_use_directed(void *cfg) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + return PROXY_CFG(cfg)->direct_proxy_ctrl.use_directed; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +} + +void *bt_mesh_ext_proxy_client_get_client_uar(void *cfg) +{ +#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT + return &PROXY_CFG(cfg)->direct_proxy_ctrl.proxy_client_uar; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ +} + +/* Remote Provisioning */ +int bt_mesh_ext_rpr_cli_pdu_send(void *link, uint8_t type) +{ +#if CONFIG_BLE_MESH_RPR_CLI + return bt_mesh_rpr_cli_pdu_send(link, type); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +int bt_mesh_ext_rpr_cli_recv_pub_key_outbound_report(void *link) +{ +#if CONFIG_BLE_MESH_RPR_CLI + return bt_mesh_rpr_cli_recv_pub_key_outbound_report(link); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +int bt_mesh_ext_rpr_cli_pdu_recv(void *link, uint8_t type, struct net_buf_simple *buf) +{ +#if CONFIG_BLE_MESH_RPR_CLI + return bt_mesh_rpr_cli_pdu_recv(link, type, buf); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +#if CONFIG_BLE_MESH_RPR_CLI +static struct bt_mesh_prov_link rpr_links[CONFIG_BLE_MESH_RPR_CLI_PROV_SAME_TIME]; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ + +void *bt_mesh_ext_rpr_cli_get_rpr_link(uint8_t index) +{ +#if CONFIG_BLE_MESH_RPR_CLI + return &rpr_links[index]; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +void bt_mesh_ext_rpr_srv_reset_prov_link(void *link, uint8_t reason) +{ +#if CONFIG_BLE_MESH_RPR_SRV + bt_mesh_rpr_srv_reset_prov_link(link, reason); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +} + +int bt_mesh_ext_rpr_srv_nppi_pdu_recv(uint8_t type, const uint8_t *data) +{ +#if CONFIG_BLE_MESH_RPR_SRV + return bt_mesh_rpr_srv_nppi_pdu_recv(type, data); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +} + +int bt_mesh_ext_rpr_srv_set_waiting_prov_link(void* link, bt_mesh_addr_t *addr) +{ +#if (CONFIG_BLE_MESH_GATT_PROXY_CLIENT && \ + CONFIG_BLE_MESH_PB_GATT && \ + CONFIG_BLE_MESH_RPR_SRV) + return bt_mesh_rpr_srv_set_waiting_prov_link(link, addr); +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_GATT_PROXY_CLIENT && \ + CONFIG_BLE_MESH_PB_GATT && \ + CONFIG_BLE_MESH_RPR_SRV) */ +} + +/* Friend */ +uint16_t bt_mesh_ext_frnd_get_lpn(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->lpn; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint8_t bt_mesh_ext_frnd_get_num_elem(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->num_elem; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +bool bt_mesh_ext_frnd_is_valid(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->valid; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +bool bt_mesh_ext_frnd_is_established(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->established; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint16_t bt_mesh_ext_frnd_get_net_idx(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->net_idx; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint8_t bt_mesh_ext_frnd_get_sub_list_count(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return ARRAY_SIZE(FRIEND(frnd)->sub_list); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint16_t bt_mesh_ext_frnd_get_sub_list_size(void *frnd) +{ +#if CONFIG_BLE_MESH_FRIEND + return sizeof(FRIEND(frnd)->sub_list); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint16_t bt_mesh_ext_frnd_get_sub_addr(void *frnd, uint8_t index) +{ +#if CONFIG_BLE_MESH_FRIEND + return FRIEND(frnd)->sub_list[index]; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +uint8_t bt_mesh_ext_net_get_frnd_count(void) +{ +#if CONFIG_BLE_MESH_FRIEND + return ARRAY_SIZE(bt_mesh.frnd); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +void *bt_mesh_ext_net_get_frnd(uint8_t index) +{ +#if CONFIG_BLE_MESH_FRIEND + return &bt_mesh.frnd[index]; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +bool bt_mesh_ext_friend_match(uint16_t net_idx, uint16_t addr) +{ +#if CONFIG_BLE_MESH_FRIEND + return bt_mesh_friend_match(net_idx, addr); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +bool bt_mesh_ext_friend_unicast_match(uint16_t net_idx, uint16_t addr, uint8_t *selem) +{ +#if CONFIG_BLE_MESH_FRIEND + return bt_mesh_friend_unicast_match(net_idx, addr, selem); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +void *bt_mesh_ext_friend_find(uint16_t net_idx, uint16_t lpn_addr, bool valid, bool established) +{ +#if CONFIG_BLE_MESH_FRIEND + return bt_mesh_friend_find(net_idx, lpn_addr, valid, established); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +void bt_mesh_ext_friend_clear_net_idx(uint16_t net_idx) +{ +#if CONFIG_BLE_MESH_FRIEND + bt_mesh_friend_clear_net_idx(net_idx); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_FRIEND */ +} + +/* Low Power */ +bool bt_mesh_ext_lpn_match(uint16_t addr) +{ +#if CONFIG_BLE_MESH_LOW_POWER + return bt_mesh_lpn_match(addr); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ +} + +/* Adv */ +uint8_t bt_mesh_ext_adv_data_get_type(const void *ad) +{ + return ADV_DATA(ad)->type; +} + +const uint8_t *bt_mesh_ext_adv_data_get_data(const void *ad) +{ + return ADV_DATA(ad)->data; +} + +void bt_mesh_ext_adv_update(void) +{ + bt_mesh_adv_update(); +} + +void *bt_mesh_ext_adv_create(enum bt_mesh_adv_type type, int32_t timeout) +{ + return bt_mesh_adv_create(type, timeout); +} + +void bt_mesh_ext_adv_send(void *buf, uint8_t xmit, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + bt_mesh_adv_send(buf, xmit, cb, cb_data); +} + +uint8_t bt_mesh_ext_set_random_addr(uint8_t random_bda[6]) +{ +#if CONFIG_BT_BLUEDROID_ENABLED + extern tBTM_STATUS btm_ble_set_random_addr(BD_ADDR random_bda); + return btm_ble_set_random_addr(random_bda); +#else + return 0; +#endif +} + +void bt_mesh_ext_set_static_addr(uint8_t rand_addr[6]) +{ +#if CONFIG_BT_BLUEDROID_ENABLED + extern void BTM_BleSetStaticAddr(BD_ADDR rand_addr); + BTM_BleSetStaticAddr(rand_addr); +#else +#endif +} + +const char *bt_mesh_ext_get_device_name(void) +{ +#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER + return bt_mesh_get_device_name(); +#else + assert(0); + return NULL; +#endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER */ +} + +/* SCAN */ +int bt_mesh_ext_update_exceptional_list(uint8_t sub_code, uint32_t type, void *info) +{ +#if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN + return bt_mesh_update_exceptional_list(sub_code, type, info); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ +} + +int bt_mesh_ext_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], + uint8_t *adv_type, uint8_t query_type) +{ +#if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) + return bt_mesh_unprov_dev_info_query(uuid, addr, adv_type, query_type); +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ +} + +/* GATT */ +int bt_mesh_ext_gattc_conn_create(const void *addr, uint16_t service_uuid) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + return bt_mesh_gattc_conn_create(addr, service_uuid); +#else + assert(0); + return 0; +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ +} + +void bt_mesh_ext_gattc_disconnect(void *conn) +{ +#if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + bt_mesh_gattc_disconnect(conn); +#else + assert(0); +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ +} + +/* Settings */ +void bt_mesh_ext_store_dkca(void) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_store_dkca(); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +void bt_mesh_ext_clear_dkca(void) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_clear_dkca(); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +void bt_mesh_ext_clear_rpl_single(uint16_t src) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_clear_rpl_single(src); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +void bt_mesh_ext_store_net(void) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_store_net(); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +void bt_mesh_ext_store_seq(void) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_store_seq(); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +struct net_buf_simple *bt_mesh_ext_get_core_settings_item(const char *key) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_get_core_settings_item(key); +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +bool bt_mesh_ext_is_settings_item_exist(struct net_buf_simple *buf, const uint16_t val) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_is_settings_item_exist(buf, val); +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +int bt_mesh_ext_add_core_settings_item(const char *key, const uint16_t val) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_add_core_settings_item(key, val); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +int bt_mesh_ext_remove_core_settings_item(const char *key, const uint16_t val) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_remove_core_settings_item(key, val); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +int bt_mesh_ext_save_core_settings(const char *key, const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_save_core_settings(key, val, len); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +int bt_mesh_ext_erase_core_settings(const char *key) +{ +#if CONFIG_BLE_MESH_SETTINGS + return bt_mesh_erase_core_settings(key); +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_SETTINGS */ +} + +/* struct bt_mesh_subnet */ +uint32_t bt_mesh_ext_sub_get_mpb_sent(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_sent; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_set_mpb_sent(void *sub, uint32_t mpb_sent) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_sent = mpb_sent; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t bt_mesh_ext_sub_get_mpb_last(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_last; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_set_mpb_last(void *sub, uint8_t mpb_last) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_last = mpb_last; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t bt_mesh_ext_sub_get_mpb_cur(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_cur; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_set_mpb_cur(void *sub, uint8_t mpb_cur) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_cur = mpb_cur; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_inc_mpb_cur(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_cur++; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t bt_mesh_ext_sub_get_mpb_flags_last(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_flags_last; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_set_mpb_flags_last(void *sub, uint8_t mpb_flags_last) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_flags_last = mpb_flags_last; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t bt_mesh_ext_sub_get_mpb_ivi_last(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_ivi_last; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +void bt_mesh_ext_sub_set_mpb_ivi_last(void *sub, uint8_t mpb_ivi_last) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + SUBNET(sub)->mpb_ivi_last = !!mpb_ivi_last; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t *bt_mesh_ext_sub_get_mpb_random(void *sub) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->mpb_random; +#else + assert(0); + return NULL; +#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 + return SUBNET(sub)->private_node_id; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint16_t bt_mesh_ext_sub_get_net_idx(void *sub) +{ + return SUBNET(sub)->net_idx; +} + +uint16_t bt_mesh_ext_sub_get_sbr_net_idx(void *sub) +{ +#if CONFIG_BLE_MESH_BRC_SRV + return SUBNET(sub)->sbr_net_idx; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +} + +void bt_mesh_ext_sub_set_sbr_net_idx(void *sub, uint16_t sbr_net_idx) +{ +#if CONFIG_BLE_MESH_BRC_SRV + SUBNET(sub)->sbr_net_idx = sbr_net_idx; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +} + +bool bt_mesh_ext_sub_get_kr_flag(void *sub) +{ + return SUBNET(sub)->kr_flag; +} + +uint8_t bt_mesh_ext_sub_get_kr_phase(void *sub) +{ + return SUBNET(sub)->kr_phase; +} + +uint8_t *bt_mesh_ext_sub_get_keys_net(void *sub, uint8_t index) +{ + return SUBNET(sub)->keys[index].net; +} + +uint8_t bt_mesh_ext_sub_get_keys_nid(void *sub, uint8_t index) +{ + return SUBNET(sub)->keys[index].nid; +} + +uint8_t *bt_mesh_ext_sub_get_keys_enc(void *sub, uint8_t index) +{ + return SUBNET(sub)->keys[index].enc; +} + +uint8_t *bt_mesh_ext_sub_get_keys_privacy(void *sub, uint8_t index) +{ + return SUBNET(sub)->keys[index].privacy; +} + +uint8_t *bt_mesh_ext_sub_get_keys_private_beacon(void *sub, uint8_t index) +{ +#if CONFIG_BLE_MESH_PRIVATE_BEACON + return SUBNET(sub)->keys[index].private_beacon; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ +} + +uint8_t bt_mesh_ext_sub_get_keys_direct_nid(void *sub, uint8_t index) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->keys[index].direct_nid; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t *bt_mesh_ext_sub_get_keys_direct_enc(void *sub, uint8_t index) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->keys[index].direct_enc; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t *bt_mesh_ext_sub_get_keys_direct_privacy(void *sub, uint8_t index) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->keys[index].direct_privacy; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_proxy_privacy(void *sub) +{ + return SUBNET(sub)->proxy_privacy; +} + +void bt_mesh_ext_sub_set_proxy_privacy(void *sub, uint8_t proxy_privacy) +{ + SUBNET(sub)->proxy_privacy = proxy_privacy; +} + +uint8_t bt_mesh_ext_sub_get_directed_forwarding(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->directed_forwarding; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_directed_forwarding(void *sub, uint8_t directed_forwarding) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->directed_forwarding = directed_forwarding; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_directed_relay(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->directed_relay; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_directed_relay(void *sub, uint8_t directed_relay) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->directed_relay = directed_relay; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_directed_proxy(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->directed_proxy; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_directed_proxy(void *sub, uint8_t directed_proxy) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->directed_proxy = directed_proxy; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_directed_proxy_use_default(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->directed_proxy_use_default; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_directed_proxy_use_default(void *sub, uint8_t directed_proxy_use_default) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->directed_proxy_use_default = directed_proxy_use_default; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_directed_friend(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->directed_friend; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_directed_friend(void *sub, uint8_t directed_friend) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->directed_friend = directed_friend; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_use_directed(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->use_directed; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_use_directed(void *sub, uint8_t use_directed) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->use_directed = use_directed; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_sub_get_proxy_client_uar(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return &SUBNET(sub)->proxy_client_uar; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +bool bt_mesh_ext_sub_get_proxy_client_uar_len_present(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->proxy_client_uar.len_present; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_proxy_client_uar_len_present(void *sub, bool len_present) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->proxy_client_uar.len_present = len_present; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint16_t bt_mesh_ext_sub_get_proxy_client_uar_range_start(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->proxy_client_uar.range_start; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_proxy_client_uar_range_start(void *sub, uint16_t range_start) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->proxy_client_uar.range_start = range_start; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_proxy_client_uar_range_length(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->proxy_client_uar.range_length; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_proxy_client_uar_range_length(void *sub, uint8_t range_length) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->proxy_client_uar.range_length = range_length; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_path_metric_type(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->path_metric_type; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_path_metric_type(void *sub, uint8_t path_metric_type) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->path_metric_type = path_metric_type; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_path_lifetime_type(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->path_lifetime_type; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_path_lifetime_type(void *sub, uint8_t path_lifetime_type) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->path_lifetime_type = path_lifetime_type; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +bool bt_mesh_ext_sub_get_two_way_path(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->two_way_path; +#else + assert(0); + return false; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_two_way_path(void *sub, bool two_way_path) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->two_way_path = two_way_path; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_forward_number(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->forward_number; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_forward_number(void *sub, uint8_t forward_number) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->forward_number = forward_number; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_disc_table_max_disc_entries(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->discovery_table.max_disc_entries; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_disc_table_max_disc_entries(void *sub, uint8_t max_disc_entries) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->discovery_table.max_disc_entries = max_disc_entries; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_disc_table_max_concurr_init(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->discovery_table.max_concurr_init; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_disc_table_max_concurr_init(void *sub, uint8_t max_concurr_init) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->discovery_table.max_concurr_init = max_concurr_init; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_disc_table_concurr_init(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->discovery_table.concurr_init; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_disc_table_concurr_init(void *sub, uint8_t concurr_init) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->discovery_table.concurr_init = concurr_init; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_inc_disc_table_concurr_init(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->discovery_table.concurr_init++; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_dec_disc_table_concurr_init(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->discovery_table.concurr_init--; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_sub_get_disc_table_mutex(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return &SUBNET(sub)->discovery_table.mutex; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_sub_get_disc_table_entries(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return &SUBNET(sub)->discovery_table.entries; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_fwd_table_max_ford_entries(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->forward_table.max_ford_entries; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_fwd_table_max_ford_entries(void *sub, uint8_t max_ford_entries) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->forward_table.max_ford_entries = max_ford_entries; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_fwd_table_max_deps_nodes(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->forward_table.max_deps_nodes; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_fwd_table_max_deps_nodes(void *sub, uint8_t max_deps_nodes) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->forward_table.max_deps_nodes = max_deps_nodes; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint16_t bt_mesh_ext_sub_get_fwd_table_update_id(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->forward_table.update_id; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_fwd_table_update_id(void *sub, uint16_t update_id) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->forward_table.update_id = update_id; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_inc_fwd_table_update_id(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->forward_table.update_id++; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_sub_get_fwd_table_mutex(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return &SUBNET(sub)->forward_table.mutex; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void *bt_mesh_ext_sub_get_fwd_table_entries(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return &SUBNET(sub)->forward_table.entries; +#else + assert(0); + return NULL; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_wanted_lanes(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->wanted_lanes; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_wanted_lanes(void *sub, uint8_t wanted_lanes) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->wanted_lanes = wanted_lanes; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_unicast_echo_interval(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->unicast_echo_interval; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_unicast_echo_interval(void *sub, uint8_t unicast_echo_interval) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->unicast_echo_interval = unicast_echo_interval; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +uint8_t bt_mesh_ext_sub_get_multicast_echo_interval(void *sub) +{ +#if CONFIG_BLE_MESH_DF_SRV + return SUBNET(sub)->multicast_echo_interval; +#else + assert(0); + return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_sub_set_multicast_echo_interval(void *sub, uint8_t multicast_echo_interval) +{ +#if CONFIG_BLE_MESH_DF_SRV + SUBNET(sub)->multicast_echo_interval = multicast_echo_interval; +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +/* struct bt_mesh_net_tx */ +void *bt_mesh_ext_net_tx_get_sub(void *tx) +{ + return NET_TX(tx)->sub; +} + +void bt_mesh_ext_net_tx_set_sub(void *tx, void *sub) +{ + NET_TX(tx)->sub = sub; +} + +void bt_mesh_ext_net_tx_set_ctx(void *tx, void *ctx) +{ + NET_TX(tx)->ctx = ctx; +} + +uint16_t bt_mesh_ext_net_tx_get_net_idx(void *tx) +{ + return NET_TX(tx)->ctx->net_idx; +} + +uint16_t bt_mesh_ext_net_tx_get_app_idx(void *tx) +{ + return NET_TX(tx)->ctx->app_idx; +} + +uint16_t bt_mesh_ext_net_tx_get_addr(void *tx) +{ + return NET_TX(tx)->ctx->addr; +} + +uint8_t bt_mesh_ext_net_tx_get_send_ttl(void *tx) +{ + return NET_TX(tx)->ctx->send_ttl; +} + +uint8_t bt_mesh_ext_net_tx_get_send_cred(void *tx) +{ + return NET_TX(tx)->ctx->send_cred; +} + +void bt_mesh_ext_net_tx_set_send_cred(void *tx, uint8_t send_cred) +{ + NET_TX(tx)->ctx->send_cred = send_cred; +} + +uint8_t bt_mesh_ext_net_tx_get_send_tag(void *tx) +{ + return NET_TX(tx)->ctx->send_tag; +} + +void bt_mesh_ext_net_tx_set_send_tag(void *tx, uint8_t tag) +{ + NET_TX(tx)->ctx->send_tag = tag; +} + +uint16_t bt_mesh_ext_net_tx_get_src(void *tx) +{ + return NET_TX(tx)->src; +} + +void bt_mesh_ext_net_tx_set_src(void *tx, uint16_t src) +{ + NET_TX(tx)->src = src; +} + +void bt_mesh_ext_net_tx_set_xmit(void *tx, uint8_t xmit) +{ + NET_TX(tx)->xmit = xmit; +} + +/* struct bt_mesh_net_rx */ +void *bt_mesh_ext_net_rx_get_sub(void *rx) +{ + return NET_RX(rx)->sub; +} + +void bt_mesh_ext_net_rx_set_sub(void *rx, void *sub) +{ + NET_RX(rx)->sub = sub; +} + +uint16_t bt_mesh_ext_net_rx_get_net_idx(void *rx) +{ + return NET_RX(rx)->ctx.net_idx; +} + +void bt_mesh_ext_net_rx_set_net_idx(void *rx, uint16_t net_idx) +{ + NET_RX(rx)->ctx.net_idx = net_idx; +} + +uint16_t bt_mesh_ext_net_rx_get_app_idx(void *rx) +{ + return NET_RX(rx)->ctx.app_idx; +} + +void bt_mesh_ext_net_rx_set_app_idx(void *rx, uint16_t app_idx) +{ + NET_RX(rx)->ctx.app_idx = app_idx; +} + +uint16_t bt_mesh_ext_net_rx_get_addr(void *rx) +{ + return NET_RX(rx)->ctx.addr; +} + +void bt_mesh_ext_net_rx_set_addr(void *rx, uint16_t addr) +{ + NET_RX(rx)->ctx.addr = addr; +} + +uint16_t bt_mesh_ext_net_rx_get_recv_dst(void *rx) +{ + return NET_RX(rx)->ctx.recv_dst; +} + +void bt_mesh_ext_net_rx_set_recv_dst(void *rx, uint16_t recv_dst) +{ + NET_RX(rx)->ctx.recv_dst = recv_dst; +} + +int8_t bt_mesh_ext_net_rx_get_recv_rssi(void *rx) +{ + return NET_RX(rx)->ctx.recv_rssi; +} + +void bt_mesh_ext_net_rx_set_recv_rssi(void *rx, int8_t recv_rssi) +{ + NET_RX(rx)->ctx.recv_rssi = recv_rssi; +} + +uint32_t bt_mesh_ext_net_rx_get_recv_op(void *rx) +{ + return NET_RX(rx)->ctx.recv_op; +} + +void bt_mesh_ext_net_rx_set_recv_op(void *rx, uint32_t recv_op) +{ + NET_RX(rx)->ctx.recv_op = recv_op; +} + +uint8_t bt_mesh_ext_net_rx_get_recv_ttl(void *rx) +{ + return NET_RX(rx)->ctx.recv_ttl; +} + +void bt_mesh_ext_net_rx_set_recv_ttl(void *rx, uint8_t recv_ttl) +{ + NET_RX(rx)->ctx.recv_ttl = recv_ttl; +} + +uint8_t bt_mesh_ext_net_rx_get_recv_cred(void *rx) +{ + return NET_RX(rx)->ctx.recv_cred; +} + +void bt_mesh_ext_net_rx_set_recv_cred(void *rx, uint8_t recv_cred) +{ + NET_RX(rx)->ctx.recv_cred = recv_cred; +} + +uint8_t bt_mesh_ext_net_rx_get_recv_tag(void *rx) +{ + return NET_RX(rx)->ctx.recv_tag; +} + +void bt_mesh_ext_net_rx_set_recv_tag(void *rx, uint8_t recv_tag) +{ + NET_RX(rx)->ctx.recv_tag = recv_tag; +} + +uint8_t bt_mesh_ext_net_rx_get_send_ttl(void *rx) +{ + return NET_RX(rx)->ctx.send_ttl; +} + +void bt_mesh_ext_net_rx_set_send_ttl(void *rx, uint8_t send_ttl) +{ + NET_RX(rx)->ctx.send_ttl = send_ttl; +} + +uint8_t bt_mesh_ext_net_rx_get_send_cred(void *rx) +{ + return NET_RX(rx)->ctx.send_cred; +} + +void bt_mesh_ext_net_rx_set_send_cred(void *rx, uint8_t send_cred) +{ + NET_RX(rx)->ctx.send_cred = send_cred; +} + +uint8_t bt_mesh_ext_net_rx_get_send_tag(void *rx) +{ + return NET_RX(rx)->ctx.send_tag; +} + +void bt_mesh_ext_net_rx_set_send_tag(void *rx, uint8_t send_tag) +{ + NET_RX(rx)->ctx.send_tag = send_tag; +} + +uint32_t bt_mesh_ext_net_rx_get_seq(void *rx) +{ + return NET_RX(rx)->seq; +} + +void bt_mesh_ext_net_rx_set_seq(void *rx, uint32_t seq) +{ + NET_RX(rx)->seq = seq; +} + +bool bt_mesh_ext_net_rx_get_new_key(void *rx) +{ + return NET_RX(rx)->new_key; +} + +void bt_mesh_ext_net_rx_set_new_key(void *rx, bool new_key) +{ + NET_RX(rx)->new_key = new_key; +} + +bool bt_mesh_ext_net_rx_get_ctl(void *rx) +{ + return NET_RX(rx)->ctl; +} + +void bt_mesh_ext_net_rx_set_ctl(void *rx, bool ctl) +{ + NET_RX(rx)->ctl = ctl; +} + +uint8_t bt_mesh_ext_net_rx_get_net_if(void *rx) +{ + return NET_RX(rx)->net_if; +} + +void bt_mesh_ext_net_rx_set_net_if(void *rx, uint8_t net_if) +{ + NET_RX(rx)->net_if = net_if; +} + +/* struct bt_mesh_msg_ctx */ +uint16_t bt_mesh_ext_msg_ctx_get_net_idx(void *ctx) +{ + return MSG_CTX(ctx)->net_idx; +} + +void bt_mesh_ext_msg_ctx_set_net_idx(void *ctx, uint16_t net_idx) +{ + MSG_CTX(ctx)->net_idx = net_idx; +} + +uint16_t bt_mesh_ext_msg_ctx_get_app_idx(void *ctx) +{ + return MSG_CTX(ctx)->app_idx; +} + +void bt_mesh_ext_msg_ctx_set_app_idx(void *ctx, uint16_t app_idx) +{ + MSG_CTX(ctx)->app_idx = app_idx; +} + +uint16_t bt_mesh_ext_msg_ctx_get_addr(void *ctx) +{ + return MSG_CTX(ctx)->addr; +} + +void bt_mesh_ext_msg_ctx_set_addr(void *ctx, uint16_t addr) +{ + MSG_CTX(ctx)->addr = addr; +} + +uint16_t bt_mesh_ext_msg_ctx_get_recv_dst(void *ctx) +{ + return MSG_CTX(ctx)->recv_dst; +} + +void bt_mesh_ext_msg_ctx_set_recv_dst(void *ctx, uint16_t recv_dst) +{ + MSG_CTX(ctx)->recv_dst = recv_dst; +} + +int8_t bt_mesh_ext_msg_ctx_get_recv_rssi(void *ctx) +{ + return MSG_CTX(ctx)->recv_rssi; +} + +void bt_mesh_ext_msg_ctx_set_recv_rssi(void *ctx, int8_t recv_rssi) +{ + MSG_CTX(ctx)->recv_rssi = recv_rssi; +} + +uint32_t bt_mesh_ext_msg_ctx_get_recv_op(void *ctx) +{ + return MSG_CTX(ctx)->recv_op; +} + +void bt_mesh_ext_msg_ctx_set_recv_op(void *ctx, uint32_t recv_op) +{ + MSG_CTX(ctx)->recv_op = recv_op; +} + +uint8_t bt_mesh_ext_msg_ctx_get_recv_ttl(void *ctx) +{ + return MSG_CTX(ctx)->recv_ttl; +} + +void bt_mesh_ext_msg_ctx_set_recv_ttl(void *ctx, uint8_t recv_ttl) +{ + MSG_CTX(ctx)->recv_ttl = recv_ttl; +} + +uint8_t bt_mesh_ext_msg_ctx_get_recv_cred(void *ctx) +{ + return MSG_CTX(ctx)->recv_cred; +} + +void bt_mesh_ext_msg_ctx_set_recv_cred(void *ctx, uint8_t recv_cred) +{ + MSG_CTX(ctx)->recv_cred = recv_cred; +} + +uint8_t bt_mesh_ext_msg_ctx_get_recv_tag(void *ctx) +{ + return MSG_CTX(ctx)->recv_tag; +} + +void bt_mesh_ext_msg_ctx_set_recv_tag(void *ctx, uint8_t recv_tag) +{ + MSG_CTX(ctx)->recv_tag = recv_tag; +} + +uint8_t bt_mesh_ext_msg_ctx_get_send_szmic(void *ctx) +{ + return MSG_CTX(ctx)->send_szmic; +} + +void bt_mesh_ext_msg_ctx_set_send_szmic(void *ctx, uint8_t send_szmic) +{ + MSG_CTX(ctx)->send_szmic = send_szmic; +} + +uint8_t bt_mesh_ext_msg_ctx_get_send_ttl(void *ctx) +{ + return MSG_CTX(ctx)->send_ttl; +} + +void bt_mesh_ext_msg_ctx_set_send_ttl(void *ctx, uint8_t send_ttl) +{ + MSG_CTX(ctx)->send_ttl = send_ttl; +} + +uint8_t bt_mesh_ext_msg_ctx_get_send_cred(void *ctx) +{ + return MSG_CTX(ctx)->send_cred; +} + +void bt_mesh_ext_msg_ctx_set_send_cred(void *ctx, uint8_t send_cred) +{ + MSG_CTX(ctx)->send_cred = send_cred; +} + +uint8_t bt_mesh_ext_msg_ctx_get_send_tag(void *ctx) +{ + return MSG_CTX(ctx)->send_tag; +} + +void bt_mesh_ext_msg_ctx_set_send_tag(void *ctx, uint8_t send_tag) +{ + MSG_CTX(ctx)->send_tag = send_tag; +} + +/* Client */ +int bt_mesh_ext_client_clear_list(void *data) +{ + return bt_mesh_client_clear_list(data); +} + +int bt_mesh_ext_client_free_node(void *node) +{ + return bt_mesh_client_free_node(node); +} + +uint32_t bt_mesh_ext_client_common_get_opcode(void *param) +{ + return CLI_PARAM(param)->opcode; +} + +void *bt_mesh_ext_client_common_get_model(void *param) +{ + return CLI_PARAM(param)->model; +} + +void bt_mesh_ext_client_common_set_opcode(void *param, uint32_t opcode) +{ + CLI_PARAM(param)->opcode = opcode; +} + +void bt_mesh_ext_client_common_set_model(void *param, void *model) +{ + CLI_PARAM(param)->model = model; +} + +void *bt_mesh_ext_client_common_get_ctx(void *param) +{ + return &CLI_PARAM(param)->ctx; +} + +uint16_t bt_mesh_ext_client_common_get_net_idx(void *param) +{ + return CLI_PARAM(param)->ctx.net_idx; +} + +void bt_mesh_ext_client_common_set_net_idx(void *param, uint16_t net_idx) +{ + CLI_PARAM(param)->ctx.net_idx = net_idx; +} + +uint16_t bt_mesh_ext_client_common_get_app_idx(void *param) +{ + return CLI_PARAM(param)->ctx.app_idx; +} + +void bt_mesh_ext_client_common_set_app_idx(void *param, uint16_t app_idx) +{ + CLI_PARAM(param)->ctx.app_idx = app_idx; +} + +uint16_t bt_mesh_ext_client_common_get_addr(void *param) +{ + return CLI_PARAM(param)->ctx.addr; +} + +void bt_mesh_ext_client_common_set_addr(void *param, uint16_t addr) +{ + CLI_PARAM(param)->ctx.addr = addr; +} + +uint8_t bt_mesh_ext_client_common_get_send_ttl(void *param) +{ + return CLI_PARAM(param)->ctx.send_ttl; +} + +void bt_mesh_ext_client_common_set_send_ttl(void *param, uint8_t send_ttl) +{ + CLI_PARAM(param)->ctx.send_ttl = send_ttl; +} + +void bt_mesh_ext_client_common_set_cb(void *param, void *cb) +{ + CLI_PARAM(param)->cb = cb; +} + +void bt_mesh_ext_client_common_set_cb_data(void *param, void *cb_data) +{ + CLI_PARAM(param)->cb_data = cb_data; +} + +void *bt_mesh_ext_client_node_get_with_work(void *work) +{ + return CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); +} + +uint32_t bt_mesh_ext_client_node_get_opcode(void *node) +{ + return CLI_NODE(node)->opcode; +} + +void *bt_mesh_ext_client_node_get_model(void *node) +{ + return CLI_NODE(node)->model; +} + +void *bt_mesh_ext_client_node_get_timer(void *node) +{ + return &CLI_NODE(node)->timer; +} + +void *bt_mesh_ext_client_node_get_ctx(void *node) +{ + return &CLI_NODE(node)->ctx; +} + +void *bt_mesh_ext_is_client_recv_publish_msg(void *model, void *ctx, + struct net_buf_simple *buf, + bool need_pub) +{ + return bt_mesh_is_client_recv_publish_msg(model, ctx, buf, need_pub); +} + +int bt_mesh_ext_client_send_msg(void *param, struct net_buf_simple *msg, + bool need_ack, void (*timeout_cb)(void *work)) +{ + 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; + uint8_t bridge_net_idx[3]; + uint16_t bridge_addr_1; + uint16_t bridge_addr_2; +}; + +struct bt_mesh_bridge_cfg_srv { + struct bt_mesh_model *model; + + uint8_t subnet_bridge; + uint16_t bridging_table_size; + struct bt_mesh_subnet_bridge_table bridge_table[CONFIG_BLE_MESH_MAX_BRIDGING_TABLE_ENTRY_COUNT]; +}; +#endif /* CONFIG_BLE_MESH_BRC_SRV */ + +void *bt_mesh_ext_brc_srv_get_bridge_table_entry(void *srv, uint8_t index) +{ +#if CONFIG_BLE_MESH_BRC_SRV + return &((struct bt_mesh_bridge_cfg_srv *)srv)->bridge_table[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, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_AGG_CLI + bt_mesh_agg_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_AGG_CLI */ +} + +void bt_mesh_ext_agg_server_cb_evt_to_btc(uint8_t event, void *model, void *ctx, + const void *val, size_t len) +{ +#if CONFIG_BLE_MESH_AGG_SRV + bt_mesh_agg_server_cb_evt_to_btc(event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_AGG_SRV */ +} + +void bt_mesh_ext_brc_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_BRC_CLI + bt_mesh_brc_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_BRC_CLI */ +} + +void bt_mesh_ext_brc_server_cb_evt_to_btc(uint8_t event, void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_BRC_SRV + bt_mesh_brc_server_cb_evt_to_btc(event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_BRC_SRV */ +} + +void bt_mesh_ext_df_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_DF_CLI + bt_mesh_df_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_CLI */ +} + +void bt_mesh_ext_df_server_cb_evt_to_btc(uint8_t event, void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_DF_SRV + bt_mesh_df_server_cb_evt_to_btc(event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_DF_SRV */ +} + +void bt_mesh_ext_lcd_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const void *val, size_t len) +{ +#if CONFIG_BLE_MESH_LCD_CLI + bt_mesh_lcd_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_LCD_CLI */ +} + +void bt_mesh_ext_odp_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_ODP_CLI + bt_mesh_odp_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_ODP_CLI */ +} + +void bt_mesh_ext_prb_client_cb_evt_to_btc(uint32_t opcode, uint8_t evt_type, + void *model, void *ctx, + const uint8_t *val, uint16_t len) +{ +#if CONFIG_BLE_MESH_PRB_CLI + bt_mesh_prb_client_cb_evt_to_btc(opcode, evt_type, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_PRB_CLI */ +} + +void btc_ble_mesh_ext_rpr_client_link_close_cb(void *model, uint16_t rpr_srv_addr, uint8_t reason) +{ +#if CONFIG_BLE_MESH_RPR_CLI + btc_ble_mesh_rpr_client_link_close_cb(model, rpr_srv_addr, reason); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +void btc_ble_mesh_ext_rpr_client_prov_comp_cb(void *model, uint16_t rpr_srv_addr, + uint8_t nppi, uint16_t index, + uint8_t uuid[16], uint16_t unicast_addr, + uint8_t element_num, uint16_t net_idx) +{ +#if CONFIG_BLE_MESH_RPR_CLI + btc_ble_mesh_rpr_client_prov_comp_cb(model, rpr_srv_addr, nppi, index, uuid, + unicast_addr, element_num, net_idx); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +void bt_mesh_ext_rpr_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const void *val, size_t len) +{ +#if CONFIG_BLE_MESH_RPR_CLI + bt_mesh_rpr_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +} + +void bt_mesh_ext_rpr_server_cb_evt_to_btc(uint8_t event, const void *val, size_t len) +{ +#if CONFIG_BLE_MESH_RPR_SRV + bt_mesh_rpr_server_cb_evt_to_btc(event, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +} + +void bt_mesh_ext_sar_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_SAR_CLI + bt_mesh_sar_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SAR_CLI */ +} + +void bt_mesh_ext_srpl_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len) +{ +#if CONFIG_BLE_MESH_SRPL_CLI + bt_mesh_srpl_client_cb_evt_to_btc(opcode, event, model, ctx, val, len); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_SRPL_CLI */ +} + +void bt_mesh_ext_mbt_client_cb_evt_to_btc(uint8_t event, uint8_t result, void *model) +{ +#if CONFIG_BLE_MESH_MBT_CLI + bt_mesh_mbt_client_cb_evt_to_btc(event, result, model); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_MBT_CLI */ +} + +void bt_mesh_ext_mbt_server_cb_evt_to_btc(uint8_t event, void *model, void *ctx) +{ +#if CONFIG_BLE_MESH_MBT_SRV + bt_mesh_mbt_server_cb_evt_to_btc(event, model, ctx); +#else + assert(0); +#endif /* CONFIG_BLE_MESH_MBT_SRV */ +} + +typedef struct { + uint64_t config_ble_mesh_use_duplicate_scan : 1; + uint64_t config_ble_mesh_pb_adv : 1; + uint64_t config_ble_mesh_pb_gatt : 1; + uint64_t config_ble_mesh_prov_epa : 1; + uint64_t config_ble_mesh_cert_based_prov : 1; + uint64_t config_ble_mesh_gatt_proxy_client : 1; + uint64_t config_ble_mesh_gatt_proxy_server : 1; + uint64_t config_ble_mesh_proxy_solic_pdu_rx : 1; + uint64_t config_ble_mesh_proxy_solic_pdu_tx : 1; + uint64_t config_ble_mesh_proxy_solic : 1; + uint64_t config_ble_mesh_support_directed_proxy : 1; + uint64_t config_ble_mesh_relay : 1; + uint64_t config_ble_mesh_settings : 1; + uint64_t config_ble_mesh_friend : 1; + uint64_t config_ble_mesh_low_power : 1; + uint64_t config_ble_mesh_agg_cli : 1; + uint64_t config_ble_mesh_agg_srv : 1; + uint64_t config_ble_mesh_brc_cli : 1; + uint64_t config_ble_mesh_brc_srv : 1; + uint64_t config_ble_mesh_df_cli : 1; + uint64_t config_ble_mesh_df_srv : 1; + uint64_t config_ble_mesh_path_monitor_test : 1; + uint64_t config_ble_mesh_lcd_cli : 1; + uint64_t config_ble_mesh_lcd_srv : 1; + uint64_t config_ble_mesh_comp_data_1 : 1; + uint64_t config_ble_mesh_comp_data_128 : 1; + uint64_t config_ble_mesh_models_metadata_0 : 1; + uint64_t config_ble_mesh_models_metadata_128 : 1; + uint64_t config_ble_mesh_mbt_cli : 1; + uint64_t config_ble_mesh_mbt_srv : 1; + uint64_t config_ble_mesh_odp_cli : 1; + uint64_t config_ble_mesh_odp_srv : 1; + uint64_t config_ble_mesh_prb_cli : 1; + uint64_t config_ble_mesh_prb_srv : 1; + uint64_t config_ble_mesh_private_beacon : 1; + uint64_t config_ble_mesh_rpr_cli : 1; + uint64_t config_ble_mesh_rpr_srv : 1; + uint64_t config_ble_mesh_rpr_srv_active_scan : 1; + uint64_t config_ble_mesh_sar_cli : 1; + uint64_t config_ble_mesh_sar_srv : 1; + uint64_t config_ble_mesh_srpl_cli : 1; + uint64_t config_ble_mesh_srpl_srv : 1; + + uint16_t config_ble_mesh_record_frag_max_size; + uint16_t config_ble_mesh_crpl; + 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_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; + uint16_t config_ble_mesh_rpr_cli_prov_same_time; + uint16_t config_ble_mesh_rpr_srv_max_scanned_items; + uint16_t config_ble_mesh_rpr_srv_max_ext_scan; + uint16_t config_ble_mesh_max_blob_receivers; + + uint8_t struct_net_tx_size; + uint8_t struct_net_rx_size; + uint8_t struct_client_common_size; + uint8_t struct_client_internal_data_size; + uint8_t struct_msg_ctx_size; + uint8_t struct_mutex_size; + uint8_t struct_timer_size; + uint8_t struct_snode_size; + uint8_t struct_slist_size; + uint8_t struct_slist_off_tail; + uint8_t struct_net_buf_simple_size; + uint8_t struct_net_buf_simple_off_len; + uint8_t struct_net_buf_simple_off_size; + uint8_t struct_net_buf_simple_off_buf; + uint8_t struct_net_buf_simple_state_size; + uint8_t struct_net_buf_simple_state_off_len; + uint8_t struct_client_op_pair_size; + uint8_t struct_client_op_pair_off_status_op; + uint8_t struct_model_op_size; + uint8_t struct_model_op_off_min_len; + uint8_t struct_model_op_off_func; + uint8_t struct_model_cb_size; + uint8_t struct_model_cb_off_deinit; + uint8_t struct_send_cb_size; + uint8_t struct_send_cb_off_end; + uint8_t struct_addr_size; + uint8_t struct_addr_off_val; + uint8_t struct_sg_size; + uint8_t struct_sg_off_len; + uint8_t struct_tc_sha256_state; + uint8_t struct_tc_sha256_off_bits_hashed; + uint8_t struct_tc_sha256_off_leftover; + uint8_t struct_tc_sha256_off_leftover_offset; + uint8_t struct_tc_hmac_state_size; + uint8_t struct_tc_hmac_state_off_key; + + uint8_t btc_ble_mesh_evt_agg_client_send_timeout; + uint8_t btc_ble_mesh_evt_agg_client_recv_rsp; + uint8_t btc_ble_mesh_evt_agg_client_recv_pub; + uint8_t btc_ble_mesh_evt_agg_server_recv_msg; + uint8_t btc_ble_mesh_evt_brc_client_recv_rsp; + uint8_t btc_ble_mesh_evt_brc_client_recv_pub; + uint8_t btc_ble_mesh_evt_brc_client_send_timeout; + uint8_t btc_ble_mesh_evt_brc_server_state_change; + uint8_t btc_ble_mesh_evt_df_client_send_timeout; + uint8_t btc_ble_mesh_evt_df_client_recv_get_rsp; + uint8_t btc_ble_mesh_evt_df_client_recv_set_rsp; + uint8_t btc_ble_mesh_evt_df_client_recv_pub; + uint8_t btc_ble_mesh_evt_df_server_state_change; + uint8_t btc_ble_mesh_evt_df_server_table_change; + uint8_t btc_ble_mesh_evt_lcd_client_send_timeout; + uint8_t btc_ble_mesh_evt_lcd_client_recv_rsp; + uint8_t btc_ble_mesh_evt_lcd_client_recv_pub; + uint8_t btc_ble_mesh_evt_mbt_client_retrieve_capabilities_comp; + uint8_t btc_ble_mesh_evt_mbt_client_transfer_blob_comp; + uint8_t btc_ble_mesh_evt_mbt_client_send_block_comp; + uint8_t btc_ble_mesh_evt_mbt_client_send_data_comp; + uint8_t btc_ble_mesh_evt_mbt_client_determine_block_status_comp; + uint8_t btc_ble_mesh_evt_mbt_client_determine_transfer_status_comp; + uint8_t btc_ble_mesh_evt_mbt_client_cancel_transfer_comp; + uint8_t btc_ble_mesh_evt_mbt_client_set_transfer_ttl_comp; + uint8_t btc_ble_mesh_evt_mbt_client_clear_transfer_ttl_comp; + uint8_t btc_ble_mesh_evt_mbt_client_set_app_idx_comp; + uint8_t btc_ble_mesh_evt_mbt_client_clear_app_idx_comp; + uint8_t btc_ble_mesh_evt_mbt_client_set_multicast_addr_comp; + uint8_t btc_ble_mesh_evt_mbt_client_clear_multicast_addr_comp; + uint8_t btc_ble_mesh_mbt_client_result_complete; + uint8_t btc_ble_mesh_mbt_client_result_fail; + uint8_t btc_ble_mesh_evt_mbt_server_initialize_blob_receive_comp; + uint8_t btc_ble_mesh_evt_mbt_server_cancel_blob_receive_comp; + uint8_t btc_ble_mesh_evt_mbt_server_set_blob_capabilities_comp; + uint8_t btc_ble_mesh_evt_mbt_server_blob_transfer_get; + uint8_t btc_ble_mesh_evt_mbt_server_blob_transfer_start; + uint8_t btc_ble_mesh_evt_mbt_server_blob_transfer_cancel; + uint8_t btc_ble_mesh_evt_mbt_server_blob_block_get; + uint8_t btc_ble_mesh_evt_mbt_server_blob_block_start; + uint8_t btc_ble_mesh_evt_mbt_server_blob_chunk_transfer; + uint8_t btc_ble_mesh_evt_mbt_server_blob_information_get; + uint8_t btc_ble_mesh_evt_mbt_server_block_receive_comp; + uint8_t btc_ble_mesh_evt_mbt_server_blob_receive_comp; + uint8_t btc_ble_mesh_evt_mbt_server_blob_receive_timeout; + uint8_t btc_ble_mesh_evt_odp_client_send_timeout; + uint8_t btc_ble_mesh_evt_odp_client_recv_rsp; + uint8_t btc_ble_mesh_evt_odp_client_recv_pub; + uint8_t btc_ble_mesh_evt_prb_client_recv_rsp; + uint8_t btc_ble_mesh_evt_prb_client_recv_pub; + uint8_t btc_ble_mesh_evt_prb_client_send_timeout; + uint8_t btc_ble_mesh_evt_rpr_client_send_timeout; + uint8_t btc_ble_mesh_evt_rpr_client_recv_rsp; + uint8_t btc_ble_mesh_evt_rpr_client_recv_pub; + uint8_t btc_ble_mesh_evt_rpr_server_scan_start; + uint8_t btc_ble_mesh_evt_rpr_server_scan_stop; + uint8_t btc_ble_mesh_evt_rpr_server_ext_scan_start; + uint8_t btc_ble_mesh_evt_rpr_server_ext_scan_stop; + uint8_t btc_ble_mesh_evt_rpr_server_link_open; + uint8_t btc_ble_mesh_evt_rpr_server_link_close; + uint8_t btc_ble_mesh_evt_sar_client_send_timeout; + uint8_t btc_ble_mesh_evt_sar_client_recv_rsp; + uint8_t btc_ble_mesh_evt_sar_client_recv_pub; + uint8_t btc_ble_mesh_evt_srpl_client_send_timeout; + uint8_t btc_ble_mesh_evt_srpl_client_recv_rsp; + uint8_t btc_ble_mesh_evt_srpl_client_recv_pub; +} bt_mesh_ext_config_t; + +static const bt_mesh_ext_config_t bt_mesh_ext_cfg = { + .config_ble_mesh_use_duplicate_scan = IS_ENABLED(CONFIG_BLE_MESH_USE_DUPLICATE_SCAN), + .config_ble_mesh_pb_adv = IS_ENABLED(CONFIG_BLE_MESH_PB_ADV), + .config_ble_mesh_pb_gatt = IS_ENABLED(CONFIG_BLE_MESH_PB_GATT), + .config_ble_mesh_prov_epa = IS_ENABLED(CONFIG_BLE_MESH_PROV_EPA), + .config_ble_mesh_cert_based_prov = IS_ENABLED(CONFIG_BLE_MESH_CERT_BASED_PROV), + .config_ble_mesh_gatt_proxy_client = IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT), + .config_ble_mesh_gatt_proxy_server = IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER), + .config_ble_mesh_proxy_solic_pdu_rx = IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX), + .config_ble_mesh_proxy_solic_pdu_tx = IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX), + .config_ble_mesh_proxy_solic = (IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) | \ + IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX)), + .config_ble_mesh_support_directed_proxy = IS_ENABLED(CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY), + .config_ble_mesh_relay = IS_ENABLED(CONFIG_BLE_MESH_RELAY), + .config_ble_mesh_settings = IS_ENABLED(CONFIG_BLE_MESH_SETTINGS), + .config_ble_mesh_friend = IS_ENABLED(CONFIG_BLE_MESH_FRIEND), + .config_ble_mesh_low_power = IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER), + .config_ble_mesh_agg_cli = IS_ENABLED(CONFIG_BLE_MESH_AGG_CLI), + .config_ble_mesh_agg_srv = IS_ENABLED(CONFIG_BLE_MESH_AGG_SRV), + .config_ble_mesh_brc_cli = IS_ENABLED(CONFIG_BLE_MESH_BRC_CLI), + .config_ble_mesh_brc_srv = IS_ENABLED(CONFIG_BLE_MESH_BRC_SRV), + .config_ble_mesh_df_cli = IS_ENABLED(CONFIG_BLE_MESH_DF_CLI), + .config_ble_mesh_df_srv = IS_ENABLED(CONFIG_BLE_MESH_DF_SRV), + .config_ble_mesh_path_monitor_test = IS_ENABLED(CONFIG_BLE_MESH_PATH_MONITOR_TEST), + .config_ble_mesh_lcd_cli = IS_ENABLED(CONFIG_BLE_MESH_LCD_CLI), + .config_ble_mesh_lcd_srv = IS_ENABLED(CONFIG_BLE_MESH_LCD_SRV), + .config_ble_mesh_comp_data_1 = IS_ENABLED(CONFIG_BLE_MESH_COMP_DATA_1), + .config_ble_mesh_comp_data_128 = IS_ENABLED(CONFIG_BLE_MESH_COMP_DATA_128), + .config_ble_mesh_models_metadata_0 = IS_ENABLED(CONFIG_BLE_MESH_MODELS_METADATA_0), + .config_ble_mesh_models_metadata_128 = IS_ENABLED(CONFIG_BLE_MESH_MODELS_METADATA_128), + .config_ble_mesh_mbt_cli = IS_ENABLED(CONFIG_BLE_MESH_MBT_CLI), + .config_ble_mesh_mbt_srv = IS_ENABLED(CONFIG_BLE_MESH_MBT_SRV), + .config_ble_mesh_odp_cli = IS_ENABLED(CONFIG_BLE_MESH_ODP_CLI), + .config_ble_mesh_odp_srv = IS_ENABLED(CONFIG_BLE_MESH_ODP_SRV), + .config_ble_mesh_prb_cli = IS_ENABLED(CONFIG_BLE_MESH_PRB_CLI), + .config_ble_mesh_prb_srv = IS_ENABLED(CONFIG_BLE_MESH_PRB_SRV), + .config_ble_mesh_private_beacon = (IS_ENABLED(CONFIG_BLE_MESH_PRB_SRV) | \ + IS_ENABLED(CONFIG_BLE_MESH_PRB_SRV)), + .config_ble_mesh_rpr_cli = IS_ENABLED(CONFIG_BLE_MESH_RPR_CLI), + .config_ble_mesh_rpr_srv = IS_ENABLED(CONFIG_BLE_MESH_RPR_SRV), + .config_ble_mesh_rpr_srv_active_scan = IS_ENABLED(CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN), + .config_ble_mesh_sar_cli = IS_ENABLED(CONFIG_BLE_MESH_SAR_CLI), + .config_ble_mesh_sar_srv = IS_ENABLED(CONFIG_BLE_MESH_SAR_SRV), + .config_ble_mesh_srpl_cli = IS_ENABLED(CONFIG_BLE_MESH_SRPL_CLI), + .config_ble_mesh_srpl_srv = IS_ENABLED(CONFIG_BLE_MESH_SRPL_SRV), + +#if CONFIG_BLE_MESH_CERT_BASED_PROV + .config_ble_mesh_record_frag_max_size = CONFIG_BLE_MESH_RECORD_FRAG_MAX_SIZE, +#endif /* CONFIG_BLE_MESH_CERT_BASED_PROV */ + .config_ble_mesh_crpl = CONFIG_BLE_MESH_CRPL, +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX + .config_ble_mesh_proxy_solic_rx_crpl = CONFIG_BLE_MESH_PROXY_SOLIC_RX_CRPL, +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + .config_ble_mesh_proxy_solic_tx_src_count = CONFIG_BLE_MESH_PROXY_SOLIC_TX_SRC_COUNT, +#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, +#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, + .config_ble_mesh_max_forward_table_entry_count = CONFIG_BLE_MESH_MAX_FORWARD_TABLE_ENTRY_COUNT, + .config_ble_mesh_max_deps_nodes_per_path = CONFIG_BLE_MESH_MAX_DEPS_NODES_PER_PATH, +#endif /* CONFIG_BLE_MESH_DF_SRV */ +#if CONFIG_BLE_MESH_RPR_CLI + .config_ble_mesh_rpr_cli_prov_same_time = CONFIG_BLE_MESH_RPR_CLI_PROV_SAME_TIME, +#endif /* CONFIG_BLE_MESH_RPR_CLI */ +#if CONFIG_BLE_MESH_RPR_SRV + .config_ble_mesh_rpr_srv_max_scanned_items = CONFIG_BLE_MESH_RPR_SRV_MAX_SCANNED_ITEMS, + .config_ble_mesh_rpr_srv_max_ext_scan = CONFIG_BLE_MESH_RPR_SRV_MAX_EXT_SCAN, +#endif /* CONFIG_BLE_MESH_RPR_SRV */ +#if CONFIG_BLE_MESH_MBT_CLI + .config_ble_mesh_max_blob_receivers = CONFIG_BLE_MESH_MAX_BLOB_RECEIVERS, +#endif /* CONFIG_BLE_MESH_MBT_CLI */ + + .struct_net_tx_size = sizeof(struct bt_mesh_net_tx), + .struct_net_rx_size = sizeof(struct bt_mesh_net_rx), + .struct_client_common_size = sizeof(bt_mesh_client_common_param_t), + .struct_client_internal_data_size = sizeof(bt_mesh_client_internal_data_t), + .struct_msg_ctx_size = sizeof(struct bt_mesh_msg_ctx), + .struct_mutex_size = sizeof(bt_mesh_mutex_t), + .struct_timer_size = sizeof(struct k_delayed_work), + .struct_snode_size = sizeof(struct _snode), + .struct_slist_size = sizeof(struct _slist), + .struct_slist_off_tail = offsetof(struct _slist, tail), + .struct_net_buf_simple_size = sizeof(struct net_buf_simple), + .struct_net_buf_simple_off_len = offsetof(struct net_buf_simple, len), + .struct_net_buf_simple_off_size = offsetof(struct net_buf_simple, size), + .struct_net_buf_simple_off_buf = offsetof(struct net_buf_simple, __buf), + .struct_net_buf_simple_state_size = sizeof(struct net_buf_simple_state), + .struct_net_buf_simple_state_off_len = offsetof(struct net_buf_simple_state, len), + .struct_client_op_pair_size = sizeof(bt_mesh_client_op_pair_t), + .struct_client_op_pair_off_status_op = offsetof(bt_mesh_client_op_pair_t, status_op), + .struct_model_op_size = sizeof(struct bt_mesh_model_op), + .struct_model_op_off_min_len = offsetof(struct bt_mesh_model_op, min_len), + .struct_model_op_off_func = offsetof(struct bt_mesh_model_op, func), +#if 0 + .struct_model_cb_size = sizeof(struct bt_mesh_model_cb), + .struct_model_cb_off_deinit = offsetof(struct bt_mesh_model_cb, deinit), +#endif + .struct_send_cb_size = sizeof(struct bt_mesh_send_cb), + .struct_send_cb_off_end = offsetof(struct bt_mesh_send_cb, end), + .struct_addr_size = sizeof(bt_mesh_addr_t), + .struct_addr_off_val = offsetof(bt_mesh_addr_t, val), + .struct_sg_size = sizeof(struct bt_mesh_sg), + .struct_sg_off_len = offsetof(struct bt_mesh_sg, len), + .struct_tc_sha256_state = sizeof(struct tc_sha256_state_struct), + .struct_tc_sha256_off_bits_hashed = offsetof(struct tc_sha256_state_struct, bits_hashed), + .struct_tc_sha256_off_leftover = offsetof(struct tc_sha256_state_struct, leftover), + .struct_tc_sha256_off_leftover_offset = offsetof(struct tc_sha256_state_struct, leftover_offset), + .struct_tc_hmac_state_size = sizeof(struct tc_hmac_state_struct), + .struct_tc_hmac_state_off_key = offsetof(struct tc_hmac_state_struct, key), + + .btc_ble_mesh_evt_agg_client_send_timeout = BTC_BLE_MESH_EVT_AGG_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_agg_client_recv_rsp = BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_agg_client_recv_pub = BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_agg_server_recv_msg = BTC_BLE_MESH_EVT_AGG_SERVER_RECV_MSG, + .btc_ble_mesh_evt_brc_client_recv_rsp = BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_brc_client_recv_pub = BTC_BLE_MESH_EVT_BRC_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_brc_client_send_timeout = BTC_BLE_MESH_EVT_BRC_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_brc_server_state_change = BTC_BLE_MESH_EVT_BRC_SERVER_STATE_CHANGE, + .btc_ble_mesh_evt_df_client_send_timeout = BTC_BLE_MESH_EVT_DF_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_df_client_recv_get_rsp = BTC_BLE_MESH_EVT_DF_CLIENT_RECV_GET_RSP, + .btc_ble_mesh_evt_df_client_recv_set_rsp = BTC_BLE_MESH_EVT_DF_CLIENT_RECV_SET_RSP, + .btc_ble_mesh_evt_df_client_recv_pub = BTC_BLE_MESH_EVT_DF_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_df_server_state_change = BTC_BLE_MESH_EVT_DF_SERVER_STATE_CHANGE, + .btc_ble_mesh_evt_df_server_table_change = BTC_BLE_MESH_EVT_DF_SERVER_TABLE_CHANGE, + .btc_ble_mesh_evt_lcd_client_send_timeout = BTC_BLE_MESH_EVT_LCD_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_lcd_client_recv_rsp = BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_lcd_client_recv_pub = BTC_BLE_MESH_EVT_LCD_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_mbt_client_retrieve_capabilities_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_RETRIEVE_CAPABILITIES_COMP, + .btc_ble_mesh_evt_mbt_client_transfer_blob_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_TRANSFER_BLOB_COMP, + .btc_ble_mesh_evt_mbt_client_send_block_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_BLOCK_COMP, + .btc_ble_mesh_evt_mbt_client_send_data_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_SEND_DATA_COMP, + .btc_ble_mesh_evt_mbt_client_determine_block_status_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_BLOCK_STATUS_COMP, + .btc_ble_mesh_evt_mbt_client_determine_transfer_status_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_DETERMINE_TRANSFER_STATUS_COMP, + .btc_ble_mesh_evt_mbt_client_cancel_transfer_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_CANCEL_TRANSFER_COMP, + .btc_ble_mesh_evt_mbt_client_set_transfer_ttl_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_SET_TRANSFER_TTL_COMP, + .btc_ble_mesh_evt_mbt_client_clear_transfer_ttl_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_TRANSFER_TTL_COMP, + .btc_ble_mesh_evt_mbt_client_set_app_idx_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_SET_APP_IDX_COMP, + .btc_ble_mesh_evt_mbt_client_clear_app_idx_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_APP_IDX_COMP, + .btc_ble_mesh_evt_mbt_client_set_multicast_addr_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_SET_MULTICAST_ADDR_COMP, + .btc_ble_mesh_evt_mbt_client_clear_multicast_addr_comp = BTC_BLE_MESH_EVT_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP, + .btc_ble_mesh_mbt_client_result_complete = BTC_BLE_MESH_MBT_CLIENT_RESULT_COMPLETE, + .btc_ble_mesh_mbt_client_result_fail = BTC_BLE_MESH_MBT_CLIENT_RESULT_FAIL, + .btc_ble_mesh_evt_odp_client_send_timeout = BTC_BLE_MESH_EVT_ODP_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_odp_client_recv_rsp = BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_odp_client_recv_pub = BTC_BLE_MESH_EVT_ODP_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_prb_client_recv_rsp = BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_prb_client_recv_pub = BTC_BLE_MESH_EVT_PRB_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_prb_client_send_timeout = BTC_BLE_MESH_EVT_PRB_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_rpr_client_send_timeout = BTC_BLE_MESH_EVT_RPR_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_rpr_client_recv_rsp = BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_rpr_client_recv_pub = BTC_BLE_MESH_EVT_RPR_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_sar_client_send_timeout = BTC_BLE_MESH_EVT_SAR_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_sar_client_recv_rsp = BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_sar_client_recv_pub = BTC_BLE_MESH_EVT_SAR_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_srpl_client_send_timeout = BTC_BLE_MESH_EVT_SRPL_CLIENT_SEND_TIMEOUT, + .btc_ble_mesh_evt_srpl_client_recv_rsp = BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_RSP, + .btc_ble_mesh_evt_srpl_client_recv_pub = BTC_BLE_MESH_EVT_SRPL_CLIENT_RECV_PUB, + .btc_ble_mesh_evt_rpr_server_scan_start = BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_START, + .btc_ble_mesh_evt_rpr_server_scan_stop = BTC_BLE_MESH_EVT_RPR_SERVER_SCAN_STOP, + .btc_ble_mesh_evt_rpr_server_ext_scan_start = BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_START, + .btc_ble_mesh_evt_rpr_server_ext_scan_stop = BTC_BLE_MESH_EVT_RPR_SERVER_EXT_SCAN_STOP, + .btc_ble_mesh_evt_rpr_server_link_open = BTC_BLE_MESH_EVT_RPR_SERVER_LINK_OPEN, + .btc_ble_mesh_evt_rpr_server_link_close = BTC_BLE_MESH_EVT_RPR_SERVER_LINK_CLOSE, + .btc_ble_mesh_evt_mbt_server_initialize_blob_receive_comp = BTC_BLE_MESH_EVT_MBT_SERVER_INITIALIZE_BLOB_RECEIVE_COMP, + .btc_ble_mesh_evt_mbt_server_cancel_blob_receive_comp = BTC_BLE_MESH_EVT_MBT_SERVER_CANCEL_BLOB_RECEIVE_COMP, + .btc_ble_mesh_evt_mbt_server_set_blob_capabilities_comp = BTC_BLE_MESH_EVT_MBT_SERVER_SET_BLOB_CAPABILITIES_COMP, + .btc_ble_mesh_evt_mbt_server_blob_transfer_get = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_GET, + .btc_ble_mesh_evt_mbt_server_blob_transfer_start = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_START, + .btc_ble_mesh_evt_mbt_server_blob_transfer_cancel = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_TRANSFER_CANCEL, + .btc_ble_mesh_evt_mbt_server_blob_block_get = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_GET, + .btc_ble_mesh_evt_mbt_server_blob_block_start = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_BLOCK_START, + .btc_ble_mesh_evt_mbt_server_blob_chunk_transfer = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_CHUNK_TRANSFER, + .btc_ble_mesh_evt_mbt_server_blob_information_get = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_INFORMATION_GET, + .btc_ble_mesh_evt_mbt_server_block_receive_comp = BTC_BLE_MESH_EVT_MBT_SERVER_BLOCK_RECEIVE_COMP, + .btc_ble_mesh_evt_mbt_server_blob_receive_comp = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_COMP, + .btc_ble_mesh_evt_mbt_server_blob_receive_timeout = BTC_BLE_MESH_EVT_MBT_SERVER_BLOB_RECEIVE_TIMEOUT, +}; + +typedef struct { +/* CONFIG_BLE_MESH_NODE */ + uint8_t (*_bt_mesh_ext_prov_node_next_xact_id)(void *link); + void *(*_bt_mesh_ext_prov_node_get_link)(void); + void (*_bt_mesh_ext_prov_node_close_link)(uint8_t reason); + const uint8_t *(*_bt_mesh_ext_prov_node_get_uuid)(void); + uint16_t (*_bt_mesh_ext_prov_node_get_oob_info)(void); + const char *(*_bt_mesh_ext_prov_node_get_uri)(void); +/* CONFIG_BLE_MESH_NODE */ + +/* CONFIG_BLE_MESH_PROVISIONER */ + uint8_t (*_bt_mesh_ext_prov_pvnr_next_xact_id)(void *link); + void *(*_bt_mesh_ext_prov_pvnr_get_link)(void); + uint8_t (*_bt_mesh_ext_prov_pvnr_get_link_count)(void); + void (*_bt_mesh_ext_prov_pvnr_send_invite)(void *link); + void (*_bt_mesh_ext_prov_pvnr_close_link)(void *link, uint8_t reason); + void *(*_bt_mesh_ext_pvnr_get_node_with_addr)(uint16_t unicast_addr); +/* CONFIG_BLE_MESH_CERT_BASED_PROV */ + void (*_bt_mesh_ext_pvnr_records_list_get_cb)(uint16_t link_idx, struct net_buf_simple *data); + void (*_bt_mesh_ext_pvnr_records_recv_comp_cb)(uint8_t status, uint16_t link_idx, + uint16_t record_id, uint16_t frag_offset, + uint16_t total_len, uint8_t *record); + uint16_t (*_bt_mesh_ext_prov_link_get_record_id_expect)(void *link); + void (*_bt_mesh_ext_prov_link_set_record_id_expect)(void *link, uint16_t record_id_expect); + uint16_t (*_bt_mesh_ext_prov_link_get_offset_expect)(void *link); + void (*_bt_mesh_ext_prov_link_set_offset_expect)(void *link, uint16_t offset_expect); + uint16_t (*_bt_mesh_ext_prov_link_get_max_size)(void *link); + void (*_bt_mesh_ext_prov_link_set_max_size)(void *link, uint16_t max_size); + uint8_t *(*_bt_mesh_ext_prov_link_get_record)(void *link, uint16_t id); + uint8_t *(*_bt_mesh_ext_prov_link_alloc_record)(void *link, uint16_t id, uint16_t len); +/* CONFIG_BLE_MESH_CERT_BASED_PROV */ + uint8_t *(*_bt_mesh_ext_pvnr_get_node_uuid)(void *node); + uint8_t *(*_bt_mesh_ext_prov_link_get_uuid)(void *link); + uint8_t (*_bt_mesh_ext_prov_link_get_elem_num)(void *link); + uint16_t (*_bt_mesh_ext_prov_link_get_unicast_addr)(void *link); +/* CONFIG_BLE_MESH_PROVISIONER */ + +/* CONFIG_BLE_MESH_PB_GATT */ + void *(*_bt_mesh_ext_prov_link_get_conn)(void *link); + bool (*_bt_mesh_ext_prov_link_pb_gatt_exist)(void *link); + int (*_bt_mesh_ext_prov_link_pb_gatt_send)(void *link, struct net_buf_simple *msg); +/* CONFIG_BLE_MESH_PB_GATT */ + +/* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + const char *(*_bt_mesh_ext_get_device_name)(void); +/* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + +/* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + uint8_t (*_bt_mesh_ext_proxy_server_get_all_client_type)(void); + int (*_bt_mesh_ext_proxy_server_segment_send)(void *conn, uint8_t type, + struct net_buf_simple *msg); + bool (*_bt_mesh_ext_proxy_server_find_client_by_addr)(uint16_t addr); + void (*_bt_mesh_ext_proxy_server_update_net_id_rand_stop)(void); + void *(*_bt_mesh_ext_proxy_server_get_client)(uint8_t index); + uint8_t (*_bt_mesh_ext_proxy_server_get_client_count)(void); +/* CONFIG_BLE_MESH_PRB_SRV */ + void (*_bt_mesh_ext_proxy_server_update_net_id_rand)(void); + bool (*_bt_mesh_ext_proxy_server_is_node_id_enable)(void); + void (*_bt_mesh_ext_proxy_server_private_identity_start)(void *sub); + void (*_bt_mesh_ext_proxy_server_private_identity_stop)(void *sub); +/* CONFIG_BLE_MESH_PRB_SRV */ + uint8_t (*_bt_mesh_ext_proxy_server_get_filter_type)(void *client); + uint8_t (*_bt_mesh_ext_proxy_server_get_filter_count)(void *client); + uint16_t (*_bt_mesh_ext_proxy_server_get_filter_size)(void *client); + uint16_t (*_bt_mesh_ext_proxy_server_get_filter_addr)(void *client, uint8_t index); + bool (*_bt_mesh_ext_proxy_server_filter_is_client)(void *client, uint8_t index); + uint8_t (*_bt_mesh_ext_proxy_server_get_client_type)(void *client); + bool (*_bt_mesh_ext_proxy_server_is_proxy_msg_recv)(void *client); + void *(*_bt_mesh_ext_proxy_server_get_conn)(void *client); + void (*_bt_mesh_ext_proxy_server_set_client_type)(void *client, uint8_t type); + void (*_bt_mesh_ext_proxy_server_set_msg_recv)(void *client, uint8_t val); +/* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + +/* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + bool (*_bt_mesh_ext_proxy_client_beacon_send)(void *sub, bool private); + uint8_t (*_bt_mesh_ext_proxy_client_get_opcode)(void *cfg); + uint8_t (*_bt_mesh_ext_proxy_client_get_use_directed)(void *cfg); + void *(*_bt_mesh_ext_proxy_client_get_client_uar)(void *cfg); +/* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + +/* CONFIG_BLE_MESH_FRIEND */ + uint16_t (*_bt_mesh_ext_frnd_get_lpn)(void *frnd); + uint8_t (*_bt_mesh_ext_frnd_get_num_elem)(void *frnd); + bool (*_bt_mesh_ext_frnd_is_valid)(void *frnd); + bool (*_bt_mesh_ext_frnd_is_established)(void *frnd); + uint16_t (*_bt_mesh_ext_frnd_get_net_idx)(void *frnd); + uint8_t (*_bt_mesh_ext_frnd_get_sub_list_count)(void *frnd); + uint16_t (*_bt_mesh_ext_frnd_get_sub_list_size)(void *frnd); + uint16_t (*_bt_mesh_ext_frnd_get_sub_addr)(void *frnd, uint8_t index); + uint8_t (*_bt_mesh_ext_net_get_frnd_count)(void); + void *(*_bt_mesh_ext_net_get_frnd)(uint8_t index); + bool (*_bt_mesh_ext_friend_match)(uint16_t net_idx, uint16_t addr); + bool (*_bt_mesh_ext_friend_unicast_match)(uint16_t net_idx, uint16_t addr, uint8_t *selem); + void *(*_bt_mesh_ext_friend_find)(uint16_t net_idx, uint16_t lpn_addr, bool valid, bool established); + void (*_bt_mesh_ext_friend_clear_net_idx)(uint16_t net_idx); +/* CONFIG_BLE_MESH_FRIEND */ + +/* CONFIG_BLE_MESH_LOW_POWER */ + bool (*_bt_mesh_ext_lpn_match)(uint16_t addr); +/* CONFIG_BLE_MESH_LOW_POWER */ + +/* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ + int (*_bt_mesh_ext_update_exceptional_list)(uint8_t sub_code, uint32_t type, void *info); +/* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ +/* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ + int (*_bt_mesh_ext_unprov_dev_info_query)(uint8_t uuid[16], uint8_t addr[6], + uint8_t *adv_type, uint8_t query_type); +/* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ + +/* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + int (*_bt_mesh_ext_gattc_conn_create)(const void *addr, uint16_t service_uuid); + void (*_bt_mesh_ext_gattc_disconnect)(void *conn); +/* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + +/* CONFIG_BLE_MESH_SETTINGS */ + void (*_bt_mesh_ext_store_dkca)(void); + void (*_bt_mesh_ext_clear_dkca)(void); + void (*_bt_mesh_ext_clear_rpl_single)(uint16_t src); + void (*_bt_mesh_ext_store_net)(void); + void (*_bt_mesh_ext_store_seq)(void); + struct net_buf_simple *(*_bt_mesh_ext_get_core_settings_item)(const char *key); + bool (*_bt_mesh_ext_is_settings_item_exist)(struct net_buf_simple *buf, const uint16_t val); + int (*_bt_mesh_ext_add_core_settings_item)(const char *key, const uint16_t val); + int (*_bt_mesh_ext_remove_core_settings_item)(const char *key, const uint16_t val); + int (*_bt_mesh_ext_save_core_settings)(const char *key, const uint8_t *val, size_t len); + int (*_bt_mesh_ext_erase_core_settings)(const char *key); +/* CONFIG_BLE_MESH_SETTINGS */ + +/* CONFIG_BLE_MESH_DF_SRV */ + uint8_t (*_bt_mesh_ext_model_get_pub_directed_pub_policy)(void *model); + void (*_bt_mesh_ext_model_set_pub_directed_pub_policy)(void *model, uint8_t directed_pub_policy); + uint8_t (*_bt_mesh_ext_sub_get_keys_direct_nid)(void *sub, uint8_t index); + uint8_t *(*_bt_mesh_ext_sub_get_keys_direct_enc)(void *sub, uint8_t index); + uint8_t *(*_bt_mesh_ext_sub_get_keys_direct_privacy)(void *sub, uint8_t index); + uint8_t (*_bt_mesh_ext_sub_get_directed_forwarding)(void *sub); + void (*_bt_mesh_ext_sub_set_directed_forwarding)(void *sub, uint8_t directed_forwarding); + uint8_t (*_bt_mesh_ext_sub_get_directed_relay)(void *sub); + void (*_bt_mesh_ext_sub_set_directed_relay)(void *sub, uint8_t directed_relay); + uint8_t (*_bt_mesh_ext_sub_get_directed_proxy)(void *sub); + void (*_bt_mesh_ext_sub_set_directed_proxy)(void *sub, uint8_t directed_proxy); + uint8_t (*_bt_mesh_ext_sub_get_directed_proxy_use_default)(void *sub); + void (*_bt_mesh_ext_sub_set_directed_proxy_use_default)(void *sub, uint8_t directed_proxy_use_default); + uint8_t (*_bt_mesh_ext_sub_get_directed_friend)(void *sub); + void (*_bt_mesh_ext_sub_set_directed_friend)(void *sub, uint8_t directed_friend); + uint8_t (*_bt_mesh_ext_sub_get_use_directed)(void *sub); + void (*_bt_mesh_ext_sub_set_use_directed)(void *sub, uint8_t use_directed); + void *(*_bt_mesh_ext_sub_get_proxy_client_uar)(void *sub); + bool (*_bt_mesh_ext_sub_get_proxy_client_uar_len_present)(void *sub); + void (*_bt_mesh_ext_sub_set_proxy_client_uar_len_present)(void *sub, bool len_present); + uint16_t (*_bt_mesh_ext_sub_get_proxy_client_uar_range_start)(void *sub); + void (*_bt_mesh_ext_sub_set_proxy_client_uar_range_start)(void *sub, uint16_t range_start); + uint8_t (*_bt_mesh_ext_sub_get_proxy_client_uar_range_length)(void *sub); + void (*_bt_mesh_ext_sub_set_proxy_client_uar_range_length)(void *sub, uint8_t range_length); + uint8_t (*_bt_mesh_ext_sub_get_path_metric_type)(void *sub); + void (*_bt_mesh_ext_sub_set_path_metric_type)(void *sub, uint8_t path_metric_type); + uint8_t (*_bt_mesh_ext_sub_get_path_lifetime_type)(void *sub); + void (*_bt_mesh_ext_sub_set_path_lifetime_type)(void *sub, uint8_t path_lifetime_type); + bool (*_bt_mesh_ext_sub_get_two_way_path)(void *sub); + void (*_bt_mesh_ext_sub_set_two_way_path)(void *sub, bool two_way_path); + uint8_t (*_bt_mesh_ext_sub_get_forward_number)(void *sub); + void (*_bt_mesh_ext_sub_set_forward_number)(void *sub, uint8_t forward_number); + uint8_t (*_bt_mesh_ext_sub_get_disc_table_max_disc_entries)(void *sub); + void (*_bt_mesh_ext_sub_set_disc_table_max_disc_entries)(void *sub, uint8_t max_disc_entries); + uint8_t (*_bt_mesh_ext_sub_get_disc_table_max_concurr_init)(void *sub); + void (*_bt_mesh_ext_sub_set_disc_table_max_concurr_init)(void *sub, uint8_t max_concurr_init); + uint8_t (*_bt_mesh_ext_sub_get_disc_table_concurr_init)(void *sub); + void (*_bt_mesh_ext_sub_set_disc_table_concurr_init)(void *sub, uint8_t concurr_init); + void (*_bt_mesh_ext_sub_inc_disc_table_concurr_init)(void *sub); + void (*_bt_mesh_ext_sub_dec_disc_table_concurr_init)(void *sub); + void *(*_bt_mesh_ext_sub_get_disc_table_mutex)(void *sub); + void *(*_bt_mesh_ext_sub_get_disc_table_entries)(void *sub); + uint8_t (*_bt_mesh_ext_sub_get_fwd_table_max_ford_entries)(void *sub); + void (*_bt_mesh_ext_sub_set_fwd_table_max_ford_entries)(void *sub, uint8_t max_ford_entries); + uint8_t (*_bt_mesh_ext_sub_get_fwd_table_max_deps_nodes)(void *sub); + void (*_bt_mesh_ext_sub_set_fwd_table_max_deps_nodes)(void *sub, uint8_t max_deps_nodes); + uint16_t (*_bt_mesh_ext_sub_get_fwd_table_update_id)(void *sub); + void (*_bt_mesh_ext_sub_set_fwd_table_update_id)(void *sub, uint16_t update_id); + void (*_bt_mesh_ext_sub_inc_fwd_table_update_id)(void *sub); + void *(*_bt_mesh_ext_sub_get_fwd_table_mutex)(void *sub); + void *(*_bt_mesh_ext_sub_get_fwd_table_entries)(void *sub); + uint8_t (*_bt_mesh_ext_sub_get_wanted_lanes)(void *sub); + void (*_bt_mesh_ext_sub_set_wanted_lanes)(void *sub, uint8_t wanted_lanes); + uint8_t (*_bt_mesh_ext_sub_get_unicast_echo_interval)(void *sub); + void (*_bt_mesh_ext_sub_set_unicast_echo_interval)(void *sub, uint8_t unicast_echo_interval); + uint8_t (*_bt_mesh_ext_sub_get_multicast_echo_interval)(void *sub); + void (*_bt_mesh_ext_sub_set_multicast_echo_interval)(void *sub, uint8_t multicast_echo_interval); +/* CONFIG_BLE_MESH_DF_SRV */ + +/* CONFIG_BLE_MESH_RPR_CLI */ + int (*_bt_mesh_ext_rpr_cli_pdu_send)(void *link, uint8_t type); + int (*_bt_mesh_ext_rpr_cli_recv_pub_key_outbound_report)(void *link); + int (*_bt_mesh_ext_rpr_cli_pdu_recv)(void *link, uint8_t type, struct net_buf_simple *buf); + void *(*_bt_mesh_ext_rpr_cli_get_rpr_link)(uint8_t index); +/* CONFIG_BLE_MESH_RPR_CLI */ + +/* CONFIG_BLE_MESH_RPR_SRV */ + void (*_bt_mesh_ext_rpr_srv_reset_prov_link)(void *link, uint8_t reason); + int (*_bt_mesh_ext_rpr_srv_nppi_pdu_recv)(uint8_t type, const uint8_t *data); + int (*_bt_mesh_ext_rpr_srv_set_waiting_prov_link)(void* link, bt_mesh_addr_t *addr); +/* CONFIG_BLE_MESH_RPR_SRV */ + +/* CONFIG_BLE_MESH_PRIVATE_BEACON */ + uint8_t *(*_bt_mesh_ext_net_get_sub_mpb_rand)(uint8_t index); + uint32_t (*_bt_mesh_ext_sub_get_mpb_sent)(void *sub); + void (*_bt_mesh_ext_sub_set_mpb_sent)(void *sub, uint32_t mpb_sent); + uint8_t (*_bt_mesh_ext_sub_get_mpb_last)(void *sub); + void (*_bt_mesh_ext_sub_set_mpb_last)(void *sub, uint8_t mpb_last); + uint8_t (*_bt_mesh_ext_sub_get_mpb_cur)(void *sub); + void (*_bt_mesh_ext_sub_set_mpb_cur)(void *sub, uint8_t mpb_cur); + void (*_bt_mesh_ext_sub_inc_mpb_cur)(void *sub); + uint8_t (*_bt_mesh_ext_sub_get_mpb_flags_last)(void *sub); + void (*_bt_mesh_ext_sub_set_mpb_flags_last)(void *sub, uint8_t mpb_flags_last); + 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 */ + +/* CONFIG_BLE_MESH_BRC_SRV */ + 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); +/* CONFIG_BLE_MESH_BRC_SRV */ + +/* CONFIG_BLE_MESH_AGG_CLI */ + void (*_bt_mesh_ext_agg_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_AGG_CLI */ + +/* CONFIG_BLE_MESH_AGG_SRV */ + void (*_bt_mesh_ext_agg_server_cb_evt_to_btc)(uint8_t event, void *model, void *ctx, + const void *val, size_t len); +/* CONFIG_BLE_MESH_AGG_SRV */ + +/* CONFIG_BLE_MESH_BRC_CLI */ + void (*_bt_mesh_ext_brc_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_BRC_CLI */ + +/* CONFIG_BLE_MESH_BRC_SRV */ + void (*_bt_mesh_ext_brc_server_cb_evt_to_btc)(uint8_t event, void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_BRC_SRV */ + +/* CONFIG_BLE_MESH_DF_CLI */ + void (*_bt_mesh_ext_df_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_DF_CLI */ + +/* CONFIG_BLE_MESH_DF_SRV */ + void (*_bt_mesh_ext_df_server_cb_evt_to_btc)(uint8_t event, void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_DF_SRV */ + +/* CONFIG_BLE_MESH_LCD_CLI */ + void (*_bt_mesh_ext_lcd_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const void *val, size_t len); +/* CONFIG_BLE_MESH_LCD_CLI */ + +/* CONFIG_BLE_MESH_ODP_CLI */ + void (*_bt_mesh_ext_odp_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_ODP_CLI */ + +/* CONFIG_BLE_MESH_PRB_CLI */ + void (*_bt_mesh_ext_prb_client_cb_evt_to_btc)(uint32_t opcode, uint8_t evt_type, + void *model, void *ctx, + const uint8_t *val, uint16_t len); +/* CONFIG_BLE_MESH_PRB_CLI */ + +/* CONFIG_BLE_MESH_RPR_CLI */ + void (*_btc_ble_mesh_ext_rpr_client_link_close_cb)(void *model, uint16_t rpr_srv_addr, + uint8_t reason); + + void (*_btc_ble_mesh_ext_rpr_client_prov_comp_cb)(void *model, uint16_t rpr_srv_addr, + uint8_t nppi, uint16_t index, + uint8_t uuid[16], uint16_t unicast_addr, + uint8_t element_num, uint16_t net_idx); + + void (*_bt_mesh_ext_rpr_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const void *val, size_t len); +/* CONFIG_BLE_MESH_RPR_CLI */ + +/* CONFIG_BLE_MESH_RPR_SRV */ + void (*_bt_mesh_ext_rpr_server_cb_evt_to_btc)(uint8_t event, const void *val, size_t len); +/* CONFIG_BLE_MESH_RPR_SRV */ + +/* CONFIG_BLE_MESH_SAR_CLI */ + void (*_bt_mesh_ext_sar_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_SAR_CLI */ + +/* CONFIG_BLE_MESH_SRPL_CLI */ + void (*_bt_mesh_ext_srpl_client_cb_evt_to_btc)(uint32_t opcode, uint8_t event, + void *model, void *ctx, + const uint8_t *val, size_t len); +/* CONFIG_BLE_MESH_SRPL_CLI */ + +/* CONFIG_BLE_MESH_MBT_CLI */ + void (*_bt_mesh_ext_mbt_client_cb_evt_to_btc)(uint8_t event, uint8_t result, void *model); +/* CONFIG_BLE_MESH_MBT_CLI */ + +/* CONFIG_BLE_MESH_MBT_SRV */ + void (*_bt_mesh_ext_mbt_server_cb_evt_to_btc)(uint8_t event, void *model, void *ctx); +/* CONFIG_BLE_MESH_MBT_SRV */ +} bt_mesh_ext_funcs_t; + +static const bt_mesh_ext_funcs_t bt_mesh_ext_func = { +/* CONFIG_BLE_MESH_NODE */ + ._bt_mesh_ext_prov_node_next_xact_id = bt_mesh_ext_prov_node_next_xact_id, + ._bt_mesh_ext_prov_node_get_link = bt_mesh_ext_prov_node_get_link, + ._bt_mesh_ext_prov_node_close_link = bt_mesh_ext_prov_node_close_link, + ._bt_mesh_ext_prov_node_get_uuid = bt_mesh_ext_prov_node_get_uuid, + ._bt_mesh_ext_prov_node_get_oob_info = bt_mesh_ext_prov_node_get_oob_info, + ._bt_mesh_ext_prov_node_get_uri = bt_mesh_ext_prov_node_get_uri, +/* CONFIG_BLE_MESH_NODE */ + +/* CONFIG_BLE_MESH_PROVISIONER */ + ._bt_mesh_ext_prov_pvnr_next_xact_id = bt_mesh_ext_prov_pvnr_next_xact_id, + ._bt_mesh_ext_prov_pvnr_get_link = bt_mesh_ext_prov_pvnr_get_link, + ._bt_mesh_ext_prov_pvnr_get_link_count = bt_mesh_ext_prov_pvnr_get_link_count, + ._bt_mesh_ext_prov_pvnr_send_invite = bt_mesh_ext_prov_pvnr_send_invite, + ._bt_mesh_ext_prov_pvnr_close_link = bt_mesh_ext_prov_pvnr_close_link, + ._bt_mesh_ext_pvnr_get_node_with_addr = bt_mesh_ext_pvnr_get_node_with_addr, +/* CONFIG_BLE_MESH_CERT_BASED_PROV */ + ._bt_mesh_ext_pvnr_records_list_get_cb = bt_mesh_ext_pvnr_records_list_get_cb, + ._bt_mesh_ext_pvnr_records_recv_comp_cb = bt_mesh_ext_pvnr_records_recv_comp_cb, + ._bt_mesh_ext_prov_link_get_record_id_expect = bt_mesh_ext_prov_link_get_record_id_expect, + ._bt_mesh_ext_prov_link_set_record_id_expect = bt_mesh_ext_prov_link_set_record_id_expect, + ._bt_mesh_ext_prov_link_get_offset_expect = bt_mesh_ext_prov_link_get_offset_expect, + ._bt_mesh_ext_prov_link_set_offset_expect = bt_mesh_ext_prov_link_set_offset_expect, + ._bt_mesh_ext_prov_link_get_max_size = bt_mesh_ext_prov_link_get_max_size, + ._bt_mesh_ext_prov_link_set_max_size = bt_mesh_ext_prov_link_set_max_size, + ._bt_mesh_ext_prov_link_get_record = bt_mesh_ext_prov_link_get_record, + ._bt_mesh_ext_prov_link_alloc_record = bt_mesh_ext_prov_link_alloc_record, +/* CONFIG_BLE_MESH_CERT_BASED_PROV */ + ._bt_mesh_ext_pvnr_get_node_uuid = bt_mesh_ext_pvnr_get_node_uuid, + ._bt_mesh_ext_prov_link_get_uuid = bt_mesh_ext_prov_link_get_uuid, + ._bt_mesh_ext_prov_link_get_elem_num = bt_mesh_ext_prov_link_get_elem_num, + ._bt_mesh_ext_prov_link_get_unicast_addr = bt_mesh_ext_prov_link_get_unicast_addr, +/* CONFIG_BLE_MESH_PROVISIONER */ + +/* CONFIG_BLE_MESH_PB_GATT */ + ._bt_mesh_ext_prov_link_get_conn = bt_mesh_ext_prov_link_get_conn, + ._bt_mesh_ext_prov_link_pb_gatt_exist = bt_mesh_ext_prov_link_pb_gatt_exist, + ._bt_mesh_ext_prov_link_pb_gatt_send = bt_mesh_ext_prov_link_pb_gatt_send, +/* CONFIG_BLE_MESH_PB_GATT */ + +/* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + ._bt_mesh_ext_get_device_name = bt_mesh_ext_get_device_name, +/* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + +/* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + ._bt_mesh_ext_proxy_server_get_all_client_type = bt_mesh_ext_proxy_server_get_all_client_type, + ._bt_mesh_ext_proxy_server_segment_send = bt_mesh_ext_proxy_server_segment_send, + ._bt_mesh_ext_proxy_server_find_client_by_addr = bt_mesh_ext_proxy_server_find_client_by_addr, +/* CONFIG_BLE_MESH_PRB_SRV */ + ._bt_mesh_ext_proxy_server_update_net_id_rand_stop = bt_mesh_ext_proxy_server_update_net_id_rand_stop, +/* CONFIG_BLE_MESH_PRB_SRV */ + ._bt_mesh_ext_proxy_server_get_client = bt_mesh_ext_proxy_server_get_client, + ._bt_mesh_ext_proxy_server_get_client_count = bt_mesh_ext_proxy_server_get_client_count, +/* CONFIG_BLE_MESH_PRB_SRV */ + ._bt_mesh_ext_proxy_server_update_net_id_rand = bt_mesh_ext_proxy_server_update_net_id_rand, + ._bt_mesh_ext_proxy_server_is_node_id_enable = bt_mesh_ext_proxy_server_is_node_id_enable, + ._bt_mesh_ext_proxy_server_private_identity_start = bt_mesh_ext_proxy_server_private_identity_start, + ._bt_mesh_ext_proxy_server_private_identity_stop = bt_mesh_ext_proxy_server_private_identity_stop, +/* CONFIG_BLE_MESH_PRB_SRV */ + ._bt_mesh_ext_proxy_server_get_filter_type = bt_mesh_ext_proxy_server_get_filter_type, + ._bt_mesh_ext_proxy_server_get_filter_count = bt_mesh_ext_proxy_server_get_filter_count, + ._bt_mesh_ext_proxy_server_get_filter_size = bt_mesh_ext_proxy_server_get_filter_size, + ._bt_mesh_ext_proxy_server_get_filter_addr = bt_mesh_ext_proxy_server_get_filter_addr, + ._bt_mesh_ext_proxy_server_filter_is_client = bt_mesh_ext_proxy_server_filter_is_client, + ._bt_mesh_ext_proxy_server_get_client_type = bt_mesh_ext_proxy_server_get_client_type, + ._bt_mesh_ext_proxy_server_is_proxy_msg_recv = bt_mesh_ext_proxy_server_is_proxy_msg_recv, + ._bt_mesh_ext_proxy_server_get_conn = bt_mesh_ext_proxy_server_get_conn, + ._bt_mesh_ext_proxy_server_set_client_type = bt_mesh_ext_proxy_server_set_client_type, + ._bt_mesh_ext_proxy_server_set_msg_recv = bt_mesh_ext_proxy_server_set_msg_recv, +/* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + +/* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + ._bt_mesh_ext_proxy_client_beacon_send = bt_mesh_ext_proxy_client_beacon_send, + ._bt_mesh_ext_proxy_client_get_opcode = bt_mesh_ext_proxy_client_get_opcode, + ._bt_mesh_ext_proxy_client_get_use_directed = bt_mesh_ext_proxy_client_get_use_directed, + ._bt_mesh_ext_proxy_client_get_client_uar = bt_mesh_ext_proxy_client_get_client_uar, +/* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + +/* CONFIG_BLE_MESH_FRIEND */ + ._bt_mesh_ext_frnd_get_lpn = bt_mesh_ext_frnd_get_lpn, + ._bt_mesh_ext_frnd_get_num_elem = bt_mesh_ext_frnd_get_num_elem, + ._bt_mesh_ext_frnd_is_valid = bt_mesh_ext_frnd_is_valid, + ._bt_mesh_ext_frnd_is_established = bt_mesh_ext_frnd_is_established, + ._bt_mesh_ext_frnd_get_net_idx = bt_mesh_ext_frnd_get_net_idx, + ._bt_mesh_ext_frnd_get_sub_list_count = bt_mesh_ext_frnd_get_sub_list_count, + ._bt_mesh_ext_frnd_get_sub_list_size = bt_mesh_ext_frnd_get_sub_list_size, + ._bt_mesh_ext_frnd_get_sub_addr = bt_mesh_ext_frnd_get_sub_addr, + ._bt_mesh_ext_net_get_frnd_count = bt_mesh_ext_net_get_frnd_count, + ._bt_mesh_ext_net_get_frnd = bt_mesh_ext_net_get_frnd, + ._bt_mesh_ext_friend_match = bt_mesh_ext_friend_match, + ._bt_mesh_ext_friend_unicast_match = bt_mesh_ext_friend_unicast_match, + ._bt_mesh_ext_friend_find = bt_mesh_ext_friend_find, + ._bt_mesh_ext_friend_clear_net_idx = bt_mesh_ext_friend_clear_net_idx, +/* CONFIG_BLE_MESH_FRIEND */ + +/* CONFIG_BLE_MESH_LOW_POWER */ + ._bt_mesh_ext_lpn_match = bt_mesh_ext_lpn_match, +/* CONFIG_BLE_MESH_LOW_POWER */ + +/* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ + ._bt_mesh_ext_update_exceptional_list = bt_mesh_ext_update_exceptional_list, +/* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ +/* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ + ._bt_mesh_ext_unprov_dev_info_query = bt_mesh_ext_unprov_dev_info_query, +/* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ + +/* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + ._bt_mesh_ext_gattc_conn_create = bt_mesh_ext_gattc_conn_create, + ._bt_mesh_ext_gattc_disconnect = bt_mesh_ext_gattc_disconnect, +/* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + +/* CONFIG_BLE_MESH_SETTINGS */ + ._bt_mesh_ext_store_dkca = bt_mesh_ext_store_dkca, + ._bt_mesh_ext_clear_dkca = bt_mesh_ext_clear_dkca, + ._bt_mesh_ext_clear_rpl_single = bt_mesh_ext_clear_rpl_single, + ._bt_mesh_ext_store_net = bt_mesh_ext_store_net, + ._bt_mesh_ext_store_seq = bt_mesh_ext_store_seq, + ._bt_mesh_ext_get_core_settings_item = bt_mesh_ext_get_core_settings_item, + ._bt_mesh_ext_is_settings_item_exist = bt_mesh_ext_is_settings_item_exist, + ._bt_mesh_ext_add_core_settings_item = bt_mesh_ext_add_core_settings_item, + ._bt_mesh_ext_remove_core_settings_item = bt_mesh_ext_remove_core_settings_item, + ._bt_mesh_ext_save_core_settings = bt_mesh_ext_save_core_settings, + ._bt_mesh_ext_erase_core_settings = bt_mesh_ext_erase_core_settings, +/* CONFIG_BLE_MESH_SETTINGS */ + +/* CONFIG_BLE_MESH_DF_SRV */ + ._bt_mesh_ext_model_get_pub_directed_pub_policy = bt_mesh_ext_model_get_pub_directed_pub_policy, + ._bt_mesh_ext_model_set_pub_directed_pub_policy = bt_mesh_ext_model_set_pub_directed_pub_policy, + ._bt_mesh_ext_sub_get_keys_direct_nid = bt_mesh_ext_sub_get_keys_direct_nid, + ._bt_mesh_ext_sub_get_keys_direct_enc = bt_mesh_ext_sub_get_keys_direct_enc, + ._bt_mesh_ext_sub_get_keys_direct_privacy = bt_mesh_ext_sub_get_keys_direct_privacy, + ._bt_mesh_ext_sub_get_directed_forwarding = bt_mesh_ext_sub_get_directed_forwarding, + ._bt_mesh_ext_sub_set_directed_forwarding = bt_mesh_ext_sub_set_directed_forwarding, + ._bt_mesh_ext_sub_get_directed_relay = bt_mesh_ext_sub_get_directed_relay, + ._bt_mesh_ext_sub_set_directed_relay = bt_mesh_ext_sub_set_directed_relay, + ._bt_mesh_ext_sub_get_directed_proxy = bt_mesh_ext_sub_get_directed_proxy, + ._bt_mesh_ext_sub_set_directed_proxy = bt_mesh_ext_sub_set_directed_proxy, + ._bt_mesh_ext_sub_get_directed_proxy_use_default = bt_mesh_ext_sub_get_directed_proxy_use_default, + ._bt_mesh_ext_sub_set_directed_proxy_use_default = bt_mesh_ext_sub_set_directed_proxy_use_default, + ._bt_mesh_ext_sub_get_directed_friend = bt_mesh_ext_sub_get_directed_friend, + ._bt_mesh_ext_sub_set_directed_friend = bt_mesh_ext_sub_set_directed_friend, + ._bt_mesh_ext_sub_get_use_directed = bt_mesh_ext_sub_get_use_directed, + ._bt_mesh_ext_sub_set_use_directed = bt_mesh_ext_sub_set_use_directed, + ._bt_mesh_ext_sub_get_proxy_client_uar = bt_mesh_ext_sub_get_proxy_client_uar, + ._bt_mesh_ext_sub_get_proxy_client_uar_len_present = bt_mesh_ext_sub_get_proxy_client_uar_len_present, + ._bt_mesh_ext_sub_set_proxy_client_uar_len_present = bt_mesh_ext_sub_set_proxy_client_uar_len_present, + ._bt_mesh_ext_sub_get_proxy_client_uar_range_start = bt_mesh_ext_sub_get_proxy_client_uar_range_start, + ._bt_mesh_ext_sub_set_proxy_client_uar_range_start = bt_mesh_ext_sub_set_proxy_client_uar_range_start, + ._bt_mesh_ext_sub_get_proxy_client_uar_range_length = bt_mesh_ext_sub_get_proxy_client_uar_range_length, + ._bt_mesh_ext_sub_set_proxy_client_uar_range_length = bt_mesh_ext_sub_set_proxy_client_uar_range_length, + ._bt_mesh_ext_sub_get_path_metric_type = bt_mesh_ext_sub_get_path_metric_type, + ._bt_mesh_ext_sub_set_path_metric_type = bt_mesh_ext_sub_set_path_metric_type, + ._bt_mesh_ext_sub_get_path_lifetime_type = bt_mesh_ext_sub_get_path_lifetime_type, + ._bt_mesh_ext_sub_set_path_lifetime_type = bt_mesh_ext_sub_set_path_lifetime_type, + ._bt_mesh_ext_sub_get_two_way_path = bt_mesh_ext_sub_get_two_way_path, + ._bt_mesh_ext_sub_set_two_way_path = bt_mesh_ext_sub_set_two_way_path, + ._bt_mesh_ext_sub_get_forward_number = bt_mesh_ext_sub_get_forward_number, + ._bt_mesh_ext_sub_set_forward_number = bt_mesh_ext_sub_set_forward_number, + ._bt_mesh_ext_sub_get_disc_table_max_disc_entries = bt_mesh_ext_sub_get_disc_table_max_disc_entries, + ._bt_mesh_ext_sub_set_disc_table_max_disc_entries = bt_mesh_ext_sub_set_disc_table_max_disc_entries, + ._bt_mesh_ext_sub_get_disc_table_max_concurr_init = bt_mesh_ext_sub_get_disc_table_max_concurr_init, + ._bt_mesh_ext_sub_set_disc_table_max_concurr_init = bt_mesh_ext_sub_set_disc_table_max_concurr_init, + ._bt_mesh_ext_sub_get_disc_table_concurr_init = bt_mesh_ext_sub_get_disc_table_concurr_init, + ._bt_mesh_ext_sub_set_disc_table_concurr_init = bt_mesh_ext_sub_set_disc_table_concurr_init, + ._bt_mesh_ext_sub_inc_disc_table_concurr_init = bt_mesh_ext_sub_inc_disc_table_concurr_init, + ._bt_mesh_ext_sub_dec_disc_table_concurr_init = bt_mesh_ext_sub_dec_disc_table_concurr_init, + ._bt_mesh_ext_sub_get_disc_table_mutex = bt_mesh_ext_sub_get_disc_table_mutex, + ._bt_mesh_ext_sub_get_disc_table_entries = bt_mesh_ext_sub_get_disc_table_entries, + ._bt_mesh_ext_sub_get_fwd_table_max_ford_entries = bt_mesh_ext_sub_get_fwd_table_max_ford_entries, + ._bt_mesh_ext_sub_set_fwd_table_max_ford_entries = bt_mesh_ext_sub_set_fwd_table_max_ford_entries, + ._bt_mesh_ext_sub_get_fwd_table_max_deps_nodes = bt_mesh_ext_sub_get_fwd_table_max_deps_nodes, + ._bt_mesh_ext_sub_set_fwd_table_max_deps_nodes = bt_mesh_ext_sub_set_fwd_table_max_deps_nodes, + ._bt_mesh_ext_sub_get_fwd_table_update_id = bt_mesh_ext_sub_get_fwd_table_update_id, + ._bt_mesh_ext_sub_set_fwd_table_update_id = bt_mesh_ext_sub_set_fwd_table_update_id, + ._bt_mesh_ext_sub_inc_fwd_table_update_id = bt_mesh_ext_sub_inc_fwd_table_update_id, + ._bt_mesh_ext_sub_get_fwd_table_mutex = bt_mesh_ext_sub_get_fwd_table_mutex, + ._bt_mesh_ext_sub_get_fwd_table_entries = bt_mesh_ext_sub_get_fwd_table_entries, + ._bt_mesh_ext_sub_get_wanted_lanes = bt_mesh_ext_sub_get_wanted_lanes, + ._bt_mesh_ext_sub_set_wanted_lanes = bt_mesh_ext_sub_set_wanted_lanes, + ._bt_mesh_ext_sub_get_unicast_echo_interval = bt_mesh_ext_sub_get_unicast_echo_interval, + ._bt_mesh_ext_sub_set_unicast_echo_interval = bt_mesh_ext_sub_set_unicast_echo_interval, + ._bt_mesh_ext_sub_get_multicast_echo_interval = bt_mesh_ext_sub_get_multicast_echo_interval, + ._bt_mesh_ext_sub_set_multicast_echo_interval = bt_mesh_ext_sub_set_multicast_echo_interval, +/* CONFIG_BLE_MESH_DF_SRV */ + +/* CONFIG_BLE_MESH_RPR_CLI */ + ._bt_mesh_ext_rpr_cli_pdu_send = bt_mesh_ext_rpr_cli_pdu_send, + ._bt_mesh_ext_rpr_cli_recv_pub_key_outbound_report = bt_mesh_ext_rpr_cli_recv_pub_key_outbound_report, + ._bt_mesh_ext_rpr_cli_pdu_recv = bt_mesh_ext_rpr_cli_pdu_recv, + ._bt_mesh_ext_rpr_cli_get_rpr_link = bt_mesh_ext_rpr_cli_get_rpr_link, +/* CONFIG_BLE_MESH_RPR_CLI */ + +/* CONFIG_BLE_MESH_RPR_SRV */ + ._bt_mesh_ext_rpr_srv_reset_prov_link = bt_mesh_ext_rpr_srv_reset_prov_link, + ._bt_mesh_ext_rpr_srv_nppi_pdu_recv = bt_mesh_ext_rpr_srv_nppi_pdu_recv, +/* (CONFIG_BLE_MESH_GATT_PROXY_CLIENT && CONFIG_BLE_MESH_PB_GATT) */ + ._bt_mesh_ext_rpr_srv_set_waiting_prov_link = bt_mesh_ext_rpr_srv_set_waiting_prov_link, +/* (CONFIG_BLE_MESH_GATT_PROXY_CLIENT && CONFIG_BLE_MESH_PB_GATT) */ +/* CONFIG_BLE_MESH_RPR_SRV */ + +/* CONFIG_BLE_MESH_PRIVATE_BEACON */ + ._bt_mesh_ext_net_get_sub_mpb_rand = bt_mesh_ext_net_get_sub_mpb_rand, + ._bt_mesh_ext_sub_get_mpb_sent = bt_mesh_ext_sub_get_mpb_sent, + ._bt_mesh_ext_sub_set_mpb_sent = bt_mesh_ext_sub_set_mpb_sent, + ._bt_mesh_ext_sub_get_mpb_last = bt_mesh_ext_sub_get_mpb_last, + ._bt_mesh_ext_sub_set_mpb_last = bt_mesh_ext_sub_set_mpb_last, + ._bt_mesh_ext_sub_get_mpb_cur = bt_mesh_ext_sub_get_mpb_cur, + ._bt_mesh_ext_sub_set_mpb_cur = bt_mesh_ext_sub_set_mpb_cur, + ._bt_mesh_ext_sub_inc_mpb_cur = bt_mesh_ext_sub_inc_mpb_cur, + ._bt_mesh_ext_sub_get_mpb_flags_last = bt_mesh_ext_sub_get_mpb_flags_last, + ._bt_mesh_ext_sub_set_mpb_flags_last = bt_mesh_ext_sub_set_mpb_flags_last, + ._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 */ + +/* CONFIG_BLE_MESH_BRC_SRV */ + ._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, +/* CONFIG_BLE_MESH_BRC_SRV */ + +/* CONFIG_BLE_MESH_AGG_CLI */ + ._bt_mesh_ext_agg_client_cb_evt_to_btc = bt_mesh_ext_agg_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_AGG_CLI */ +/* CONFIG_BLE_MESH_AGG_SRV */ + ._bt_mesh_ext_agg_server_cb_evt_to_btc = bt_mesh_ext_agg_server_cb_evt_to_btc, +/* CONFIG_BLE_MESH_AGG_SRV */ +/* CONFIG_BLE_MESH_BRC_CLI */ + ._bt_mesh_ext_brc_client_cb_evt_to_btc = bt_mesh_ext_brc_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_BRC_CLI */ +/* CONFIG_BLE_MESH_BRC_SRV */ + ._bt_mesh_ext_brc_server_cb_evt_to_btc = bt_mesh_ext_brc_server_cb_evt_to_btc, +/* CONFIG_BLE_MESH_BRC_SRV */ +/* CONFIG_BLE_MESH_DF_CLI */ + ._bt_mesh_ext_df_client_cb_evt_to_btc = bt_mesh_ext_df_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_DF_CLI */ +/* CONFIG_BLE_MESH_DF_SRV */ + ._bt_mesh_ext_df_server_cb_evt_to_btc = bt_mesh_ext_df_server_cb_evt_to_btc, +/* CONFIG_BLE_MESH_DF_SRV */ +/* CONFIG_BLE_MESH_LCD_CLI */ + ._bt_mesh_ext_lcd_client_cb_evt_to_btc = bt_mesh_ext_lcd_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_LCD_CLI */ +/* CONFIG_BLE_MESH_ODP_CLI */ + ._bt_mesh_ext_odp_client_cb_evt_to_btc = bt_mesh_ext_odp_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_ODP_CLI */ +/* CONFIG_BLE_MESH_PRB_CLI */ + ._bt_mesh_ext_prb_client_cb_evt_to_btc = bt_mesh_ext_prb_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_PRB_CLI */ +/* CONFIG_BLE_MESH_RPR_CLI */ + ._btc_ble_mesh_ext_rpr_client_link_close_cb = btc_ble_mesh_ext_rpr_client_link_close_cb, + ._btc_ble_mesh_ext_rpr_client_prov_comp_cb = btc_ble_mesh_ext_rpr_client_prov_comp_cb, + ._bt_mesh_ext_rpr_client_cb_evt_to_btc = bt_mesh_ext_rpr_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_RPR_CLI */ +/* CONFIG_BLE_MESH_RPR_SRV */ + ._bt_mesh_ext_rpr_server_cb_evt_to_btc = bt_mesh_ext_rpr_server_cb_evt_to_btc, +/* CONFIG_BLE_MESH_RPR_SRV */ +/* CONFIG_BLE_MESH_SAR_CLI */ + ._bt_mesh_ext_sar_client_cb_evt_to_btc = bt_mesh_ext_sar_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_SAR_CLI */ +/* CONFIG_BLE_MESH_SRPL_CLI */ + ._bt_mesh_ext_srpl_client_cb_evt_to_btc = bt_mesh_ext_srpl_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_SRPL_CLI */ +/* CONFIG_BLE_MESH_MBT_CLI */ + ._bt_mesh_ext_mbt_client_cb_evt_to_btc = bt_mesh_ext_mbt_client_cb_evt_to_btc, +/* CONFIG_BLE_MESH_MBT_CLI */ +/* CONFIG_BLE_MESH_MBT_SRV */ + ._bt_mesh_ext_mbt_server_cb_evt_to_btc = bt_mesh_ext_mbt_server_cb_evt_to_btc, +/* CONFIG_BLE_MESH_MBT_SRV */ +}; + +int bt_mesh_v11_ext_init(void) +{ + return bt_mesh_v11_init(&bt_mesh_ext_cfg, sizeof(bt_mesh_ext_cfg), + &bt_mesh_ext_func, sizeof(bt_mesh_ext_func)); +} 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 new file mode 100644 index 0000000000..ab87a87e67 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/utils.h @@ -0,0 +1,248 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_UTILS_H_ +#define _BLE_MESH_v11_UTILS_H_ + +#include +#include + +#include "mesh/buf.h" + +#include "net.h" +#include "prov_common.h" +#include "proxy_server.h" +#include "mesh/adapter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_mesh_v11_init(const void *cfg, size_t cfg_size, + const void *func, size_t func_size); + +int bt_mesh_v11_deinit(void); + +#define BLE_MESH_TAG_SEND_SEGMENTED BIT(0) +#define BLE_MESH_TAG_IMMUTABLE_CRED BIT(1) +#define BLE_MESH_TAG_USE_DIRECTED BIT(2) +#define BLE_MESH_TAG_RELAY BIT(3) +#define BLE_MESH_TAG_FRIENDSHIP BIT(4) + +bool bt_mesh_tag_send_segmented(uint8_t tag); + +bool bt_mesh_tag_immutable_cred(uint8_t tag); + +bool bt_mesh_tag_use_directed(uint8_t tag); + +bool bt_mesh_tag_relay(uint8_t tag); + +bool bt_mesh_tag_friendship(uint8_t tag); + +bool bt_mesh_uar_valid(void *uar); + +bool bt_mesh_addr_in_uar(void *uar, uint16_t addr); + +void bt_mesh_add_uar_be(struct net_buf_simple *buf, void *uar); + +struct bt_mesh_prov_link; + +void bt_mesh_prov_record_req(const uint8_t *data); + +void bt_mesh_prov_record_rsp(const uint8_t *data); + +void bt_mesh_prov_records_get(const uint8_t *data); + +void bt_mesh_prov_records_list(const uint8_t *data); + +int bt_mesh_node_cert_based_prov_init(void); + +void bt_mesh_node_cert_based_prov_deinit(void); + +void bt_mesh_pvnr_record_req(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf); + +void bt_mesh_pvnr_record_rsp(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf); + +void bt_mesh_pvnr_records_get(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf); + +void bt_mesh_pvnr_records_list(struct bt_mesh_prov_link *link, + struct net_buf_simple *buf); + +int bt_mesh_prov_salt_epa(const uint8_t conf_salt[32], + const uint8_t prov_rand[32], + const uint8_t dev_rand[32], + uint8_t prov_salt[16]); + +int bt_mesh_prov_conf_salt_epa(const uint8_t conf_inputs[145], uint8_t salt[32]); + +int bt_mesh_prov_conf_key_epa(const uint8_t dhkey[32], const uint8_t auth[32], + const uint8_t conf_salt[32], uint8_t conf_key[32]); + +int bt_mesh_prov_conf_epa(const uint8_t conf_key[32], const uint8_t rand[32], + uint8_t conf[32]); + +uint8_t bt_mesh_comp_page_check(uint8_t page, bool largest); + +int bt_mesh_get_comp_data(struct net_buf_simple *buf, uint8_t page, + uint16_t offset, bool full_element); + +int bt_mesh_private_beacon_key(const uint8_t net_key[16], uint8_t private_beacon_key[16]); + +void bt_mesh_directed_proxy_server_set_blacklist(void *client); + +int bt_mesh_directed_proxy_server_directed_proxy_caps_status_send(void *conn, void *sub); + +void bt_mesh_directed_proxy_server_connected(void *client); + +void bt_mesh_directed_proxy_server_directed_proxy_caps_send(void *sub, bool clear); + +void bt_mesh_directed_proxy_server_directed_proxy_ctrl_recv(void *client, void *rx, + struct net_buf_simple *buf); + +int bt_mesh_directed_proxy_server_solicitation(void *client, void *sub); + +int bt_mesh_directed_proxy_server_update_dep_node(void *sub, void *client, uint8_t type); + +int bt_mesh_directed_forwarding_node_solicitation(void *model, void *sub); + +int bt_mesh_directed_friend_solicitation(void *frnd, void *sub); + +int bt_mesh_directed_update_dependent_node(void *sub, uint8_t type, + uint16_t addr, uint8_t num_elem); + +int bt_mesh_directed_forwarding_ctl_recv(uint8_t ctl_op, void *rx, + struct net_buf_simple *buf); + +int bt_mesh_directed_forwarding_sub_init(void *sub); + +int bt_mesh_recovery_directed_forwarding_table(void *sub); + +int bt_mesh_clear_directed_forwarding_table_data(uint16_t net_idx); + +int bt_mesh_clear_all_directed_forwarding_table_data(void); + +void bt_mesh_store_directed_forwarding_table_data(uint16_t net_idx); + +int bt_mesh_power_up_create_path_origin_fsm(void *model); + +int bt_mesh_private_beacon_timer_init(void); + +int bt_mesh_private_beacon_timer_free(void); + +int bt_mesh_private_beacon_timer_submit(int32_t delay); + +int bt_mesh_private_beacon_timer_cancel(void); + +void bt_mesh_private_beacon_timer_reset(void); + +uint8_t bt_mesh_private_beacon_update_addr_type(const void *ad); + +void bt_mesh_private_beacon_update_random(void *sub); + +void bt_mesh_private_beacon_create(void *sub, struct net_buf_simple *buf); + +void bt_mesh_private_beacon_recv(struct net_buf_simple *buf); + +void bt_mesh_private_beacon_enable(void); + +void bt_mesh_private_beacon_disable(void); + +void bt_mesh_proxy_server_solic_recv(struct net_buf_simple *data, + const bt_mesh_addr_t *addr, + int8_t rssi); + +uint16_t bt_mesh_proxy_server_get_solic_adv_net_idx(void); + +int32_t bt_mesh_proxy_server_get_solic_adv_remaining(void); + +void bt_mesh_proxy_server_stop_solic_adv_priv_net_id(void); + +int bt_mesh_proxy_client_solic_send(uint16_t net_idx, uint16_t ssrc, uint16_t dst); + +void bt_mesh_create_proxy_solic_nonce(uint8_t nonce[13], const uint8_t *pdu, + uint32_t iv_index); + +int bt_mesh_proxy_solic_init(void); + +int bt_mesh_proxy_solic_deinit(void); + +void bt_mesh_sar_init(void); + +uint8_t bt_mesh_subnet_bridge_state_get(void); + +void bt_mesh_delete_netkey_in_bridge_table(uint16_t net_idx); + +bool bt_mesh_bridge_change_net_key(void *rx, const uint8_t **enc, + const uint8_t **priv, + uint8_t *nid, uint8_t cred); + +void bt_mesh_disable_directed_proxy_state(uint16_t net_idx); + +void bt_mesh_disable_directed_friend_state(uint16_t net_idx); + +uint8_t bt_mesh_direct_net_transmit_get(void); + +uint8_t bt_mesh_private_beacon_state_get(void); + +uint8_t bt_mesh_private_gatt_proxy_state_get(void); + +void bt_mesh_rpr_cli_prov_complete(void *link, uint16_t index, uint16_t net_idx); + +void bt_mesh_rpr_cli_node_addr_update(void *link); + +int bt_mesh_rpr_srv_unprov_beacon_recv(struct net_buf_simple *buf, + uint8_t adv_type, + const bt_mesh_addr_t *addr, + int8_t rssi); + +int bt_mesh_rpr_srv_extended_scan(struct net_buf_simple *buf, + const bt_mesh_addr_t *addr, + bool *rp_adv); + +int bt_mesh_rpr_srv_netkey_del(uint16_t del_idx); + +int bt_mesh_rpr_srv_recv_link_ack(uint8_t *data, bool is_uuid); + +int bt_mesh_rpr_srv_send_outbound_report(void *data, bool is_uuid); + +int bt_mesh_rpr_srv_send_pdu_report(uint8_t uuid[16], uint8_t type, + struct net_buf_simple *buf); + +int bt_mesh_rpr_srv_store_nppi_data(const uint8_t uuid[16], const uint8_t net_key[16], + uint16_t net_idx, uint8_t flags, uint32_t iv_index, + uint16_t addr, const uint8_t dev_key[16]); + +bool bt_mesh_rpr_srv_nppi_check(uint8_t nppi, uint8_t net_key[16], + uint16_t net_idx, uint32_t iv_index, + uint16_t addr, uint8_t *reason); + +bool bt_mesh_valid_security_cred(void *tx); + +void bt_mesh_choose_better_security_cred(void *tx); + +void bt_mesh_model_pub_use_directed(void *tx, uint8_t directed_pub_policy); + +void bt_mesh_is_directed_path_needed(void *tx); + +void bt_mesh_net_adv_xmit_update(void *tx); + +void bt_mesh_update_net_send_cred(void *tx, uint8_t *bearer); + +int bt_mesh_directed_decrypt(void *sub, const uint8_t *data, size_t data_len, + void *rx, struct net_buf_simple *buf); + +uint8_t bt_mesh_net_retrans_match(void *rx, uint8_t *cred, uint8_t *tag); + +bool bt_mesh_dev_key_ca_valid(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_UTILS_H_ */ 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 new file mode 100644 index 0000000000000000000000000000000000000000..7024f4a17d8425c71b14425c99b702131c7fcd0f GIT binary patch literal 667916 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�Iq%x79;3G=xZrDW769{Z)Q3nzdNiHE=Gzx)h04xi;vDjYl$ z&#@Hda|oJ*-$44T@aoxE9)ua^=fZq`z^{Z0kX{TQ>&a&}Tr0dD=}p3nzYWu)CkEUh z%$R=_z5|?w4?WcD4Yvu;MEZm<>;FArKL4Ogn00$WnC*R8m~HukFypM5<4)^`NS_zx z@3vneqd$AX@!Rf1*TdhDpClZEbfz%2qXw(u8$dy`r-TWS!Ol(bJKVby|l-&qPYrX@z1soED#v97)Es z@;RP)X&1-yGXtN~$nY$Ohpf}(Z=f~KJneNgms{*bi}{LMJ)5bMQ$Sv;I? zWS!Qa=q=F6IxP>%FlHNcvQ8^X^mfQ(ofdyz&S~-fnsbDC?tU&Aak}9rM=oSQ^r7fI z!m2M3eJ^yf)+d*`#J^oUz3`B=E%%7t2b~<50l=_T^nPL0za#p7=wxlUEI=wz)A =h-ehh2J)*}!Cu{sh(YYRxRc{eJ0G+J*PSN9`leIqm zq9;QqYkdxio(i3;_4&Q%Y0$|U|9#OHKqsrtjVRm2b(E}nwCI`8$y%SYsYBzl!&AkR zk33nIy#>Z|kub0MWQu<|{A68*v&EB#^h#m+c^=4Vtw35J%x8Wx&pH>%IE{0QczB&D zDC|X?8u1syPma78ZN*S0o=1>=RXnBekRvl)&jZw<@fy;%#Z!(vIr0+M^MrVIA$>}i z&pUsHjCxkUPuBel$59VLC#(Lh=vC0kIe>HsNmZ@VaKBc#gtD*7i1wJ`A0#?R`vi?pMj`=d}P%%LkpT>k;oIpdJpLtp1lp z_d_RZ{QaVH|4i06Z;2iQovd*_5S{xqvaSofUcl+jfKJx=?iW1(ogBH?T_$6xqphs_ zEb+v{L)Nm1q9;HnYuOa)DBFXwmkMWruQz-v8TH9TS+dU4P2%A-U_Muaad_?be&H=h z8-#g%_Zwuy$wC~m&eLy-=M;Fhi)Sf3WbLb6qGv-VYo9+SI*(Jx>gV_MoK`+`vd#;B z7f*dTbh7&261@;QS>yBC0sY0$$r|UF=%vuf8s|i`f&OynWSys{iCzJntn+2I=t1aY zoiEAM(VwjQ=fzV64_V7D61^HaS<7BQ9c2%oY>6

I)2k&Jrs7>%s+v_(9RA^o;+ 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 o~lTxhu5aFyXr zh8qkw8*Vqe%P^Ya3BkIcgR-AGd>rgN#pR_@9kY9sx!X{Gmf>8(g@(%wR~g=9xWRC< z;daBj4EGrBGkn1CA;W`)hYg3D{^5G2?Ftx9GMr{O({Q%o<%UZQ2MyO4t~cCdxXo~< z;cmmdhW8sDFnq-DQNup(SbL)k&oG=|IMr~v;iZQ24Hp}(FkEf8&hS>lErvS`cNylh z26TS)8$M|Gu;C%Y9vstXS-;^p!|{fb4KFa9WthM5)|iEc%MDi<-ej1+Pu8-{hT9GE zx47!*G0fk!s(!#Qe+#Pmpy6S|;l43XjNyRcB*STjGYw}OUT(P5aL{m#;d;aTotW0S z&2XpTZo|EX_ZuEC%-<1dO#T)~**9T~qYTe5oM1TBaJu28hVu;<8?G>1ZMe?xR>LiZ zc`v@!xy$fg!~KR28a`~8_fKmaPuLjy4aXUdH=JyEf#EE}xrPf3mm97!yvZ={x6`^c z8*Vqe%W#ij-q)pN4;VgVnD;`dXV`G~#4$a_aKLbq;WWdUhO-SXH(Y8sXt>5O@4e8v zH5ukT4XX401LbbRy@vUHxq1c+A2H1DkJaM~ALA&)GYlsfPBolvc&Xuh!^MUx3|AYj zGrZL>uPJLid7W38*JqXY8s>FR)p=b~nb!xEd0kK0gJWoAzu`E;@rIKPFEE^CIM;BY z;c~+~2iEEGJXV?Kkjgw~Q|9@SGS6+4c}}9ta|z`Gh7TDYG(2oLJYuYDjNyP`J`+Ua zry0&PoNbuTe^Gy_;h^Cf!}W&w9sw=eX1LREx8YvHd>)II9WZ>v@KM9Q$T5GE;TeV# z4D(qw8b96eQp5R%iw##8=I>!NPMzVchFc7G816E>*Koh#gN6?q9y08~LBH04&o)tx zGaPT2?^96E0>fE`a}5_7E;n3dc$47lErvS`^SK9FcCX=n!v_r?Hq7T3 zXju<_Q?Kkd9A}u%B~VYY;RS}X4Cfl=dttO}xnVwMK=nn7(Qb7s9|5sSlyxw&oG=|IMr~v;iZQ24Hp}(FkEf8&hS>lEr$7fcJ0G1!+Q<) z8$M|Gu;C%Y{O!5M^c#*d%-@`=hrc;j=5NlG`5SZPT*HNi%MJ7QkadF+*+SD z!<~k^4fh(}Z+O7)5yM9f`|$f;omQ0L8HN)Kry5Q-ywos%Q>`(J4ObYhHe6?TtKk;I z9frFM^EcEwt$xD?4IefNY(n_-Q))NsDxV#5`N z`Fmb1TW5Hy;TFRkhPw>!HQaCbpy9)YhYa)gw^|3k;W)$bWPE49A(?!>%L@!=8TQOw zciZY<(F&x&N;fT4sw^olnp<8LEU7Fi_sn&2!IG+=XKry(u*fra#kzG+*D}Mx=gdtN zldE~=u3Wo%b;%m|tAZtK))mbyTXW-Du~Y>acq~&I88qG;p<-Ji~Cj^}q$17h1W|)-cZF~|QVzKThzTG2h4rD2?YIsf7T2ygj4x4@Av@zZz8D`|q8%OL zF2wypqdC{d?5+5i>Ugr@$efCWoXSuyj;$78Fbv2 zkhk%o5RX2_!|C;CJo>fofSwM_+Xhq+ryw45rQ>56T#6i>XF$(_B9CV#u2JZq(`7kb z1~{(xBljId<9)?9&Rsco?b!hxk`<7;?EXJDHPsn&{^!n1c9p`2J1<$fC?rIu$o{zD zxIQ^piE*fevyR|xR8x2oHEyu;VBDxr%=X9Q9vys2@kz($pDq81K_U9i@OWC#k5LJ@ z-^=vpr}_UmJ^5AT_3z^4Nr?zeew%prV+@rkiJ zCdBxk8YW<={@2_t{^Kni;ST;&hLIn*?faC`|CDUkfq$yt|A2WDV%T-f^4|-eydL*< z;`-V6?SPj5+2t#ENb`SX;Bv*~>+c1R$8uePPm;n)WC?Prx@TcS)_R7=wanyZthur_`lQ(Wk@K3~uS;3n^vCuI?#M-6kD}ju z>Y!7H*v2q-+d)-`n<0!QTc1pjwqv|5AK6)k!w(d!C zh1hpI6_1OB&yB~gpm%ENWw=E1GKP{3EtRQu}dS|fN1o!Cuh8v#3uP%DeuK8IeU^R zXfMoN88i>>L|UhlpmTg#d}S3MoxG} zXjn!@bVlgJjEpJQ`|7vmOz~xeMl52No6 z%yfl}#Ol`5@v7GWpDaBp-vOV`lQr!c@73t#X>%gnUY@4otDW&~Zc*51H);Rb4o4Ht zy^G<0vhdQ7dnaEyvoEE*H7vuEu_ffOn4u*XYnj;FkL{e|iFzc^+39O|c5-KD&<($H zN(e-k({}|%*;QI2X1UNZKM=b;M8(rwxICioogJYrS7+?wv4sb7E&1CLk8@Z?L)+OR zy|5$H|5>-t8143IMX~D0V&ZysM|@iT4g9QYvbQ(nBkznz^_&%>n_nC8N4wkEyFAO>d4CP&eQfLLS<$h%r)Q$kjtxj4n!8@eygQ`nvFS zcScVh2=%O%4NOX+XVuEd&_>4>-V`V-l;t}u;>>kX7}*}}#}Y8b%~!h0p6GD2C-l)@j`Y2Vxw7$C=Z47@6+vuG{Ibc$F2lrWId^i!ya3vk zoE)tA!OWUxdpdu>RWSM4z>d)dg^!|ls$xpx2*7wkKGZHvMjQ8VVqm5=0$8|ir-&SH&TD!l4mr?8>1_U|0md0xn`^-vOMd2;bKwV zigo2K&pCK<);Z@d^oO3ZETt&yyv7OGo~*++1<|n=kEG3tofnqko#KYcNGwO6H_V%i zjoIbWhdGIB+N04@YzMnm^kiZ~<9p^=G<9J6XI+nf^GM; z^L9QT2S>`nX&K9;3>vU%%FGmRY({iMa^A+vGSjaLOc!6yGFsi(?*Gv>=+m}=&*&xx z+rR{mE@-~_$y+W)IX- zw`YoX_EPV@3-GeN(Om)dKQxW?G*2}2Wx744RwLqE4_QX)BKT7&G1d{#U?lsU3~q~_AYmB)L)ww?~kj^oa5~Kv|WK#S^HZO19{Uzeu@WG z;Q1GrvyZ*$7E75X>&N3$ykRL^;pd4kx(Zwv5&NO6=&ccBM*%O6F5Y202*5lY6|k&~ z@{Z7*EqA)p8r$=a(Lb}ikM5uRC%obDeB^!U1pgm&{_3Kod3FH$Nc+L9Ky6|*w$b6T zp;7G)N2`nIZn~#2d2eRV1I3I0hBCe(Uo z_VsGCFFIAzLqBQLr_WPa6y9tdslUB0x;|}(w`6d{Ssq5qoE32}!Yl>S75?zr%Mu>_ z)@ZRekDwTjF?nFQImeTq5_{E1Uuyll&3_v?A_o~ciB;_>*y3L=%f^btTagd*JpT2Q z7ln=;_D6iQ`Q4G~or@MCh}*0ciIqHm3LD*-*Cwu;{v=j2oR;al8TI7M3e9mgTNu^4 z%Pr?3*LQ6}` zIe1KD;)(n}Kb-%kdGY`JbJT}@U1(0rAiNh!u-eJtEiJzO?bx%&x6BJ<*G1LL3uHu} zl(G!FbARah%QBWtdUNgwR+{?;pU9Y#c*cDrXGPTCo;9UDbw_B)YfisDkJGKPkg~~T zGt15?TUfTNtf=gkRne>faI3eBX)})4qodZ&=w~u2%n|o@4qahW#1OQTx#X zcl_7f@y*lP#i_oqKaZ^VQMzmTo@-hi(Y#GS9IBivU|!NFMF!_vroSv+8d3Dn|4GFO!9O^KRtEM znXcN1BZmi1Xqwf2&4cIFC;B6wo`2gljT57)Uu=0Ws&R4Do;^`Je-sxxA)#@C$A7|W zr+61V=6U*!AOG~#BH7}h{DJ3Np6KzP((>?@t~Yvr+Rz_d^f2}f5&nqQtEbifhyOlz zLQgz$WZJ%JPiy1k2Oq%^*jv+X4ZGLV8a)M0`0~m=dhn63$$0;>H?}o8qVy4er2mwj zhc-?>xP5!egMn8Ug|%PZnCBg9OVd41hxL`AjT^Z2DSf1DQrSK2S4*23C$~mVe(aRl z2Tyhd93Zw{9sSspvw2qD{e7MD&^F^MKo8O*C5!aj6D!K%*~3Hr(6G54|CIF4ZS+sV zVOrzj*|Fa~78c<_N5ozlGP-!dn=--E_wBG*cxJ@n*^2^*mogzFcFROh$fc7l*Z;Ddz@F&u2aL zU}#_P{HM-;d=XmjIp25wQ`-30ONLTT4oSIsdP<8YW$`&FEg>n3Wg~*aZ5)PXwD6_3 zZpTRXB+8-tv`Z&0-V%1(wA*-|eOu^la(L&Ko7ECBT5fj;E||pfw($*BD*^uiZ|?rkY)z z1p-5P`6FQ=m>-_A!rOD*X<&iV7(2Y_J;CJ8p*MSu`NRFuEeRXBzbNwf#S^ceRG7ap?}uT|G;yt~vr4WF)=jMM#T2i~&gK+1V+z;f(w8h8 zdMcbX@n8_gHjAV^D-vt4U&Nl~bBT-mo+WLg*Akm?I5)*_GJ8y15X!RGDyXy1Dy z9$kj}wrkk1zl?aYLi}OVb8{}k`NRBq>3JKIuL`71EsMyx*1Kv;*b`Hqn24q4iO?se zBCwoHI(>__p_$F^=j@q*+OELG&Jt-*R+xXn)mu-}X<#dht8kZxFKN^31b0MqyqM;z zi|xDn{IJDMk>|%^r9Xed;--*mV*R)ba=sk?YXDr|tn*#(%WMDJqIaA*>m1kI@132I z`c}>DSDncJ`QiAF{>6V;4iIBS?pu{}W~W^B zR>o9%;_~@FAqW4zhOZ^(Y}`EAiIbHM1#c?$H=Y@na?h+tx~h_>O>)LJ1^iDV_dr}6 zHD}s9WkbeUr3o@kEHXG0dGwKEXGJ*u*wKjVoOd}_iR*92A=RufE@bVEu9Wx8vDR6# z-_85*BPWJ)-3tpd4#=HlZ3xR+>8Ast5)u?(}8f zyQOABAa9~v@2th;U9J%BRNViyiJMU~h*=S_`~8t$$07Xgi4QJo^hGuF`|?&#XpQl& z+IB|Y&$<@+XYBCd`q1u(uqZqSXkqWNFTdeGRis7S276j#qIXYRwQW}43tbCe!aQ}{ z=$ENwCv`21{Nb11=;;ZHip8_-uTK}bb*OaeHBsudb7olg1-M15`fzfxuVzD3@`ga# z!peo770W{AU+kaq!5Lm`7I%1)GXuLrGM0IB7KT0g9Qt+NBu`~Xc;4b+EdCR5inDKm z#KWeKE!6GhqQ5xDA`3m}w%FQ8zb_15&x$oC@uD3*b8J_enC2Xu#ojJE_S(erc?=is ziM>{?VXsJ>uSa!yy!!YzE_K_rBJo@l5A$@({!{aRc_-m`gI?aLO+3$;-mfBF3gcyU zbl~(%*V>x+dHfdl@m=1{`$ur0PEX=+tnZKT$2}a8+_W*heIxd>d4HV}XxfQsWt)XG)foHv&7kP?2p3nB(v^_Rra(YV;D|PJcQ7zkR z+=;EmQQU;)nB>fcohRcU>a+4C#?@Qjlgj9&(hDQ{UL3uS9mbmw)i8R(ba1|2&enZ) zb;hDIk2`O|!O!T<_`f)B`tM#ljrI11;o9kR-5cXNfy_Xym5v$hTAoM6rc7`fl#*DD zRY#X0)$VY#_K1VGt72WwcRpzmwTU6I37#{~9Esid(T>ox(6GOaxF_J)Z_JsDi+6RC zZ=1QI$deqvwsi<=a(A6ZyStqi|J>+qa=HEb6>TH!nH?bMqzNZttTHA8Y>blgii4jP3RLqi1FDO~`rchwDN* zdcy`sUh?8HXV@9rj&7mBxI<$dF?iw=w+z47RxUyPg;rrW^ep;)hU zI<`daR>zIz{>P@s**w)nbfh)LMW6TJ=;csuwzMDo(fnQtC!g)|z0|n%TfUdVJ~_re zA&|Q$5Wrf zela$(E99jx_~E=hqCLc&5_W*)k79AFzT~V4P9Ggt=ewt~&hgW=&P8K&-d8%hy;^{t z(G4AHeqUV9cSf=+hN>T3?Zcr3+Tj+jO}r2@P`3RwHA9c5$#Ee@;F}P4Ui{^zw0*cO zN7v!8GLN74QxnED^Rh5nllOl}dmp$gtNZ`|=H?a&?g|i*$m#}Bk#r%Mp|e6n!m>g# zqp|=21w$pkq@qUX5Q|R{TA^b_%!*1kbFQ&z4a}G;YF4heb!O?x2?B%eoty*F?VT;Ub>lYK&aa8`P2KAA;+Xzwb052jS;VakYkVwL0zaU2BzN zNM%s!PUmb?&Q@_Q>NXM8ew~E|&)Dgli^>5|Te5#d603%PpW<-Yu`}J2YTMwqkTU8o zf^>1*b!DO_{Ml%Um7Auk8v@<{hdC__r+;&A9|F z4Rx+=nb;cyf9Bdy8m&x6uCAOJmuThhEN5LT6OE~*qLT3 z@!#(BFP8uCx3O~5zShvL`t_BYLs$POXnnmY(O5aJ=47u2&wPeJ!4| zmExdDMr%EY)YN-MW5W8}$79_srNPbxr{F1hxa9Y)zbCE2#uXYc5Tt(B`H+lf=p?3c z|4IB)yukRL5wUHEUDLarlQ=>|H)Z2W-qXD&MUQC-L%=Z)xNtaw`Kb$rbY?U?pB5K0 z%2l%KBrd6BOvE9f^clFu>Zn=W^1ZAetc;}py9;#z%2oI2xO-Xg7a%daEbw|BR1Z}05bvt4Qm!8=O}(+a#ZrbK1oRZ!Q$ z?77~H!NWjTHMlV^vtcbp_l0S4!Pg1BVdW`ZLA`aS7N+^U*J~xNVd<`4KPC0l`|FWy z#hiEYsx0;@X36TY7v~ObVccg%Xbc;BEOcIUNER*->TYF0@nCqgbUpPz-mm~D-C}=6~40eci2B*PrrJ~|2%@V8M9%nH?+B7WnD#eTT<4Cr(#O} zqxTZ$g`Eib(qF6W z%TH!qfOS?M95J>uH1}uU;OcVyjELOe)cW9wH+ErP#>c4|Q&W>ycgA8@^6Vv^wA2P& zZxhkuw|F{tCOo@m%c!;bKnym-yr`y2Fa|6;nGl@X_KtCq3m3z1#58v5nOoa~IUa94 zg)8aYWH)<0eeo17JK$ze)5REw$~jPT|GgC68>7=E++ehos+h<4=LI3 zf9y-o$k_^Zlvq8ln!>!m$Ne@Q1-NJQW9lO&btwAPCvv7S`0&G&OO=bI_K6!WtNM>p zLcFLZtUe4+$(`2{=f#6^tJg=j#6{s*xz+2#Tf$OsS90|^JUx$j_ZyzmWgS87lM4s7 zxyuIMZ;}fg*;D5g%ku<0Z5!r4Z8LEtATDZ2VLMWtNA$)y_h&;_<3cEIg9eXSy?%tT z%)n*fQ9*bV!DM?U@i z9Ts_Y4?>tAm!BHL7L`UrL~T2JxSG-2zGR=zCy$(9(5)H1b6DioVWFMFu9njTW3VZq zCCF1h3=fatvhxFt&50}P5`1{T@ygsGEx!wDPOr|G?!G3-dnV3D&qPkj#ur?baM?G>I|!#-_Pj+FeOsctfws@J8V=-exDpgu%Zg|Yocn5~gy8HW|Z(RM{ZyQ=XjXepm?xP9b z-iJLXwZ8D>GeXXHCG~W=z3y>3%JfVKtB-agxP}HRI4^?h_}NJl9hReB9}%jL^bUmQ z9eU8?T*zze>6G1e$MiVHQsrqZ9Eio;ungCcI(ziKLr2fZghDAW7RUQ{dO8ZD&EjLI z!z$1#RH`*NT6S1VeDwZRD%yr#Ps1%9*OZ>i&Peb?4E;DIA=-OsOY-h7_<+#UcbsVZ zdzy5G!Tu9GDPtcyyLUE52hY4o$J2U34&pd;>`M^^3EeI2KN$O*yLYCicO=duePbM9 zoV#JVry&-C>zZH_NNZR;imW+PbBjLvUX~tiv?TLN%o#ZDJka@tF*rW8SNG_xVPn6F z3As!3zV|qxl&yz5HXxr~PdScbYW;!;SwXIZ_+bfi zJoWLz>c&L+lCV!4l9Ld92Tt}9&f@>6q5MC}jsJ7zRJR00)W=8e86D|;pgkd?HVpSh zu^+|I)cAJ7^oWG`2ydKsT-}D13DYARzexIMb5O#Zu)8MK&pD%IPWY$8PvqoyCWP%s ztn{QTdVIpHshz)W8~vj83bbf$VMGY8`T4bax33-=e}kYes<$E-Gn$6uKRs`2ar;^d zBk(dq-u55{qX#A)p!&jdhm76=PEi)HYJ$g3O1)kJ%Z(4jqZbn*fkSilT z0{0s;(mLYhW>nMHd0#Ae>PX$pQO`uX8&X|3B`{5v7xu?bW$?}mTlDEnoPqoMajw}8 zhM*tsH`cky_I5DDHSg}PalP8_YV5z=IJL;qoqMj?4xI8kT3nc{JO32XQP`K z_wye3H_s=%S9kP?Qgi=wydIc8G5yM|=`-VVoO5}c$m1;jKxSn6itd6%b$CEO#2aHA zEGUfX{FgyIPkl-bhjWu}VNV>w2XA`6a@WU4#iRwbegV&^@7FmeyGJhF=Fa-kZB?9o z|3sH7J%3`#q^+I*nmQ?EQan!HyRVN-xuiSg;<}W~?yc>QZP`|5>T2j`uN`;4Zt6Hc zk+JR8u*!Dahp1RCZS0My7_;`dw|y1WO;HVByEAs3OkcFJDW>;7?zEnSVeX?D?vQ`G zxAyq7yzXJ!(=+c4Yl`muhr1)*Td_#?z?b>=z-1p*GJkfvdb4&HgdHA-F_l?X%8r z_|K`)-o{l36Px*eLGrzhRvK0xKYV9=bkk$4Uo`Jt*_~7EzrTrrt0VqQj8djV$U=90 zOz5RJ&>8Kj4;e8w){RR#TVo<0L1llg)9V_S8)G~f$g;Y5sQ5$F8K^ZlT3*<^5>M7h zSKWi7>K=~Y(%4=1u&3?mwnqQZfAiP%k42(7|J`8-DQ<{M7=A8Bug;fziO9+Qn5Mrcge3K~Bn(MCHzQ%@#EhA#Nt64cau)`7 zzGN0O=57}(nxeAYZro1Gl54EI0)h*yi-u)S_Kw0~jW;|6Rb)nN9`f`hCp!NvZL~O~ z@uRk5CX`c)wrr)X9duL8zg#2OGYbzct>=GmgI< z$64Cqs?9@qA|BH>EF{#uIi%#K6Ct=V;dO5g9w)oTf$@fC5UK4aQWi#dndgY&kMktZgEHT*uv|D56Ar815tSR<>Bk@pUqD|v&xu`N6A$AV4> z<|#$mTCDMT38ie38zOR&*3Mh7D5)nS$~~`tVfdKZS8+Ci@qg^k-3^ZiVdYKmOr4yP zv=XOE^FA)dLjgle?&osHHI(zBa&}y5PwbSSn<7&S-7)s|Jb242 ztO;S*Dv?8Tn$?k#5OHhRyoB7+p41rkm{B;`57ImR;ZtjS(Y6HzM=pKI-Frn)A@=LT z7B4OswQ^pQ#R4DpUj#aoo0%vuoTUGdnA1-LTw z*k#QZM=VVA?3jV$o%DJZA$t0fn*1Q^ z4R*yOU-JLv!zt%+rTm&hPVL^5?HyZwF+KH-Q#g!i=t1yu)YtF|78H*POpnzSJFra+ zTy+@e2}{Ci|EQJ~3nT8pQ)zGGftPdc{$b^=ledNyWcVh8Rg7C(chg$m4L;n!nGlvf zZf#D2@7XAK)^Bk6qkXK!Goieht-&pM*Qg{^LKLAPV!Q-3H#<+Wb z>A&}es|s@Lgae)pkKm)G4XdAXH~h?HTBsh^;!d*O;9BhBw6YD+i&7lJto~3CS7Io$N^ZTBDbI8l)CUXcLr7ArW zrWL>S!4j9WaJ)FmH81#UTzdBhgP~vd-F@{5L9zQ6WEG;(8{dxEClTuouO1Isee7$D zz%yl072{UoRAKSLoIGDag0J)Kb5|tHalagtJKdErC#Z6INJ%NiorWf?JU*A5tIwtn zti2`vad6<8(7<}cF=s_W#QzNOj_|Esds$eWulhzDnB3;#4q)us8>2kEys_5WgCoMD zN$!R`*L1vM;J#{M!Q*R7-^PWo+}`_hDp%H(`3i3I&6^qB+4HiD^k%WKy&x+8k%Nln z8beK3%zr|XhAxQrW)z;8F*IUm|Fsz-WOwrHx{TUg=pG?_*26zgI8RA!bN5b0t39wG zX4aW4Bch&NAC)^cc=J%SIX024?PuV6qIY;pjC)?$aokf6F?DW=x)-km_kQX>sT>p+ zF5u($>SQfsn3#1J6f@*x)4RqA_Dx(G5B9&hnBLK)Jt4dfsuel+36hRq6V~?i*09)} zugBdKw`J$bk|W2P7JIM8;nwKUCo>RR|M8HI`5MCcuD6|cU|zJIGsi0qvGzrX-YEYC zCNDQjxiu_ekh~(G++6{F?dQUbhty>A^q4m|b+IdT zv2^E*?yTgQdjVrDfG+_^nY)PCjSZijqp-4HcT7wbXY*Rf(CG31`dhEUCOpZ08l0m*J;K z%a$!Q^RHP3XUi(fmM#jg_vMyUSKj5ju@JvMDrK|Ema^6xmfpT}*@~sU>#GZ^OLX3~ zB_+ir#m2|A%c^~vm(YAOYf6f+2*qmekIQ%c@}eSB_}lZc3d_m|$_&KLx-03;S$S}W>s5afAxU90I2({)*M?$;j(+%tWZ#G5M<@qSdp9XbRpbzA; zlQ`=&zq)Km$+G3}P+qvS#L^cnM@Jo)E9J_|7M8GtHN){&QdGL^v|43JMfqL+Ifcc8 zLdP%RqQj$E*uNY<#=ICmi91k8W3DW@V|htcH8zVubDeTaOh5Ej#4_wV`ODGwPcv_D z8&tBd4l2v}%d70gbhSDc?eN=i&b>QaYah$j9GI#_PxKjW&ls6^<%}6qeMv=?%c`oX zmn|!waP5^oY`+sGrhYH=dnx&;DXAByq^6{e^BKYU?Nz!6!e5^AlfL=0_>;ajTt72^ zddBtF&Awso%>3E2=FZHWKKuI1Qo^QZ%)*PT{<1_?+A(+9GlNUO# zsmJ1vx{n(E#(>8or5zaqn&Zz4P6gAR`c+6d(a&t8Bk)H*9DvTlA8qQ8a$?y!q|WnH z;6|_qf3#^r%87o+-@_mM{2D1kr_CowkvM+(k?OL11|E(-+MGnHKHW6NM4uk;<6!#y z5&rN>gX8B3Fq@8LJMqV5COel3#D>i0Z>WEQKm0Q>0CZUnS$xFe<6w=)g==G+7!SD^ z3F9eNUHEF~tm|jcIg9P~B4CZ^QyDxa>SX-Hu48|LrIR(bTP-fJcnMfzy93OLu~ma3 zz>JOGq0~OGMs1*zxxZkXUs*OM!8BuRL2$lSY}TS#B9C-P$GjOQm{?Hf;n&lmew zE&VkxcKME<%Wx%`6XPMLfF1u}E&CuiSM(3SKH(E!PAp4K05gUQ&^Y|fR{GfvM&j7; z8-yBvHye;T;wMLgS(e`;M0ifw_rY5BPhj01`@uzGb0r!|ZL-0-es5$0Vq$D$p7PMY z^L;_lOQ4s68Rwf|UG@`Tjlq2e3^36T`57?n`HekJjGufFnEw9=*7koNoDH4!@d#dh zj^Tn}qEE7J3%{~-vbNRBs-v!Ma6HPgu8+XnUg&=~I@oQ(RkFWvwps8JR>q6d2imSqU|Ve!9Cbk_SAm=k?+Kd3%`Z0YS_ZJ*zRQOsHPJz#br`gu?7 zg_&h+A6q(E^?zDAS?m4M(#c#G^z&~px{Xtp^DQ^9({G`39noecItf<2V{;9d_X-(X z0hp_RyqFyc6PK62k*(tue>Yoo@}& zA!|SXm8Fy8P?mMQ3r6Dj+zZxq`X{i)!0(5t{xP^r%3h5fqS{;o)^?i@&JvprFek=L zo&{#TpM$mDL*Of*b6GBAz?f)HX1&xWS~^+x>2tyA=LRspB|!hpmOYu{E&Z%h9etk6 zXTGUFZ|R%B38KFR)@|X>;9%&C?L$ld91O|P`E4z>34Q((%!%9AVXz)259JO~^iXgb znD+dJmezF*Sbbg#PJzuB2={?GF$S`($5ycRfgf8oWcDBWe;TYlp8@Of^L9($0oL*7 z0GJc&B5VIVtU8wqJRUamKN1c#hIp{nl>la&Fn)eROOHJ=z?|rxtYi2rFx!gu{B9N} z+K_cSU2N%OUB63JM{E^fjwg)mQPqX@TxPSSlevCb?-sDejCV(!iR+Qy+(P2`{6KZs zlXYzW%+kqhF8VxS>15R-*$FXm8Oge>jQ~S(^jJ$jAFTZ_UYPz9!5Z@zFek>G1m?P9 zJMep5oT!sk&jxGzUk9ci#xn=3>!MV2*0mVSiGIq#6=3?`59TBAwD|^%#PM?+%%On# zS#YTFM}l=-jAKQZSTFfvFzx4qeZu@!7Mqd!BbGgxhdLq9+bo@|eex+wCu_aGvUD<+ zoqo2fj%C~d=J-$jb+KWbec-JU&wX@=i8@*PWWDO}vkF`Q8~W)7>waw*-b2wg9}XS` zn=!EA_oX!c%fOuIpRC8>?^`-q>-|7=)XVQb>2~VHput)6KbivwCi*0^Z5i8CODC(( z%TR86{;1uZeKOd}p`yMbPr>v}%}2Qb<<(!lK7jBN%FY%p;d$=c@GmQL1oz6z`{ zT&p&SAqRW|{4j>6RTtL2@d|WyUDo>^SmS&j%v~GxLtq`x!*KCO`>+?Renx{~>cl(- zOncUwY1wCixxG`r3(SejNLD{BmQJ1w8`|%-bh1zMgWxe>#(5Sh)iykb0brtkvbN#* zmQL0-^ntYv6V(Q7NM@EXWB}C9m0(DY|7@_X)7ve*91IsuY>$FDF&?tkwO)1h8Su5R zVO@U*YdaqT>;B?jY7ZMS_eZopY3XFu!`PWIv0k$F;j=BB%)00&60G}(STH2hhTs`u zGat;ZJ_a*aST;4_%SC?)tjDykfTxN6HJB5(5q=MX>yGs%_^28^(Km3+HWkc?_S1X= zW7ixo_iK!y5UhRpE-)vjU-<^w?FV2^)XCaD4}v*SC#(KAm=krfwp$yR6Lqq-+Y?}I zx2M6JXhXgN%w_BcYnvPbYv21Pm=l-ruy3GEV&Vt-KrHwS*l>B{!JO!y%v~7uG%ylJ zp90o>WhPkr=OW9d6g&y`jI9mKWv8D`Femya>pFT1tbKA1SmSvgtoCG{BhcqTODC)T zAF%rQ3e0w+JrBrr`wa(kVhm)pi2`$7FwPO+V6lk<&l0@|Om{3>46X*#|2{A$>g2It z>ZdGwHk2NJhJoE;@3nNi^z2OZL*}+gKO-%jta<`i{Um}hoI3XDmOWY9d7w1|3X8+`J6@cS~?+0^YTah_@(SN(8lP?tg4Y2xr6Rhp? zM=*++HV5lE{RGU3@%Mu{rqTZq@DMQL`AThsFB5$-I*hLCY3w|h7$^A>Fw5QnRzG)I zHe}WB0mIZOTWjg}t36^{1=eGvZI;ci)CLa7Iwt?l(#al)=S|h&llRfI-M#^949CF< zuxC4*j}F83-`X{%Xk($ zIVQFznK95OzpclKb&)mBR4|u?ao!51AM*dGy)fI{i4FQ}vH1|}6Fv!M{4AS}I&>Y) z1heU=-wqB2Gq$B*?dPk&TJJV6C&o!;e_*|zf%W>sQLy^|2CV0*XD1J|c_f$<{X~Pc zeKNti-?;@0*G@e1!Mbfe1m?sz$=Zg^s>3H4i4)teREIrTj|tzgbn-o7e+?TP6aACf z)NG&SmQF4d{XKB8@YL}GeIOUiiGIi&1|2_^z8oAbdYz?{!=STmAFyh zxo!oAh)oe#m%Rk6W8DUDsMvIXb$Oo#YkU3~to7~(pDF%719ReXk+tu+FB+)J1ExLW zj0AI{J^3s!yh!C1aqPvGOBR=OyD4ii8@)&0n@>e&{@|U%Z9Am#e6W^ zfi{c5+Wt$xY+mX=0wZz!w}B%?-wfu&ddUf3+W+3t$vp1}f&O=}`uQA8|J2XH;B&T= zO#-Tclsy3E#2CmM!Hi)QPFi)nKLXaWE#L^T=>T(LS+cgtW=kgz zg$?7}X6fX7=&WlP4#;&~WPo*@W`ebE+z;l&y2!dOTW{&)MA*>h%V3^^kdIq7WDKWH zJY%pCX`jCW3{%H{I#|cmQcEub=Stb_mc9ebVUTql1nWNQENp;WcIv~y!-SK->OTjp z{p3EdE_)qV+vhJ}?N=XzxqZ>+*_RH)906VdJp}q{OK$}081fKU<9QU!iS0@Dg6Z=q zODAWG{uvmv9s9q79|g0nAEW^=(GU4rF!eXVx}SXqtnvQ=+zcDmRWgMoOY<>zm2W-x!`-n&+je$Z7`diF^63~5ZifRPK<#(9L%~>!MYwV z1*`ulU^XNDR9X6RFgG{q&w)A7Ct26gPc5B10yeDcHA^R-CHlLTPL2`%GfO9{{eQr4 z=hS=5vOnvJf%qf9TJKn}+9!z(<4Fc{;&I@3@N_WsC8`TE3@+~r(2+RxZUWCihWd$g zh?v+8WIg5yn(oMse-D^r2>qvkBf%^?9n6U_WP;0;$U1pA*kFps zADLt1XyMsN*$&i;k)9{K3Mt!}dK=Ox;VnqHeNo?y^jzV7q#R4Bvk_Du31(lSJ_)Qg zIbf};0?g&5%_?xHaFfOBEN-)Sqs5ynhKuiUcVm0e{syG_EC};l2bkfyL*_q# zl+VujB>yB*KI`_r`0GKQ&v50S49mZbd^dJ32gRPx7V;UR;gbJ?^Ko$Zb16R@<@k&# z+nMFZA+OK(FmF%6*lT5CKHH4_FbJ)F9rAqc=Ops9FJvA&FNPKWF)KkWaxuSTWj&^Cuy{ z3iG%PasCy^C;CjD^Z88UG~~BpKJ#qr!^q!>dYE^fNklB%E?E9i%-3y(`KOTA?TLB( zHm`J)w8nS=1Kfx>D>pBLaW71>{!*G7u~Cxyb9YHO$|RJfEpKDDziyKJxcT{u$)?T!@x`5qUn- zQ7Q9xAg|9$&>x@kH)vI1so=?CX)& ziS6AQkl&2_0Sq3uVIKXzgFNrE|6TG&k>@?>rIH_sv7PsmIX=?aG{_nuSB=1e$Cgptr^Dha=n;$_j9$5aCfcf_Z zi zZ>PNi=AX}lZJAhq2J*b-dMlXrWytf|Dfb`DKa9K{&vE;E7I|I=-GDyK`F+UiM1TJX z$e+mz95QkKgn<0D0eL>_sT1uR1M)u!$oB^1KMcs92*{sLr!o;I2jp)E$X5sC*9GKX z49NdBApf_3d@v6TWa6xZfc$jidCu|&>AwpD=HHLJXS%t*!uIb#Ue7O>e=We?#rN)( zE-NmP zec$ZAzHa7}Io-QpGUIeFg7Mw5fgr7>aybnjur~DdNWMX5*_swzQdnJ7YKjd+GAQo^ zU@2S&#S6t#(Xyp@Z>u`LXjui`DqEJnpt>lr0;@eS#WXyO?ats-A*+Tj%US&-KY!u! zrA7JqiI)SEmb<{;=OY@zrXxXxg zfyJA6vBjwtPqa8?fKxSyJM6}_mvGPwfAEuCvI43K@uuYIx5~t_s>(vNqQ6ku09xUs z_+RTRslhv-e2X`~d|A=$r;(R09W(>2T!{@ZAFpu^GOqkCFFGT@59?(otjb?hQa#91 zQDHf1^h;dRmHC4;7B+fSNi|=ntjxzySm-aq`RG#%%N7mtZi+0dEGZde=?DSau~{=k z3;c#y-uyfHma<=AB@31>%&#h2Qi0b^+5MKM{kORbN+wSB&v(q>bHU(PmQ*duFRHFV z_0{=>6&3kq#WnsStZ>kLtcvfP>2&Vu>hk|?P*jPRi}elPK>x-?;i5qXOA(mFSG9bg zd05t(g+&-ts-m)NNg>{aW$zg@!zxo%Ik3{rc!8EEH(o0XmsTw)s~)sA1FEdS{6Vf+ zn2X>Swd-Qctirp_?7=eD`G-eqh0{HjkX1S{*lWT+oMFtW;mBHvciHpJ@UE?ivRt?Y zm1V_?@bxHDlDJbSpELlI3?vJOR$wKUpmn2+(@vhu)OAYMB9RT)oJXVkhpWj zh*FJ4EG+-l8a87S`YGS)SAVSD%y70{IS~5Rh$uR?SuWGy<09us2;1)6175X%a3~l! zPAbHj;>J3-xH&T7Jl!b{KI(Fo42^)GO}q0geSiGUahjtK>{R?S19Wrfu+;n(fi{4@ z1Ii)>1gB;TE6do?28_%hp;H5n*X%vK)fJp|hrRr_ciGMnfj>~L1!r95FgQr%S{Wp2 zBMtmKfc1*LKUyBWerqL~*Z9?@7%%E`Cv1N3BH$>?AH(TlcMh4I1t`O6;V(_7Pp3EG zfZFMN`HL!-Ew88=+%ryN@!v}i-Yf>fG3#Sc6sKPl*}XYG!eGZ~Hqq~p2kqI6Wl`bM zqLRTo0c@ZHW1_LbSY?l%PXExu_|tBgj)k+~nxpp98kvpO^xxC;b2h3Bk{q6NDg6iV z`R1o0PV3r#PVs+H#}faltq9m*4VuGUt3QarD;(v%z2_QS`1X>!1{LPM8``&qGfV&0 zUd3#8gBrgY2cv$!{%$mAud{q2LNHaB;9l{L=pmOm+y|E)ulKm!Z~{-!ydgTRBI!19$e5R50?)GY;z51FnT10mo>|yi0T;;HzgH|TFaIw` zm(J`#hnJOwD|mq83}f~&rt0M-OY=;}ebu6kb^|uBK zJI4Ur`}x(uhe^&J^S?DjRpFfjJM4gPusHb5pn=&MjdkQ4oJ%>KjB7}oGV!OJZSic2bI9UnuEnjE z4e#TrpLUBkT8vvnuAnRkn0VbjD9`XT_zs$HxR1;W%9zIEepL{z_i{=hry1sbIMt_- z3yseEVXE)8?E5U8_sG;{zh!g4(kJ1*k}gY{#k?P;dOBHR%Op!|_z8T!UV!^OYEx`+ zsm0|M^WLl4S6f_TajnI57O%3n(c&hHn=M{vajV5`7Pnix(c(^vH(9*J;%yek;=WT5 zFVbU5!#y2s!)X?$TfBuVZM%&uZQEt(yU5ZfcU$biJsH(QEp8%<&t|gtqa^HjBF~n;n+E+u}aUW{;&Gu(;o{IcVtxxPPOu6_X|AQcG{LxY@ETB zw0{m++F>qPe9pJ@I$WpMHe5v(`$n?ZH(UBT%f8cM))*uYRbaDl1%2PdfJJoiIV(=Q zC8ByP`7)~J8G@k84f~KNCz5duoKq71)P6i!^c0IHk;M-~R~uHZdLB6)|6!VsKYfO$ zz~W+yOUW7d4^uh*lq)Q*CeOfsm}>B+K5NODR9&t*{At-$WLfq`vc%j(7W-z4*O6!9 zKTMtY)A%=$r&Bfe{*|{OuiRzv4zl>~Cd+c|vUs<}eHQN_OPlYtcpq7oWxu5#u(+Qr z%XpA1F&wh^Fj}zIiwVj$>?O}K96`Rya5P!kKbD+sbUsg^y3f)R$x>Gm z`D$Z7o;=%d3i%qtlgQT^P9tAun9t+{t zcHT#p`1g~gKOZ39WR|7hvN=e;+31HX{V@3!qaPuQpJNsuC(Cx>;&G1Hc*qiSsHJ&uUArvGiK9EK40(*4HZXt)^@vS^8KLS^8KrS^C&I zvh=Z5vh=Ywvh=Zbvh=ZyWLaOGWa(p@$kNBQkfo1pBTM^tktOCG7VjbFo0#{KrLFc^ zyq_%XbAT-E({JeqE&UK#>N-r8b~r+ob~r|sb~sL!c5nrQr5!wEX@^j7nLNYT ztRtrzZY38PZX=f(ZYN9oY$QwDc3QlNEPl3-o>}%eHXP(hpgDm@M1E5%LTZ+cC@LI62ekt|0^L zu{e}mW^BCVnT8`QjEkUu#nLB{W!clnax6E^vQHx(TQZ~S4re_ zV>6yS(=eayRhvncO`2sh&Ej;j?3*&lvTw>J%f4wgS@umiWZ5^(CCmOgk1YG9`D9ry z1!UPb6_aJ(R7#e8Q#o1oO%-IG$YQD{%W~CNdM#PjbsbsO^(sqmw77{Z>$=&}*O8@c ztEIPD+)kFV8!f%l(l=T97E9k|>0M;0Ylo$GTfB=bb?vtFK1<(g>HEm{nzq_cPB(mj ze4pWd@(&CjBujf9Axj$`v-mh!{J4e=*mx`swb*NMgvHSo$67qnVxPr{7AILe-r^LC zCy`}YGRgI38M7^Ywx#EgR~nnSmQ9{zGvBf)u(;T=FC|O6m6K(iR#^(NEMv39>&P;mw~}Rl(Pr7SlO@iLmflI8VcKDnWwV1U$6ejzB4g7> zmSx;SmSx#XmSx#z@qUXBkfpAEOFu}K<%$Re|IpMGZE>u{Bgx{&XX%M#i7kmNv5mJl z#o|fi22)oWd9~qbWbvO)ZZvu(d6D64vb5)HvXspsuQ4`rEj^DcKIfBV84Jjb#=e*= zek#b~znUy%Yb?Fi;yR00ksmZZ8_8E1ZY9e)Z6g;MeUqhcvGi_B-(~50Eq$M*AF}kr zmVSgRzlZk;phNR2xA&X5Y`5|NDB|mI9g4}F4n*502ShAEINp3N^kG$4! zB3arei7b95S$aBIV$QTUn=E}`Hd)qJo~6&X^m4Mac?DV8yqYX=)>vFimOfl(>8mVm zBun3JCF?pRi~n}Zej{0Yc3S!-i?@))=Qd04vUI-pq5ZJive`wJ0D zeJ}Yjqwgb28}27dn;fvXpDghowDdz3A0|uuM=bpqS;`)_bpAMm*5x5f*-)|`tB`+W z;w&b&87?LN*l;=d3BwiSCk7nJn$Ij{LN- z=ld~1&lqkaKWn(1+-Z0t`8mU#dM&l~$4WbwmyF!da27g=K4 zO_nzAv-CX{?6B;R6elE^O@9#58fQ^?Y8lPo>W;%Q`Q zw{%O-wDfFCpG_8@IhH=x;ykkWoNws`WNE8n@zYsoJd zKXqhTzpE^6Bukq#S=>yPb+OK}Z?$aN$g(cl${s=eAq>P(v;mzmhHWdyxHh`$g+*^CCm1^&(imkWqUk8mhG{hEZgHjvTTEg z$j=-9hsjd*2wBP=BTL!imOXERsvi$omN%3vea36)5f(?2rO(7#`bbOXdv5A8kt{xw zEPXs#&izv?o@Cjik)^I_mY#0unPgdy*_O?0vW(|B&UWPtz?O_&C=V+Qtw8x z)Z0mxec2}Rk4M#p@J;qTQynQq=qcx65k!w zv8ayxGqWtK$kJ|&WNEi1OK-M#9a-9~)zaI@5`Q~c;@?P?_&doG|0c4m$1UW|CZ26% ziKmM!@$9hlZnE^fU1V9_-DKJB`YiiBWQlpNrSG%!{g!@!EPndQ;{PDI$i#VwTw?ez zSzBlVnxW)XD8;!?9ma?H1d&#nmM_4+)wW9X17LT;-eU_eRagxR3El#m`lErCc ziD8FV1c3TVZpd zFgMR>!tLOzg*l8Al2MMoZ^C=rWPb1MQsl{(Bh3|FhI9oP@f<q)itYDSf^w zdJ5X}J<<8Q51FCHhTjb1^()%*+FqgX9Y{|J(|$Pq=zkLY#0#f^dF_Ha*X;|!-C&;k z)8`jRN8wzIyd5dO14jE@u$d^l8_aWF>V4ps$YTFIj$^5h$GY7toC4-CJoQOn7xwkE z=dlvM-$gwQdX?}rFpp1Y!|!jsE6nd~{Y9AH*7{udOQbx;pgq5*^_8#(W9ohQqyJs- zdB5;(@G9XxF!wLC*$4i)@P6=1!Uw>AA;Uj^li+ho;^!2cu6Z)@!nK7jO~Fu#*@6$Wqm$w7LL@D`-}tqbb^MA{)-g0xGR z-#Yq0xF6~H!;L+^19XM(ETp$u`Xb?Ir1y}qj><9K+%H@TUM*YzZW1mAw~!IfvqC{}HeZO&vGza0o#3x68|NEDh-VY@A@IxCwt&Nh8N*p*sh8g-qD>q0 zXiMj}iKsV2KiAUZMc)X0w&?tZ&@tg@_}!dv{Lw#ojKvQL^Lsq&Eq=n{mxLcj`di^e zu~@(Oqt7~|uaFU&7yFBdbBxY!>P!{>Gg5v_hc*$gnI#+z?i7v%zek2o+9$*ro`&>N z;ju^`6Xv&MwhHt6G#^^}L1BLXW*F?~llJEd*Fhg;agA^*(m#`@VB1AJ2Skq>iLnNM z^uuqx%(S>e`0wYrT)!Zr>>-qWS9E@hWhnkwmfuZD5azd7(#T>zU37laB~SFj@N=i= z{1(d^OMh7O+mLRw^w&h^cUfZ2H}(3Eo@?<0GU`pkemPTgeiP+t(WgN#6`kK);dfMM zpANmn(*Gv>FQoq~%x|B3Bh2re48a|3iBH$!-aiFtA!s#8tyZ7Z9!dU32y^O z3iBAGP%eykw}bBz-UzN0?gT$CybZirxC^{RcnA1H;oabmg!{n#!h66mqfI;q zz~>0}gGUM<1b?55W!Z;xw(y%s?-OoEx|)pT+7J65i~bSP-4^e)_^9v?#-M%hNB`t1 zi)$=iO@{yRIF{}ZP659pHg6#9wfLAYzX=hJKbB2{eT48d@Oa@I@I}IN!3%^7z$L=P z;8NjI@Sn(tncsT|#~=9sG#{Dk7dE4Wo55p**MT1p`y0l=C;nLWM@aLM4fFd44+`Ig z^d({b=I`$6mGNlS>daZZWm?@eHQO0!_Roc@DI`XZGdq6(Ie-pn?m^ObC=5OC0BV)NzP**PUOr^>d#ve}n!pOaCcZV)#n*rI(-&;E!ebTlOWw zJCSw?^S9&g!5?kfkZvTy&osopUv$Rrz0}z7cdJ(kQ*ROG?`}U~>3_BC3)75GZg;h0 zX%qgAJL^h^{(I5spTFHsJrnvgq~vVy0y4_drdxFSjGJoo(MYcr=I^jC7G|8A$Sec< zt-|bwUBc{#uL!drzD`D6XMG>%^`f)vQDK%nF3hrS*wH`Bju2)WP9n?lR*BA-pA?dwM(o$xAfyl^8pQMd^_R=62FS$G}zO5slM znJ(iWL%A!CjAiFU4#&FZgu^H&W^CTh_ZVp75e~I2~Xr!5?kvkS-Q3Lb}A_N{d&JQP)VMnRbMW8HFR?L3;?EkspF5=@*Bvgs|Gq*x^E!3>?Zw}p$ne<+8?vsWzlz=jovd~J zQ}kx&WYv#~&i+ddp9#P;)NSfo5{zw+jJnuQ$+~`{Et?C(W)p14+76?|rUZU?-JE{5 zz=o_glf~v%*kp*!HrSBWCR=QHUt^BgbiszKHaCh*G16PaW(RD@y1b>LcS9#@n^%gy z3p!c#TG4kyC#&8ddLMMM>Kmz}9eK~?sMzd*4OzFZp;!jC!(QlQ)ni592c4|z{e02) zLno^}uidk*sYrQWhdvL$hO9QTMem1B)_!uM=m(*bwSDqMKLnku`XbQ}LnmuLsi%$@ z_Fn%{;KE^(8=Lf8U1&n zGY+zDr|*a!3!SX}_RrLzeTDQxu^EXxS~{G96sCV=Zns&VifNwc+0e=1*BgDl=p1*+;d70?Q1l$=KPS)d=1Jt2?iu7;7^z*-Dv~xA)k+rV> zh|O`NF2qEe8rYE4X9#s@KBN(1Q;R%Vmn%kWc)vAHI09X@m_~+v*mv$v|2p%oy$y<~tKBE#`d-E-&>5 z$*8v#d9rSsygxy`4LVu3P3Qgrw5Or*k2dX+*RnqqeIsvru5G0V~oovhn+nCQEp zlXbi1{RS@kZs=s)uH!`SgHG1%+9&!R=w#illSSVPovhn+3Uz3gA&0e2Y{e`^|4bdWe4mWp{a{@l*pPMI{atLhxM z1Eh!^0iCS--|vgg<2$nMf3rl7g-%xc>!>6CyO36i%}Cggbsx=nwBfTA^}?ZO-XB`} zgJi_%Ls_zxZ5KTeI$8H4&x@V}ovhpGR?){pC#(K8b;R%|r2B>WoW@7O*$C)wWW!(!1pp_6qyuMm9`bh3`;cZ`36$H+d}3ub#GeC zcUu@6&&$c$-`*EJ2Rd2%+eg&J58rKJ*}1SGYuSH@o(G+*W&cebW%*3s*J3jtHe_wv zaLl960_bGzt0P1&hECSLnjm^9bh7r<@uHVQCu?7wEP4fWvi8+<(W{}8wXa?!dJS~4 z_SGEGYoU|1&2JXH4mw%;YJuphpp&()-Y$A0bh7r<`$XsU46^ps2GN_LleOI*5`7(X zvg$t(y%joHj~QMRy$w29j}Lz-dOLKo+W(e1)*YXj{GBkrN43Xdz5_xVK4ZyuJ(Pn` zhD=+Q=lb0U|77(aC3+`xvK}9vEBYqrWW5%YDEb!YWYs5#z70BA^~s`lK_{zzId#M~ z6X})0*C5RiE9r)zCrXv=wyxI1<{kBlU4r>b=37X($_40!{T?z zXwUH|OV+Y~6FmhwIed|cA@XeF(}jI{jBooUu`kJ z$;O!PMtZ%)H&`~e2-hRM)zXW|Se6{bOxE>YX4xzio4K$dt4+1o@L6cq%^2vvR+!(0 zTSbQdJd`DC*$2diwk=}AYmH>xmu(OmF7Gp9Qve&X-V4|yHan1R5u0Mzkaeu!H|H2b zDRi=y?W2yEKSH`kY|3Fn*0F1!=oQe(>hp8atD%$C=a@#EMijw8?yR5C3-D% zvg$)ohH=(GCu?2NqVpOmS?@tyAbKNovg#L#&TFe=)hCMH44tgU5>rLzH3zb`{|xF_ zmOP}nV$%v6vW{<@$C%rolfz3*pD(43viBh^7n^q2kac^h7kwjivW^1}Qb*Y~r2Kv# zc>~hT!V`z#{=M*aq+P;%27V_Q@pQr`S$*=me)Mw;>E~jz2{vS1-Y>-_HWJH#Kic1o z^lahJFh7k9|65R&tk-xm#pYV1^TcKwY{+_zbb;73AuSQ6|3zf@?1DX6W3Cb#K8H^` z#>402?<2#02kgl@20m=r@R@$vbi;-mUToIOlVZbX_S&*9kX|n~`(Z=Y_P44@ja0wizky&HVI|PTG!=bb1l*r8vfWOvtdKlWsjteWluyJBR0Ih zL{>jZqR)j+*5ys1j3kr6{4{E)S;-YEKf=wz+8m^%C?AYCrZ zcX4Wj`A*M$!hBC>mBkNO{IJEX7C&L}MvH$X%=cz?2!Dq3H^O{xW~VUU>DevJcYNNm z_<+Tq3-jHYe+u(Go+Flx3-g?Hfi%?OiNdq7jeK92@8hJC(VkssH?m%P$r776NUs;0 z9k3y*%}rvHjWl0ux?w|Bn-a@rnb_=t4Oz#NN5rOW1on5r8<0M3>75q8Kt{~F;fJi- z*RMqHgHG1*|2LxVflgNYJ=D=Rokh{ z_8j4HNaM+3&%D}PN|v&hi@qPeXOOX6dl4sD`R}|6H*-1{<=L9cS5GC^pAoLspw9md!M= zapArkS#4&E?txBLeF60<(+BwO8RHCv4Owlfs3Xq1klrcG_IphD{c~`vZ1HB{-AKEH z`5xPLVcNfD@mm(}B_oEBh=Clw!o;>;Z20cmUxbe!{hSPYAMDBg>+@pMkCb+_NrVkq zk8Mtfo&=q&`<)@EgUdS{X&4!0$HRuKV>Rbd=RIn&`aECsNzlpaa}0I(N7-7hfdb(rPqm`37xFhOK%oE8#-C9mllgY8#-C9mo62Z_sq$9y|hO3 zxzNday|iBRJm_S-UfL-7eCT8y8(Ty#fKJxyrLCeDLnrI?(hku}p_BD`=}V%QLnrI? z(r(c!pp(OEOrO~;dNp*iw&xzvYoL?W{uAn0M^oeQOrzM;!iKEd!V%Hypp$ic{#x`^ z(8+2a24D0!8mX5&1#JTxvf9Ln-UOYjV^=bDlubc8L73NJn5Rx3dBW?E-b{x7X80ki z|5DM{K__d>OGR&mPFDN-sKftyqe>XK zWUb4CdDOQ+Cu?0^>QYzi|Ht0@$7fmA{r}hIfVpesR3bvmiHH*sCr+G(HE`l2%xOqy z*f!V@Y``2tXHiXBw7jWE$;g{(66sPXQc6mwRYY_*ij<5By~(Jku(*qilH~h(Ug!IL z?ahVN{r%iO{`fpT=Yx~udAzRI@jj08IDcN}d0xkiS*}uJmUW!*eM&Ee6=$R3z#hNa z^i9%X@Bb;LZ}@%KjUydUwkYr{9(An>$V4BOUhR zorFR-A|3Yrxd&bKzE)*FW1f`m-@;z@3G@6|=~vBDAP?-Go#x>;(fDXXp**mAer+Dg z9WYO^Jg|H6RNni%09M=heKc{2St38|{^91~x7ueIL^$UM}A4^OE)uzQvV55Eb=Gg2PdJr4!X!{#ZI2X@cb%){@+ zzhO-Kx5J7#Mt<1+zcHP6qhQw$qpLq(Qu?AX>p7)$kN!%fC&IR^mcWW%p*XN_tLLE0 z&+pC0nWtJFIK4F4&MVDRqjZ9KYUF`EPOa%vrNdr!I=bTXTlSmGQ!5Xges29@J^ z!`}aWrZ-E6)0Zd9@}%i4(qZ>Mhpzbi?tY)~Ys3cvA2#N9`URTt!>1eLr9ACvQ+(Lt zk2SqrI_$^lOH5xP9rk-`Ri<}Hhh4wg^iJup>(`s!B^^#*mMrg0=xQfp2s9ecQ_4&` zm&*@(Ki_7anMym1-=~xr{|fnG_kYMd?MhdgXQe!F`gKVgR-3*`I_&oe*P6asI_xnw zpsUSaQo70bt4e!~f1vc6u-enDvat8_Q>L$#4tvZWo8BWG_G|vaN&L;y zVSjF0h_1GsuJqOB>6Hie=Nf!AxHFZR&Vl8xRC*q4dU?<94aNtQUTJ)t(l^3Z z_RXd@D1D3Z%}Q@FCe9pK{nMwm!M^?9W}bCQ7a4y>>79Y!XZ%T}9|`T&1rtW}J)?;~u5> z@H1w{X~rqlb(ZnDN=F%wlujQ11xm*lS4k(2ezDSV#>1swYRs4tuMa%YnB~2}m@yG& z1iiudpqBgX#s*P!R=oThftr!ZrRJYvi;J`StwNR@?soBxJ+_`&Hm;~y)1%J?rz ze+sK?naaYxJ^$A9G16hz{{uZwdByyj@lK`r$`hwte%Spdq07&BCTEzZLLNB1Ea}g) z&2x&E>!=UrpikCTt0t36wlZVLR>z~6^e*Ho2-eOVYghO*Bp{i!i+dk&VrR(?4B zfus#Dm_AK9>~Ywah(lTSVdo)%*-u;_8JO`|sB4B|!rpHenCD`p*Qv z`b}NXUxL-PF2#ZU9ghO}h_hSTD~$`3KiPPK(pMReQ(9rnacnZIn5z^M_H*}C^VBQ7 z$vms&fzz{-_Rlg8aTb_oojkC|X){lk(xv9vAP?+uK58D~tT9ioJg~>z89rF<9Y4hxo2lhC7+@th2=GiR|>~a3)9>pm-JL#VT^1vSFRCM)mnbHyFIVcb8 zan3XSkaXDZ6JCg}vX>~WFlG#&OO0Qzw95E8rPanelwNJjb;~s4dZlw*S2_>YIz6m< zVc!n#G|yd1neiNv2Tm_fWu}jro;p#_bkOZsx&~cs{;bjmjcLO=W7_sPSTXsn0POW{ z4xVorvyOfc_$S6cQ~Ini@qcA}`zU?CfEB+`@!|A`k~aUrJbzL8qIrttfzuyOJb5Zl z`wvMQ2rEvBJaBqN;wdqGuyi>6kwhPgZe>q1&ro?_U&eFIvqb4w^9+{_a(3&L-@?U%iIYo<_DC%6V|e{ z$q)N>_(Ahf@5hW83u|@YPr)kNuClO~U2pml>9AiDK4yA{blCmhL|1#BRr)RSbjky} zXP4<+(qX^G`#HMG7N~6p0{Pq#d6Hiey1r-nR_U-m^Q8>_?b2b7`Ac-Q;U%SiFi)R6aQdUE%*1Du-6HDO^ zz8yYo`hMxK`+te9_PnU{cg8O$J#74IrF=$R2Tn}b%buuqpdXYD`}Q*oT`?I4?{xDV zk_Yy(V@y9R9rkvPGyRBk*!`2x6?3N2YV)Lu5_Zq^rWZ(uy*;zhRkl;4V1IM;cfm^QixN)%YqGsP zYkH$}IK4X2_nSUfI-LGQqW{tKX6bPHlZpP4>HLljPJb%V3(rgHZIceCyA%Bs)7z!P z=?4=1LUb+fc%>H^Glp1=@ij`XH=d#N24g(rS;i%b38&X2F&jb#=)PyZ=7ZmrI9T|CH$~q{F`5K8CI~d|Bz2j2UO_ z30U!0$`7YMleA~2d7f7K8{>mYpEss$e}+|dmCC~D2a~e-W0JZGl@2h*Uj)m)T7EeF zP~tz!^ls^Jx+l>uL06lvS6XeJwerB}&nBL0%(GbObo2Dc1E(KOJay)2Qaa0+_AE5M zOzAs}?^b#btah$b9N3rZQ|9@M(ly4!c?g!D-!j6!T;DK#qjcDp>uGc?*Rx8WGtVY@ zU~ltp&GR2he`icxFB&u6=1V~zq&#idtT?du *ON{7=;NuRt1U2Ql+>2Tx2ia!EY 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 Zu-&jd+8lB}v|N6lTVF8})_soe{{Yxbt6Bg6 literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce019d13c5358f768b89814752c2b8a0c5c12a82 GIT binary patch literal 1459768 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

    ?ZI+AFUQK{`lfE+H6nj|f#v$3eDG63KM*X} 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%0DH3)&1 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򸮫 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 )$LIQj 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
    Y9azy9>s&-wkS^E-%s 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 z%0AJBi@|vO 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�YLJxhH0V>U+# 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%0D< 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≀le?79MW=EuU=s&(6Z< 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 literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce019d13c5358f768b89814752c2b8a0c5c12a82 GIT binary patch literal 1459768 zcmdqK3w)K;l{WsKgoKEQA)q2s2SFL-A212G;8+Gyk|3oN8G@IwhH!F#*pS3r5FG17 zlAut>3wW!e4pOR?aU4snSnH@TK#@_Ze3q(X9jg|tV;!V;{jBpn&)$2Tv(8Gwk*S@T z-+%w|=B#I}weS1g?|%1Q``xFUUDF(2GNs>{!_!@nf}Ym@hYv3(%wqF^9PZ%sw?b;%jeHG~fuY{INGh zf5SIxl*Q(ZNAg}vA`h3?@=SKt8Rd8Zyl)UB?Mg_bU)poy@J{A=m?t1CksNjF_ z8Z>!H)a{zl8V&k_uHzEzQBT+L!=H=}b1iJGUYclGQk_`dS{-j}SX8&TdU2vP((FZT z4e^#V?y}bi!ylo}beiF8&?eO+yJOCsLZT-UmyI^LY9O@8;rL_<80jF-%K zeO+~YVK-J|QyQzKd70HBOKG8$su^BgYhr12eWIbdrS9@nOjeo}IK8w~FJl39<5&B9 zCzjW>q>8ttZD9kVTi9GzyEu_n6X}u`RdY_cu3>R?Yt6#?M0HJVDlQ{xPAqL)mP)#h z1y$!FO|N+4Q@0c&VritMbYXMcmc6i8s*s|9lf{vqucbAu@g=>;+8XNOH7#hxhtX+i zt!Yh9jSfFmNZk^RCYXRv6#h38E70Vn3S5~c6SSzVp*BrYooHxnUXhgh60MFescAs< zu_h5(Qrgs9*U%bDJ1vx?MkpNJAcdtGWK(nFvTEEVjm@>y%`K_stoZ4bnI@>$?X3a# zUUhwA4RTe3n-6y|^4{7QLT{<=MLC{mZq20VbQo%FwTnNk&v5Zt4b!irr8?f&hO*Pm zP>Io}=}c)!+P&JiXc2Cl>c%!)i>enQ$keT(JuPakS-ccA>+bYkBTZ`cma68&rOBFY zTGr5{l4YgVbg zuHl>L0nqU$b>fXno2rWu_F`02qFM2q@WgP!lG184ydounm!=xrNAV?z_&1Y$cDT+* zZB1*9?~5Hw`ApMD`g7fF3!Z_kHO^|F4`+6eh-dkV>Xyd(x_EU%qkeFrk6K2Jg^3!(XuB^h zYFxOettAd!mCiK3wTbR3@^t42q_w%RKJDh}Ce%+k_vl9*G$YArHynoqfv@#z>ssP? z*fp;RkHvURQ~FKNqk;}$QDgIEHO;lDhlYN#b`#iU`n#G$>W33U0iUe;KBSy&3K4aN%^*(qT2XwA59% zE@{S~y0N}CEhk2#eI?V#+@_awN`$d+6K~EHX`%Kc*Fn4TQ_Z?=Dcf$mwTDvfQA>xF zjEmkg7kD?VUc>5Eq`Kv##oA3XEzCuBj9KeBYMhh|Ep&Hiad#Y;0@6YlIpQ z7`+zn8~s*8`uj=GdWP#`$sD}vlIxHfJjRpVi3uyDq^${$F}yD&n$U&Urh4I?wNZA} z3+rp*-%J}a^sH;R@z&;g4qZ}XcB2pyls+!+StorAk17j({kYwao0IuQ%ShFh>cO0H znpO=)J807G{U;f5uRd_cwl+4WUNx(G)$A5#Xi0p_NG710(jxTJNKkq*lQ(D2eINT> zW&sbkHav8CR!W7zj*G7;z4f9?8}ZWK*xa*5ZDLVP8^#!>m(n+)6D_T2UW_*(&G&_y zsY5_($=JKPeknu8;&cul7FtmH3q0GDe}9)dqdMFvyu0~kk;HrKIo7qu)+3Jt%<*%pM1S3jpIZLAfyQ!UDcm9{rSv|`$C3<7m9Og{r3z6IZU`&YD4|Qqm?0nsMya=PR}?B_Uvud? zwWui;k{t;etuSS!^;}IKzBiX{f?1F*zvq~$TkDqM$>rXlL*9B;Ojd)8^Eo)~siqq* zLwIdXoUG$R#MFE;7`EP?W8yG0srLEO)KhhG+~6K9E(PKK(s!m*X-}Rpwd2d=a7t;@ z4n2ipW*zF$>EV@=ucYoZQTKl44KA%`tdFB}NuO~PmKu_fWjZWjDJ^!3HMPsCmveyY z?~!C#hg*g!zS-;P)-c)Sn)YRNd@*WDO@JmdUz> zO_)nfdkwEmEaTf@b-c#RZ{q2S@KWMr%3UCQ!*!DsNp@pxQ(8e1>yaL@DOh2tBE!3C zZDJ|AOnHM{T+@n<%Dw37I&{IOKQe@+f|EePYp@Q$h;&j#)JxPoh0vCih1JyTS;!qpRA;j2drDBZ2~<%EMd2PTX{ib=GC3IOt|22N2`W`SDk&~$ zdge2vR!_xC03j`^Ta+%KM~y|ziPUhdM-ALKxYtx_(q=MzJn?q6l zDcoggow)?7mOO=JYTI|vC8+GwZRZ}&=`8W>N+Ma(-4e>Y`HH~o!eOL6Gz`>$3)~e| zQ*B!}-%g6<8n;w~F-lXTX`L)7A4F~2VdXCUy#(O$-g^f9WPwxSh%haYY_T=<^^I{? z0^LMzAjXipNw7j#i^W=>EVb^#LT8{_&c_c5p<5Vk7~mce{xOhLXsKyVPLOilT{m+p z)1wED80S zx_L^4mYn{zWh^Q!39PG!IpSobBIJAxCu@51j2q&xG8r-@17`Nq9wtb-U&Kfb-tFsH z(yx1r_BdbW-)z&`u2)9O{k$G}pE2tpbpKSu4UIm$-q}rH*&^*J-$H?HIKoqH!s*$j zLp}18UTY1FKsf1^a4WaUK7^vWrAymaqs<8gZr&+by5#s5_Le1esfQ=$ zK0*h?S8X?|l=71<#B@?`BAHmqAjgYw4;p5kt0xVapzvc8HRb&|lrj6;gO(4;RkX}q z$lcytb6GX!F#Y2BLN$odd^M^ReVW!ZaR7}0R}bE_xCh_3NAce7#xFhj*5Y1$BZ|eX zDf1IanD@)p)kCsU!XAQcfmO*;4CiRO(1Tws?!mXS8|ulQ7xdtReMNmuQ%`ZxOJk@SNaL%r?SXF!l_4j~EKOaNMjAg=hH30{t11Q?vY6D8{OOFb z>!$9aX1s~9f>pJ2lckrH^QY7iykjY?rZ)7b3|^@vc}mZ}P`ZIbGPRzU_NwYx=H1jY zF=W&)qn??3>v0cn+@kRkJ;vi4PaVe5e2b`ASXW=yiuL4F{HT?dMR@QptZz(B8o5pt z95u9athA>|E#6g{vDgT+0cyIH4~&$hLr96;laz6Uv9xIT-1rAA#7Up55hf=&DoK;n z#9J{^IgCOwIuylX^em|)acGc~wqg>}jfst42PnTaRgRc4XEK4i&Cay$s8m)Wzxqy3YN=%S> zXbTHzgh6LL?fCF6C-qv3*Dbu;w{*kZbU0*5V`@*Jt*j?~^1_&~Hi}qOW8-5RWuHZF z`zt1nAMbWvOe_w>@CE(;x_nkeEEbEz#iHLuDHKIBj>irR2**2x)1#xKe$k|yC>oTL z6Rm9bR9D{0_SnD?PmkI?wsTYG7D&lo*OlY6X6~B3Gj~tP>W5d~iZI@6kD~aRJ}1ZX zjyic=-}b!tutS5_^^L~HZ~J)gq&^5Yw>|Hku0c6{BGDeyrw_Q%*xlfE<_Wi>a$eTJ z%J`jc7Iak9W}Q+QzkPo}c4cc;e8`93bY}gaGJf+11s#<)WyROM3CYH+?^MR~A*+0d z+IPO0pIx~<>&A-s&|l_gN|72hP z?269pu8R1uef>KsZlb^b9hDpDuYY#sL)plG-}vAUL2oCWg>-^`9&~$FeAtKmvMb*p zor}DIK17{kp%1!GALlp!!+x>ygHsny-#fkRoXzLt)P$Nrx$arT65W8Z%So2#QB}`9 z@vW+@PpqhVZ%bR%ueMxT_1u=FRa>{zRkb~ls7gFhQ&siEH>%2?xS*%OP?sOs(E5s)wxf6xoX-IldCS>GNGzwOL5h?TgFsP+j2(LkDfTK>U&R| zQg!naU#jYQ;>4;SZ8@&$ds_xp-Mrw!k#zS;PPGw3csR^H1a?m}eMX*RZH@xSMetzNn_IK2cjZ{Is^@ zA5<&9@|ClOpB`^+Y{5vsv3|_#%HfHYrZL4OV@t*sRhJZ%j4LWBDm??ci^zzkorchx z@%pnYik$?qPkv7GvT-GKB~8WEOG}!Hs^jkz0Jo$SwZV$Sv-Zyor5# zw79>KTRhmvEk4=EEk51IEiN%~i_bQ4i>Dj8#j}ju;`5E%;#woOxXH*ZzQV{YzQ)Kc zzRAdMG59uvHyZq82E5(KcNzS&!Ot4}yumLR{IbEX8vKUAZyEfK!3PXJWbj7@e`;`) zB{xjC9}LbjxWB>q1`jrPh{3}Q9&Yfd2A^(lp}|E4k2kpV3&v-w@Q#wAbH5n527C>E zV^N=IBz{T13O~dwdhH*>BIRhAo?e|h(-F}w=>-PIsz`Fgm1MBwN1+3fe8erXi zuLsuc_ah`-8Shrt3 zJ9Yd07hv6f`Rvr~_vgU6KYI~4m15C&qyJ|{e;V*86<#Iq9k{%U zMPCE0+xtA=5h6zT7Xn|T@B(0cKP(2;_fG@xUAVl9MXjLMD|~sNna2WzekomKim-#3( znaM-qxVPsBcNfC|qoH*X>Sk%YDYe9*_8Oyp>4tXrU;ZB#NY?#HflpfaY*WW0qi7y3q4|uFav&|?ECem(Kw9{VKo{)5KRD9DXTK!+q=kP4XwfGv zd?qpfTKt2%30MB#I5N6}^mU%Thcq85a1Y?hzrm5wBcyNi^fuCKJ^eK4b)McwngPST zf-C=KM@IWe-{R>5q&bNN_YtoA+Z@TRFv{n{3NDZI?Vipj{kNVTN}7pq_`(tqdasifC?dIsscJq&3)^m5YQ^K>U^77W}Cr0?}K``w|d zQ?!)xL*Snj_@sr;zEIi^Y2j}JJ?1_i4*Nr)cPo02qW3C#pQ2w<^ec*fP0{-m{kEdt zRrEncf1v136#bc^v$9fY&Q)|jMGsJPfufIB^iV~gtmqMn9;N8fiXN-z5=Bo`bTqbQ z#ZoLH5P4GEyHWuco&2C~8ONmSw^>0upX)Qe}>QPH%4Besv)mb-IP=h#k}%O5iB z#>F3Bf7QRl%7qg@=H@J+hfG_&I9C4g^*6q`dFqJiYo||(t!x+BhOQCQJN`5$fAiE) zT~2bfNWdL9qHE=?U;E{6woDtCyK~gG5!*K&3m)D zD&zg$S1H-jH$VFL`u9HEJatgc8~@4FjGM4NqF*0Q%!D(#GZp5ht`W)b>t2+YrfrE0 z%-zGalhK`ADVe)nB%3-@`lDAXdQFPnw0dST%rE_Vb!Gh3Tl*o+YYwS2uSVJ4_|tW_ z9u?bqb$sT5KG5nol$%;D7%`LU1$(;YCPQj_@2c`t93#3GPCqzx@AS>*jF`DDaYj^j z&bs&CKQ^c41T@3NXk(II)&oOXd23hsxxd`HMfgLe`BHoF!=+m!EUr?Fn0ZxsDikS& znY$k7oV{~&vZh8SSB*N(C_g@xs+HeCK971oO67yOSeG~_ig#^{etU>1)v=|gSz@zg z-f?PL95=c8S8@2V(lzsX*3F-d=$ck1xn0-y(ObyPvO@;-uOuh ziNAAync|JsHLO~}Ce;e==}MJM>=|D}zEpFPHFH&Etg@?O)T%vQsaA5_$5&OvD(+F7 zW1dSZr^M(8^_*72|4mCP$-b)>SDjImUyT+jM^26*S?7Ng5elk2q&re~Ol zL;6yExet%yW$${%6Ga^Sml}MQ!Dkyh#o&qzc#e_J&4A|{`S}K4Xz;}bFEBXy;0yU> z-FoNC=ZnTyNbn&(i?1~DFzg4{r{@ME55xSVJPhNLScdQ7{|@6n6TZjj-)Hcq44CgI z-ud)f{E&!4{w#jX$hRB3)8JhhFyDu~^XYk3V2J;DgI_TC6@y-Tu`&a`#>m$geA^LXz9Z}S@5z8S8#&*fwf~0=e%#<~25&cbm%)6;*5O;c z*T^k?!^kb(Z{&RE*6|%QnD5wH&iCxY;nYi$zu);TuJ!fYKA+!w57%-%*H5{g+y7%= zzQ61EE!JxTjGyoFTHoTCMn1>jxdvZ+gm|IRUz7naG4ck3Q}5@#zLp#L6$W2v@TxBu z-(bSC_!c9#_yHq-$l!+!-fr+tgP%3{d4u;E{DQ%+8vK^Q2Mzwn;H>22g0G)kgNGPA z^nV#1Wzutc23%s~<1^qXMm{wIo?+xO4W5+&&ogq1=Now@e7@1I&4BBTJQHp=`WCM= za*Nj*`Ar${Ek=Hu!Rrm)Xz)D-Z!-9PgC9B!J`o+Ye*gOt@B-g?<9{qV1^@N?+G)UN zEBP6q_4~qDU_CzOe7PR~mICYdl`jM9@k<%7etuR0>+#DhU_Bl>7g#^v`7WrR*PK7R zPd$$p0PFEg0$4v^E&;Ar{YxY89EJJrr~AVdz`FnByP9rq9l$9Ui@3C;>*FS1{e0lE ziI#5w*8Mx*weC{s`A6XU6@D04_wWA%tovuaE9w50Yx%l=-3zSy(-(pBRr`4rSof!I z0_*bk1A%pUo(Qb(&r^W){dWeiF27=6JwD>Q zhA!_v2QE_O$9IXd6y{p}428K4rN=LS39Q58*uMamcd@7rw2r?Cc(jsV2702xSAs56 zxC``bg|7vz-%r*7Gfau^cF=nKemC%DCFi}M@0WiBeo4tWR@dXFJsEg#@J%^wAVw+7^(t9cp`2}HwvtZ-UZOD9h4lPU8L)02=Kw!~ z%e$ECTXcVN9%TA?$G%BF9~J@Mp!_cdt^1!=V0}OS74RB$KXm{vSNPk&dc3g~c%hQt z4y>Oy8-T|v`S*b@QusmOI}~PKrz-pe@B)Q*02grSKcTx;_3o z@H|{nzU13#wl-N5}+{PzLt`|$x_Jzx1FU_HKg3|P<4{WGv0 zZ|nxv^Ks7s>+#16z@=c(mHv-`Z&8?wp89_53(Pj| zT`U>^tnbg`fc5xy7_c7Sjs(`@#nHg}eklgl)0N-!%B!2Hy?L`nwAkZNdJ@$bV_@M+TpmBeD6l;!=a>0rP%iAJ6cY8~Jw({xLB7 zgNBfv7mWOOz^fqVJ;(5{ODpM^-*E=dGI+7Uod(}$@Y4oI-1#29LFabGr)=kF4MxK* z+Nja!%bUTG>nz)x?U*xf8|O5f-J7FmCpO-hveCP@T_ZK#S+UV3ZK6}5@&rOLW>Z#e z&Wx_2-2If5(M%1-XiNouyqVf0&n)%kYNg&dt<;;Pm3qUsQtzRZ9?Hss$y%wmX)9&y zuvzo|CVLN)ebB{4o?Bex*~LYH?}`A{a||MBWalyi`#P^X(Z@M4B$5H8o7=&(&Zoc` z|G`Gj$K}lafV@9v^*4Xkcpv6?ALay~)d}9i1fNw`fUxmnb`TN0CoTDW7R7qc2jZ#? zY4E;X{Q-HIGf_k!LiqrKD0^R4scQ^TCY)D6g0i(Nul^f7$PYO z73V`JF7jC|4r!n4;biZ(xXAxb_I@TyHbb;N#K{tp|DEVVnCPRO7?|G2L?6yXAL=Bp z=`1x-AD-!&GwQ?F&IBKYGvS1a4{W>-dP1l`ABwv*;Lk@i!K*kkPcVHwj`!Xt_#bEZ z37Plq?if_APlVS}4PyF~4Ih)k^vlwt$ITM0A!UO+P<{Ecd zx%{wDpu$MObU$S-d>}?sR_1R`xkp|2W##z!99E$Gh!=Ml^W%;7gI+Wq?cofX!<;We z9}J~+xet^dX~3sCk_q8wJ9_!}M^9eUz7Ap(dP=N{n!CA^(SDv|Z&dKy{Ooqs_ZELr zLFdhVjk5Q1b5!`DypzepKI!E5WZZ{0&5=6Rt1H!3^%;=fzMEn_Hpi23{=r|K{XE}m zMfvsgIa6orRuBfWv{4Y-N!lkA{?HMGxZ2|D7YFhwvl$A}#vcK^GqKI{T?}vyYdw=rFi~TRfk%@INEp zvm?^N=lH2Gq#+Nq#7kOq_})Aw#5;mIAupsw$Bmmp`H&Vq-$5juq=nCS3rQzw;m;*M zlqYH7UkJL8lSXhCgUpE9oIE{Hf&st=A_l{8^y$fA4~c7LsPefm;N+ zkehAbt^_T4CoO*Y?jv!L7XC)^LtLbV{~+jmjJxS}Q75!9(xUS$bz)xU1?q%$PFi&M z-Y+_DD;?6Jb4clYLY+H(n50FAbDa`S9%v~~(xSup&w{(WU(&)K0=h7ylk))Lm$c|` zZbi~hTKJqpDfl}dCTZbMC12`D@i`|_u-@yF7Ja_|7iM`r-x~`!;Ri=rbU5Eru)*_5 z3%?z-q@Qy{1>f~Lq(z5wtD?jAMri}2Md!$EwEu9U?BU2GQ=5y6Zal8kdu+-s`6Tf9 z$~hGmUHxg;%ZGQszM$!!GCrF|1&nMt_m&U=`;tLf0O#Qnac_FX(4n6qTy)eEnwT
      ?ZI+AFUQK{`lfE+H6nj|f#v$3eDG63KM*X} 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%0DH3)&1 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򸮫 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 )$LIQj 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
      Y9azy9>s&-wkS^E-%s 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 z%0AJBi@|vO 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�YLJxhH0V>U+# zbMB0(GiLs1Mi-e`Q34OBo;#%a(k>&aG2v$Ixt#GPVV9rk$&Gn9PX`UB+I>9jONUm8!MesT2nH1dTCA1u~qo@ z6}t&ixeiV;F6t{b2}KBkmDU&u4hI9M12N zvVRXLk^1x}P5ha-m+{x34XOBg8@uJc#%{UX*asLMYIxMwr8mdD~x@$;q`_$7~YtHA2W8#Ta0~Y27blZ-!%Nb;V%r!+^+uT z%R~Er!BgNU^<{JXWks5~`%O>dUurmRxOWEbW9)+rV@QYoe0nb=ma-^3AKP$!vAwg} zvBB@l;lIj0k>VG-<;liA+px@A>wkWK^@bN^;2Vv7MFw7N>}w6LGc5Dua{BHzeD4wR zBgX%+4E%(#Z#Mk2;Vp)r%fLH~-SX>XzZMxG{4};PkcYW&iG$%c%|Xh8F;O+Z#29q18+8V%Uj6)9F9l0C$^#fX1kRCZ<@E!{w02y z6Wss&^ZW8ZFghvD6ZU(LX;8~YoE-^#%68oT9#WPcS0D!dBYkl$>V{P=fsx`V*y zx8>|?B*Oi?J!&}5aQh5gVC;n%IBx8glg8f1aNi6()Yyj`mO0+}_(vL^kbx%|`!vHf zhHoU6=Uic_Uqbm{yOfVid>h4=i~FkZg%ls#CB7r&J1Bk$zsm6147|?R@6Esu8~YZ+ zI}E>W_#MOgi3n2e%lEs+zTfcsh7TA%M0^7BTeutLH`^t@j+8&6_$B-o8Cd4X_dkDp zma}sj+jBE;Yh#aQV3~iP_b>DAGj}xHnfSZNKVi;4w#)G!DW5>`OZYAsxT~>S?qTc& z8MxHg;~BV@vG+FI$8cZbamYX60oaE6gY9zs|85>Y>5=^%DOZ~CgA9+zz~>wLk@AHm z{Fo!;amIgw;faPPW#CJUeby23WyXJT2EN+ZR~TMvc%$LXhF|;_EPX$6ujBUgUgQ7H z5%OW<-yGxm{m<8jc^SB!v3D@s(eMcwxVy1i?rH3qSk|iGEV|j$Jk1{;Y@HE3S49_;aI0Ii}?AIHG#b{`~AW{<1y{r_Zu3bC(LQOS%11&X&fA`}zIl zX5gr?w>Mmnfs2j3)Nnil_c8Xq8F+xP56-~Dj9sU+L=O4E z|7+H1s#5+sWmJlFI-nHmv^Xi&DOFOeQ*)&FVUu3Vn~is{6WJX8^$nP{rUWF zWw^az3^#A&U+^`#mkD2Pc&Oo#hDRA5_YLz56QAW-#(w43WLYD~|NQx|e4Vi`GrZym zd6n_skbyTD`y&~6i?PevLVSF(rV#T!!v_sVQUl7gyc+IcxSQdm;XxUAxUpYoc=8eQ z4C7yuffpLP<;BJ>YYK6GTE52EE#GMDs|??rfn{AH-oNFCjeU#ZZHAvS{Jh~;Gw?oR ze>VdkF!m1&A2uv&8u9U3Ze{Ep40kr%#c(&nvL+Jm&vFlAFECte_;kaShKCs*k%7k; z`vk)?GVpw3Uuam?PU7SLck@oOKg+v~-LkCX#OeK}d9R7z@;kyek=oTGxqI1HWPHI%O=f$hYq@@nLZds>iPT4K%6ul{XADKkX{d{^WGw?8Dw>-kwEsrwx z35G8*JSzjwHuiaj>of2oW53?;GQ+YC9_QBz!z(lJDr2|2(bz3NZ0y?%KWBJ{;WrGw zY4|O}vPK^t?*YSK7?ySU*k9J>`&ZoB*xMQIV7N;L?rQAa4fix${tfd;6QAW##y-KY ztQW}nHR%ZXGUIP~p|RH+US?RkXZ&Yp;JL;=KLal^_UjGH zI+2{8EB=r1YLgzzvTh}(-}2qYZuvfA-)Q&&!;fX)=ZxL*i^gtwm$6%Z)!5(6!0#CQ z$A+`zgD3a%?H9|Cm6fsF2>&7aDn08N64}kE$3Hd1|DSW zN6N!Z_>qP$G(08)%X+w+{!5OKry2iQhUXf-G6OF(cFT*6UDn~{^jltG?3Qma_W!^6 zZj&C%8;$*ue>2Pa#GJpDw;B6$8F;6$TYkmZUp4%O;R8p=9~l47GVmA1ex#h8*Es)j z4Mz>xQ7vtaEaDic28=B95CN4Gpal=W&eKPO}W4AoY*e%O?)13Zsh9?=G zVfcy+TyN|vGVmS7zS{7*47|bEGx0{_zc~YMF?Ly-n)B}s!|xhCWH`5NmE?;lrv%JjME#GMDD>LwI#=iCl zd7bg!kb&_F?P$c2053{+;+OE2_Zs{Ah7TD2!0^Y04;glgD7g&t&m&)#bKCjc5AT~S%i8Y#=l2&ioM*V5 zVOay7!*}_HxzNOCxu>!B$-sk*eWYPoPo9rwwBZScWu1BUm-XeD7a5lIFk$TL4+ zc$?v!hF>wf%kUe9-!%M|;dlR!b2iqP=lrtV&e$!VVC_^IDO!#qzFEKnV1J5<~c}K{X8UOi)>kThHLSA9~Ew428wHbJwv2V!0 z_Zqw9jmB1~V)#YFZy0{}Yw~^*{(ZxdZ#BLiEO#_^%bktga-p&JHay7iNW&8{@HAt$Tx0CB z4X^x$d6kLpo96W_o`vVzxld)&whmHSc!%rK2J_GMG_E-PSyw}8U`5j~5mw^u$ zyX6mz-SRT@%&%#C=PnA|TX(iS{9AnYB$ z^NEiK*ARCF&m%qwyq35Syq{R+O59D{3;Y1_ncywNG8bYp#aWR`Fwajs7|ioU%Xj#L zQhAmYIS0)1qmBkYM)Ao~(Y?uk0+{Fbyco>$W6E5Kl4t&x75O1#oOy*kT`NwVs^ZZsamm<$UwFb=dXRQbG{8smXd48{r zV4ffAAu!Lk^%$7v`*{k?^Vd8JKA*l%e+k^3_+>E9FYyO3&qwj!V4mOOZSXh>{~nm< zOZgj^zd!#3%-_HN9n9aKH$`6Zd;l%L{QdSZVE+F3STKKo-3iR!>z)Ya?_W;>^Y_6; zVE&#v2IlXnPXqJ!%ijg__sA7s{yudGn7{x0zJyO*&{>fmfcg8;i@^MSXcd^hC!GT3 z?=@$F`FqbfVE*3oaxj0tv;fTClU)Vo@0qRz^Y>uO!TkN!&0zkX>}O#9zUfXdf3I~H zn7>E+PcVN!_7IrAhk6{$-$OnF=I`}>1LpDSzXcDa@$0_>^Y;Sa$){`5y+9?$t>Fpnp#1M~QVC14&u^Aj+SKe!3ZmD$V2fH84<12m*=J6L#f_Xg1R`6x?e)|P5kB9j$@JbpV^m{OmSNtQG$0O|l^ZSiI zgZX{(U%`3we()nOzfb-g%=KiB|!Q5YT0l1i+KgWaldF)~^ z_fJd*bN@>%n4j-11@rUWe}MV<6^l(p`1x@un4iaQ0Q2+lPr>{=b32%yU)F%LseSoN zFt@*d1?KkYgW&WpEAlv)+n3wG++Kgl*k1v2`}uWnH`>3<1;*{;{a}86`Vh?Ve+K5~ zlO|{zaQa(<`FXVsnB$YVzW8~vi?R0r^L&}7f_Xm2B$(&3>;rxn*M$F}eG2CJE2VA2 z^H+`n^Zb=#z&wBDBrxx92AH4k=YaY6t}rZfUGe;~OTj#!=rV9CO0Ucvbpr8fa1Uac z+bK@G5j=?a5irLub2o8+>TkfD{vF^vx_)+pI}^VN=KjTf;3U}(fH}TH;GtxfwjcM$ zH3xHlTNGSR{?c~j{;)1!?hli;Blm~(1oQRR3(WmteZkxxHVDl9VZ*`PA2u4?oSuir zf!h;L26rH?0e2&w2QDC<4~`Qr2A@uRJ$MlDO7KYHRp4>N>%m-K-3R9L{ScV1mnRHw z1M~duFM)Z!=~uu{NSodLvLdg6cM;26LOkF2pTRBBMhgB1z&zjhCt#jm{4ltf{BzJ& z=J~^0fqDM$wqTw=yd#+B4?ht+o8s#MzJ~ZzFwX~`1oQLUnP7hYlev00KZbz$`W*r0 z`L53g^Yfp~#l!DEr-1qTlV=mQ&ja)O!uepnU&`D&qv-v^^@dl1CzE{@nBU*62lM;K z`@nt4U!G<7eWA>?GneeofjblL0N+Tw8@!hIP4E`tePDi{|5q>{zdS4TqW8sz!Ii|h znA>DHaceNYKbL1Oet&)fnBSjw2lM;$VlclyPlEaVc^~k4+FvD@-=_})^ZRspR^#{S zW59fTlfXQFWIC9~W6TEcr}otq#*Sr-8~HBE}N&xzd4xO zt5GnwpJi^FwUnP-z}FG?F!r8c9>3HJJe-cFFPO(S4g&M|#^GQdzc?Dq;|IrqpP=|A zgL!;l4VcFV&I9xK!1-VvAGjFI;{mS+pFqdA63pZGR)P6>U_F?}?>ESSsFb}&DG?E>@nAa8)5rstt|jQxEue{b2pO7J#%o|e85{vK--IGc`l44A*4ngs4b_8DOQ zK58zQzmK{S%-=^X0`vD#*Ma%_s1@M(6#pGy{@!UFn4eGY1@rUuCNO^w{J7ZZc(;JZ z(D$A%g86&eSHRbk{dF++C&=6@_mO=+_-SI9J7ov)7vR0b+30)W{)1Lv{+_fQxGSZ% zGnl^*?FQ~c_Chd!4;lya_n*DN{C(#D@GJ^1eN+7X=14GqpLrpe=U1o#bN*fe?n3=R zv%oz6z-8buWS6--cz%GZ!L!J|49xvUw}81nO8UC^d-)Au?q8C=E&e|K5io!M{xtXy z?eBSTHl3fHVE*3yRWN_A{ua0=`M(S9OZ)+t*RT2%%SYkQv0+uxIOW) zVDA6#3?54MeDE0J0`L{YCE&%xy}-P_(s#kPkX_E*ZNz6wcsvvNAJ$g{??M|V@C9I= z@3#uf^V3c>Tnpy;W-kZx{I_-B&9uLz;9bPa!SYNO_J1pw=c8Q%mS@UfzYDyM_#|HLyGr1^+!@?%#h8%=4*!23gvAd|@Ag z`TfA>;CCo|Q`FsTKME}Oh!B5U!=1o9zg0fCBl({K=J~>6;9Rnw0ge*)2cJ$n1pF4I z?;Nn)Q$l(!0Q38ZDlpHlG}Uk|nCDBn9DEJMR|lR*yc9f-csY0>@vUIFr-k&a0rUJu zcY$9g`~Bc)!5!u25%7gnUq1z2L3a7Jel_uL!5fKpfwvI<5xj$VFZfO3_rUKHe*pf1 z_){>iCmKOpiPsZt1}>)bwg&V2=wrd7$le*8s_t>T`Cz`j3c%y=Oyhr9krFVM=U(8; z$S!R^p1*Vucoo@)gL(eZ(cq0_9|z|7M5S%W^NH4gc|Os3V4hD@+KxP*=wfgLZSau( z>%pyvr7hWkcomrE6I~DH`9$vn%QIAn?_sb!Lj~Rp=J`XP1Isg0uehAF-Yevx4e~awR!91U(e0$CFS9Somqw80`olX+>01qJU z2_8z^3w%CtU+^?ydDf9)ciIo;^_LDB|IfjFDSQ(=+jk*u0p|6G+JM==1DMyp z_%?U|g_mzjdHtLs!}4t?ua|QMnAgiG2alun+F4-UpY(0;`W~afSCYSc>&g3{4CeK3 zYQVg{%{=fTO8+;Fqqeuk#9A5 ze9LoSUf*R0nBQOR2FFtkoUF*3V1D1W56thY4uJW6-61f)|B0Y4h5O%|gL%EPD45@u zbO3Yzau@KJ)D0vn(gV!ngXCQ-j}Phv=J7>+!My(8ATWv-OnBS*f4{k;FmEd6%-zqS_KV1*z_qq3h50L-EV16IF z89b5Ve-6y=M|ObudGhyQ9`E%AnAbmj8@xGHp=7zfT3&zjL)f3D_YI$cdA-;y^d<9n zGx=7I*DE~+%)^ZWcoVE+E;IxxTASOMno0e67;d!Th-?*G0Q z{3`xJeZC2@9CP3&AnzjH2ATW6w}TJhoCSa9Oa5;_=Kjuiz`3~Qga7+r9#8QxnERs- zgLynfF7l51*IWNT>fQy+%CcM^Uu$3nB({!&2O7vtgA&r3k#!gjMuZCnjED%8jLZ>+ zK|l`U%z$Xr4;es3Qxi{-+nKRL9D^F)0{*V!+ra&LpQpjk zarU1B|CZw~f}ijBYv6vp(Ocktzp(ef_c;IfZBU)#2ZD19Y~ec${9@-mzXe+1%m;z5 zcDw=H@At%a^Bgmqd;FH?J;%p``}Id`dpV{x{b}HSJ=3Y+hd6V7OT#g#=`RH5nAG?Z z@KYWC7Pz19Tn)Yl&*Y|mF}Pokb|tvq@9|o2zn<+T@b{ek+ra&Lw7bCldb4}M{rb2q z;C?;aHgLbb?P+koKjU-Yetq1F;C_F<*TDVyx3|DwcHw&u+|O53p>JA)IV+3*f#7~U zAlDi^@63+?_v-@(fv>uL0*81#|y0aKGMn9k`z#y#d^xzqJ9}pJ%oa z+^;9z49+z$=Kh1=ettEq#d7{{hk0Q*gy;EZzzfqG;Lm~2H0Qv75AN5y{}J4;hu;l8 z&guUJyw>r*f#)2r#8~uX$9sbhbG#3@pFijaKBy2t%s+tp`J+#R`~9@D;IBIU&w#({ z_*ig1-}D7=zhCtU;C{aCYv6u9tp(iguYU&kd+zzP1KjVY{|#_I|JDWW*YjQo?)Ot) z3qIY2_j}-Nj;{yz^JD)EeuFc=1AM+q&&}ZHJN^JT&vKP3nRpc3f4}fk@MUI<{C^t! zBFBFNzTNQ`z;n*MKZ5)3A9jOJcjkWq_s_q{kE1-h`G^C+{rc^L!TotU9|wQb>34)@ug5+P+^;A9Jh)%){bg{!e*CN8y`B3rz$ZIC7u>H0KNH-a ze{nYWLZ^Q&xS!8BAN)p_UYCI1@A#GAPdWZi;2Rvj5qyi|{|x@L;~T;K{K97NQ7(NR z1o!Llw}Nwxh+N6Uc5uHwe+T#!XTB4hYer1}74Yef?*{kt9q)qga`X2UXguC>ychT$ z$7{g-_Xf4#RnGl7aR0r*5b$beo&i71@ngYj9nXUgaC{>8k&aIV_wy~&!MnTX`I8^Ha1%?5CP{_{p~KVP#M ze7v*&Ah`dYW-GY=er7xPA+EpK0Y267o#1}H=M`}O{mgFg{!ag0aIRUk@=}2h%T9B= z7q~xPxCWeSYE8cu+|L))f&2NQA>cEeeg=HLVg8TW*PlEgN)CYt6`g07puP?*E zr#kmO3-0IZ#)13tItjeimA@0gk8u1Ha95U^Kfgy{dl|%+^em-mk_!eir2HekwT?X#w@796ua{4z!d;_@O zKXoIxpFi6S?)N)=5Zuo%ZUy)AYumy7eAy0gKVP;J+|NJ00`BL7cY}AwoRrn4cftL9 zaK%5Ct_SZG@fz?+&VDVppRcV0Kh>EJ0r&II8E`+Jdn~wr-;j^^L~y^q&Q$O!%&A!T zr-S?bb!LK(cINZI{riJ z#5*E>X~cgR@$C`+L&X0U@sEEpQMeesV-N5tQa_`teCa6)eqRLVd@AQ?m>vtjIlp|O@(UyTn{>1v;DhW!{2)_4D@1sOhx?j z;B3E8B!c@b;C%mltnx1K9pEYDH-qziH=m&xo`?v% zG>j<2zefIL`IqD0aQ>x(PCBTMpkO5as7PznNE4)KAx%euewvyY+R4(n91XHm$x%5+ zYmIa#N7G?c9!BL6R2f0XhX)kA2!9O32wEE%JQ^B&%FuQ?69SPAc&K2ykj~KAbS8u@ zOZ(|;FdZIDv-CbaJecO_cRF~P4k1bp7tP?p@Zj?B;A1ZMo(uBEU~5E>j|lFB;HN_{ z(<6edkwIr<@O>mTGee0pA#9mU2*XIamXR2Zq^-x9VF4)a6Wpa(dg^&)pVU%~aF70H_v>F(n52oXr!fo25 zVIfGoGZ}CXj*icV6dm6bZZu`od8aopr9Uv`jZ%8WI};J6OhuUTHccxN@5aSeIuvBc zL-cqTSJI*K!xfeXxWXIU9?I}R8UoN1Zm<)Q68F&3@UCuzVnj}L+(YKWHlqPIB{q%2 zBt(rN)22;o4276?#)E#UdB|GI#kI!J0Faxx#Hew&q+#O-COOPUNN5^Ebth-x<6Zp^ zjTU$)M!bu^jiEx5tAC+tkgI>8!jNm8g=)m`YCeQ2kJ!>X#8!Mwhav@O$fTxln>Ird)1-C9O%fnfifNNHIvR`6_Cm<8!*>P|VbXlk5T}QRpyosA z9^Vvh`Fti+2;4(cn{U!PIHN$hre~<~NDnQKjV9N!)2Jn}F;rmcX}*N&0v@V5?;&vc z;4MO-xf&`bOhfwduDPP+xiM5m$~E`3JU422ZVXKe%tN{6U2{LH?u15`aw*}Vzk%Lb!k?%=dVxwxIva-Gw1pBpBw=CnTK zLeoACJ+H}`-mo810`AHkTtgF@I>aP2cD$=UTAp%Rl5$#7UO_H_p4{b58Rwr}>pLy%1XH zg$|8()z`K$r=={XH7cjAOHSLUoR&^$x)FM9t8yV!}c%2Q5rBNs|F$^;uD#9G=U>87Sl%4(iwwdQBF>Sr~tvRe7GnpauPtE}cx zR`VpQd63n%Dyw;s)ix@pd63hZF5MwQ8`>z|S$4+fL*kEb(mcp&4bEyBW;KnoT9c*2 zM=Z1#ldhRu@oJ8693^wD4xM@Mg5|X2Pfk_Oy}BXkoUdMaHr;*YHTG&WEy&3}SYoVWMGPN<3~_ zA3`=saKy4!JR2i~jK~KM;gY6*=pyn>X}RZRgikI_U^)~`H&_epcei)&`UAcoxOwx@K;H-8US*yNUxn+qg!Dn>wmtwvNxsc%ey$4WW9%Xv>QmXoxWkF=JLv;{}o;Ix*Hw3d&ww)SZ)A89QIX)OoCG^K}Wy%?sA(lBiqhG`=_ z%$_c^QA%q?7^aP5I`mjFYIqy9d^Kug->B&} z%*I#RDKv&j2#mM1a~P)KX$&J4J{K@Ac$fN<*2Y4uY1g4Wht>ggT1&1Dk+eMP@JmNo zY3 zNKf}AmW|rQG#1A166?moh+4UJS&dfTv^3?kb;#LMmgZukjoWOzsHHcjBc+_CcB6Kc zInAw{rdm$pnbY{?w6)4F1T z1aRvYHQjRBD(5s`a+)tPnE-u@k3MtcwDig(1l?Evv{cE|1^tm`DW|3CLKwVXc9)nfn1BQOvaFFm#XDfreq-3p;FfJ zOVe4VX=tt;ot8tHRDxX7OD2cFwfxEi6wS?^jy*NKvzoqHE8h|CfgHdfF~&gvs~Rtr&9D`!>N zMvG`hvo)g)c19ccj5fs?EvgyKZkZ2dRSfxM(;V8~i67P)YU3s`wHcC(wwW1iLo+&T zm8oC^RGrMID;ceG8BNZNW@kq0u1p5Qp0*_!&DM-2t<2oeT+&fyZs?CbhG<<%TQ;fv zwCbm|*re6{v=$c`j-woFn_j*NfZI8?uz`l-H(>l_W;XCD8mvjUva|@U$kp~lbc#sLXyi7*sWik?s*$5`L(01Yx zhNUrYGZrCnz?i1E1x=Z(0#hHD?{FpDWFi)fMH@Z@6`8cnH-#dN;htEKTRt>RFcS+Q zl3-#lbdMMUiUqmlL;B^L?=TOcgt^{BvjjaEA4ARt13c6>xFdHw)~UYTC7U4+`WTn1y-@C8Pwp7ROBD4E zeJLJ#hqlFlOP*rNpy% zmvoVrYMjxO@=}<2*8Gw75cXv{0MFCG9dJpX;#~@;w5xDWtDbZq;9Bc4`q-~`Og?CQ z-^>g9j70FA}@SV*I@tZqq>HC_`XlwgmbG|PxNfqaKc+cP2Ilqj;jMGaMLJEWh1Kwf21n<}@ zdTs5CmdJX78MBs@I1@}}w$5m8#cG1i`9Z0;%AxQY9;+rg7kBJ!GrXfmVm7zU#5#Zl zi#l7IXU*uGQKA@V3#)1h-{D zTft>|6XHL&1FJR)Vx|h#m$dCw3QXACI=^)RR2E|?i7z`P<|QUl-MD0AA7ZBKV&t3T z{K7?@b7!AjSUnSRW>H(~!sgZ`T)N`@E5@}nYg%T`O6s>RnYH!p5Ov|7X3;2PcdjO!$``0?Vm zW2uKL1IDKdjwiB0|n<@bo3*yI&l)A}Qk6Px@%%I_69vB~=a z*DitsxQI(od{Zw>#zMjRA*mUYBe^C4-Hu*Tpe=Krh zlTV|3Y=~}x*yL@%)f%2o>S%fro6d44CpP&-PEKrc?!jCCq=bJ1aP`jw-|p~Tz%{yA zBC*-MA2_A@+oopF?F9V9mS6w0*@5}W)~%C+tjn|wayTE~e^z67}T zRmoFglP?4Ar*dMGuLQO_OKkE>Dc5$D*yQV+oY>@d0@w2}BV2bo9b(hrzFemB5OC@j zqW>iIHQ$L%pXYj{o)(>*PKVfZ`0cOd5wXd+r&{$d#V+?}vocIik#Tw_fY;5krSKzQOX||IkCx~qWlSw6Px@w%D0J}*yOt?|Eb7{P0l?K zQqM`cz3VW)<*v~US&2=bdm5zvQ}mB;cnGlR6Px}R;Ogh`hl}4=+gOO$bokwW>bIgZ z8@KA6g6H98;}BxgZ>L<#7_rH}MY*;=#3tvy1F7HP57))i(RPE_bgrRX+YMrqZ=hV; zD`J!1O}VyL#3p};a&51OP0l91_Ih+&xQI>8YTQrd#3p|h*xDarlfM9*;vcUn=;&CE z*mQW7nYB^GCg=C*rcZ40!IbNGkJ#j6fU7m#CKCT%{5=)8{zbvulflxK`!Uq~Ov)Is zxwC|F4JWb5R{+tS2CRq)Y&e65t|P8STdcvsq=HuAvT?@ zz}4y(_h71dN_2=#=NZa>A#!4qKM$OGS;EQh&ug9*9b(hrcju<_7Im~95u46?)cJ$B zQ_%xD8ct%}a-6uA8uA%%Hai7@a8z}#k$catPGry`|6MuQut@%Z4 zIKC!exrcu0PvR!e?5f@+_z>Xw*99L2Y<>}&-Hg*2MjdsZ*mSt( zermV4Gle=DHe%D^*;_R`B)-HZUkF^!g9>rAQ|H&BLu@+Sqd)bA=q#g-wtK{;b3S$6 z6rDBH(L5qH9q!$4I_sPcvFY68Q*D*G+$+@S$*?k7M`Yj3P zv&3%;-bwt9V4lNO{TIQn0@waW5u2ObXQ-dbiB0|%aOz#re}{JODPq&%9z^|APHb}S zMO4c}Dsd5;oO=@WQ#rB8xi?Ymy`oQSa_&*oPvyiW=Uzp%_lZ8S$!n>va$=JYp#J@$ zPi%7TVbo9M#3oMxSN~P?GsJrY4+Bp9x8M=LwGR}r+2y`b{ZvkD@;vn)6n$cokEg!M ziA_F<`ac$ZVv|pyzRHPBK8^b9Byka&d^+`2PHggaU@P0iCg;9l)$fTrtEuy!_`^kP zI+s!BZ=!QGb)FX;V$->S^52S_*yI~1*Lp{6^1Fbm+417y(82mFV$dSZvCDn-tb7ui&db!P z6rEkf8W)~jW@$of`W5(o-Q>h3=Q#rPRpJi!%rn1;O{W$()kAcSB$bb4a% z02_Z2o1A+Tr4AJLxgU{@KZ#9;`w*E9_aL(JLu@+Sizs!FxRardhLhNI#sODXi_S#g zdLD|5i~Dw3+=)$}`xjZEUK=2ac zPYON0An2KTvco2d+L+FwfqqK1%R)z-E`&?A}88 z>*6M{$v0E3^U}m7=ib#RJpkiT>g*P~#HRBkaP_Ce-=~Ni=2viB11y%I^?4 zvB|k_cS^%w1#ICbHXWYLXmPJ0K3e>$rT!Lili2imc4NJUZ4hIwkts ziR%TwMtu&zaS@yT9?JDy2C>O|;pJ-UIaxLz zNNhSIDA)NwVv~=fT;~IcO+Jj!#zUFjzR)UQ&h|T>P;8a%Z9!4D2Qxh)8YPtmbS#EQ%#-EiaUo;N5e^MI)i|# zM~hAhxc+m3kELAGD&UG%8Skh>e$?Z)47XstzX1u_kQ5&v10d8>gc-(V$*q=a&3!+IZHtIazKe2g zi-=AB9_88=5u3bcpJH1?Z1Mwvtt}!p`C-7;77?4A=fR}LNnA42(Y~A5bVfNjvB^)R zT+^S}L-Z)<4*o0u*H`+8%i7YL~}YXP)FZ`5Sz|Bl)oi)huGviv&rfdvB~>VuH#Z- zlMkg_$DG6_=eb1YFR{swclyL8pH8{XaS@w*Hsy~?IEhW(PPx9jBsTfCDA%zKvB}p^ zu5($$Cclz$oy#IN`E`_Q+d^#eTPfE$E@G4430%7oFF$b+n|w2HKa~@k{9a(2<03Zs zR?2m*iP+>jot)U@+}|{Hyp)YYfUQj?Hk~7!P91f$ts^#_9B{R|GlDwWCKH=Zo^oxI ziA_EcIQ4l61NTd{bR#w$?vrXd+#}W6WMb3dUa6^x;?6?qXgG;YXE|{77et5WE7eaD zd=d4vJ`$V$mB6Vliq19E(K1GCI`=p^vB`PJ3J%K$~>{@9|2tbCDEy) zj;?tiHk~2BsVSn?`fvZmxyUVDfb(z?7E~Z@5jo9StDA&44Y;vAkWOb9+SIVw0atxwePICO-|h zewu`V=NZ{MbYjz4NS&{UPP@aMz_xyd*z}iDj&(16k!8e`6ECA&*S!#%{&HYjKSONt zm6WSH#OBULl&d?$rhh50t)C$_`PGzHOTH7E{8lF?Hu;^vsgotXcM*S8@ZApI16-~0 z?Z7p|#eHIP=XvT(7rQT0N5epDI=g^VUlX0TsH5%>n@%+n&)N!NllKKq>4y6Ksbl5G z>9E!$e7~_9hL&;BJZ(DOm0d%TXv&&M}$5Y8xpjPb?tg+hF%0n@#q`0=_E?inVh8Gp_AA+Bw>h3f_A zF|F*P4lmv<4&=SD5WV_3Nm~wg877u9_BNJwfQkN_@&0l!kzD2;9^Fdxjz>JsG$q_k zuLECqVOf7eOT(gL2H+aXKfMIY|FB#xNU^!;h!Fvu*6aT?O&Xs}noD%^&joks)t5Y7h{u$4qYI%b*c)6~zx}+)=WSg*X!VX&b*n0_{+Ii@ zePuk-qw49prv_~wctkRB!Gx9`Zzm)~49A9*nN^vU4TZFz%L5O5y%6?p6MmN5*tGVn zH@o#YtH+*SUDDQb(5ef@uXh?nx4d5!+rG1(KGA3IZV1Ui#gOctFuX_N^^Hy6Jp8j4 z%&h#&C69%$d}sXVZ5IDxNX|ZUSz`3oO?W3c`tfDR|GK9}Z}a)MVb$?H&DJI~Pit3K zB`U{H>RC)-y2bQ4`lR37mppjT)=j7!b&n50dFr01+BWgg$y=sAWG)nK9sID#4t`?h zIO^^mvwd9t^BX^3H?eZY;iy!nqsA2Vhpe3Y8?(`^>8J|BLoS&6v!d393ryZ^{81I# zR!uCFH?LE~Lsr)zPtA_qyA7$VH{8|qiyr4rn7k@EVe9I;)fMZCF8*NCXCFK6;JSyZ zwiHYKQ4bW|PCr(}AAh2V&E=wGI8vC(vzyaM88^_d*J1!|{eDp~xmbX4E zJ`Z|u;{8S6=RRC?^XtyXlYVc0c56Dcka8PVe)WkPQ1;F2J55Er361O8RXvdYeJW#cM7 z&lvWpT>j3(_Z@xGo14CT((gAht}J!Ku_T2huTRwh6>BSZRrjf^EQHF+%Gqa*3MIK0 zO7f^sk_T-cz3sD)HLU!X$2Ju5*q7(7rtXPi>F#Peq=X$=!g63gDwHl?6N>F$u~r>@ z(l72ShD&N#&q57jxYAEFti1k-zdu}S-+Z&1rP$x&dm^EI3C1S!Y5Fm97AsPg zF3j6ok12Fn>{jNZk64J`0=+N7{Y?DY^sdVCMSDVY*_ZO7p6_#m(Em*sJNDQCgIn4c zb#!ztS~S0Y@`M2hQ++zqkZBm&j6D>wgWJ#%M-LD|;<%$=ISk4Y$uMrJu54eD&CJcT zrJEOI+J-i_;Lp3S*m}_302Sy#*>@MO@*Iy-?%KD$#hE=ah9KdhEQyl<=$|(y?-?}s zC+?xk)=N0Yd~ylr*u?WXqiR3q#UYE>FUO1NCiAymoIbf(>}kaluOD(%=ulVH!sI8iu5mz zIKRR4?#2A-$o!W5p$8yr6!0ht2+8txWfZ_fDgyIr{?yyGK2DdKd`>;M0qpBRNV<|jwy(<6RL#7~R( zoHD#EGLQK=k$KFQMdm9bzPb!QKQfOwzoqv1d370nU1VO4-x}%1{I zd`n~=^X-xOj)=cfhQAe=zf*?udvG8A?h&tw_<<4U_u<}tUBojHAMN;Aut8DoZrQp`Dy_2-slr8|Ghc$@5A!V&Of>r^Lrw5exEOwr1zGH zZ;SYoW%!QB{Mj=6#mM~SGJIEL{$3egd_b4@_3mC8-@XxVh&cBG@aYrt@sWAVxle$% zKcx&mF)}~344)mDw@3V(h;z>XAD)$E`0B`@mzCjHN9NZ={JJvyhRFQJh(GiZ z^T#9iK5D)#azExfBJ=0V@STx)%wLSmUyk^D5$`RZ6e5eIzSKtCpIOiLCFZF}e?%ER zIWnIT@slHd%6{@$k^V=`xxa&4l3p?Aeh%JzX&HV_WFGTxMdr&Rer3dOEW>Y!%KT@nMplX#>41Kf%6X-eQMU*7(m;Ki#l@$Vqj z1wm!vUf`7lo=iLle52!Afc^a7R&YOm_fv2`U-@(JlzV=quAh(i4Y+?E+X?QU-(CXu z&jYW5`|s4zroW@J^@S4(`X3XM_9nTn_HXljni^@#MweK0H@|`~Kz{@bRwwyaC*gmwo{5 z$3wS+`|-{ua6g{84}6acKbOq-@ybuZ{dnb<;C{UFpWuFc@)Gzs7rsA%`|-rv;Ip0i z-@yI&p$DF&Ryy;8zVG}BZ=V{$ef#uTaNqtkf&23GMRFG& z&K>yv;A`N!op}qm@88Y<@9o0V0bc9)H^6;=)&=hSuM5F_`Ckj}=cm?z`}vpa!Rzpo zE19?j*w6R;E4Xhj_-xH*1JnNz_)^FDtUb!{pMXztoX^q=9sgBi|9Nm9-j~2{a{8}< z-{tt5;9DHu1McS!yP>T5`MzF-vdb8te*pLK=?m`L+an_LBf)oS>}mhg;QoCGpRM0< z<|Dz`=E;=|&%Q&A!v1)e`}bRu!2SCyKHK{DRVRb<*<7w`Cmr7c?&n{g0Qd7RPl3PT^nVSGr5^?Vb^`nPl0SeS=FHjF)j9q)F!NNd zWa2&GQI1!lF8lU|ZK1FKeIniu+^1(9_!{Tl(cr#+9SZLIU#{-(&+ntbefy6^2#GcL zS$Mw)?EBY~zs8>szxg(}e_p%-+_%U7 z1n&Fi?}I<%+Pi-N_v!g>;J&~A5%_ec|1h|3KWNvFe|`==*_97I%lP{LTkxT-zVcaw zdwN>@{{+6o@wdR)hnx9-gZFp5JHqDQ2Yw9vG-qA|?%U6ggRgVu1Hj*N{8QkVm?`+z z0KUhWH-h{3Tcf~lapq&e?{<75_@j=08GNVX#k8iEXm4O%ZQirJ0l(7mGr(_joX-|l zJAO9!I>(oTU*q_B;C{Wpx53+-`C9Omj;{lM$nopJ{rhS@JNWkOU%^jv>Bqj@kAJ!C zke_dU2;9%ta{JdRS0A>6v(J+&nfMj>qmDmMbCd})e;M4@kJrE_Idg9Lu@V15#OFku`+C{M_;DXDyU4k>mR;oCxM)`|^4f@xiTHwuUlH*iNBr%G zA6#6l6YAlRh>rkgd1EkZP(QgZ58J>?mA6Iu7lU(rYWg>WvraEj{rgp)<_BYi^3TDC z0v{PT3Wr-5#tq0|2QU<^25=511EI&$;=FYR3pWaJ zW4LgW6U_9`$Z+xzj$LO&aO1f&aE12tI9QzhBt~LQPnZh_1K}X6!l900Uk+%eTzoDb z_9%X*^}OJ8n&F0?p5InH@{%!xJRHD-fRO5Ov5*#y`BK;P7_q{!Um-gx#r3IWdC*Fo5(4fL( zD<0M=(bnU~^t3fSWG$Q#RC*vQ4&#DtoXiy**7)f8iFQ`6qgrzCmSO&xyJxp(;gejZ|g@P(k4d+RLX?X~-fK5Gma<79{&1E}!G#nR2 zeN7TOXw?p6&5AFDW9IZ&Iyn}MB}L+!*5mFPh3bKip(^7nI|-W>HZ8$=j-9%1hZ0H* z?MOrkQz+6XaAMXdWlN8r)6?!WRCYe5WWSztC)TVYgxs;jk<_&$5L=pmqNjEx-}Jyn zJ~fb;4;6JZWN4TMG_;_&^o*8pZQy=vR<5^Gu-1E z*881)CE*Qc6EQ#~j_vzIDVG*)i|5bZ>zFNZk>7tUTF8Tl_7%SmIK)d+C!C@Zr<_EZ zZiWt(>$OV)9H;F2XzhLCS8TDRbLqZL-ig&hG)h9ScZP(+y5=s#X-#t%%xEt?okx;^ z@hP67G_6 zA66C*0pWEa_^}yMreMa(?5b3Ba2;(H2Ai>y1q1J%jUZcQ7Q8UgqBe|m`G{7lV}D}% z=9FvY`>CARD z$U{5VU03s^1Fm-bYK|6tV$`8t^~Gt5u48Wz%`#1yTm5vd#~!* zV)t(9q(q0oq<3E~)x-33Cp&nq$NrV$&bz>Ki-Ohg9>C-o$or|B z*yN*tYbd})Y;w-A)z6bK@EwTN9b(ft1=z|MvB~EETiqcxc{}A<{NW-tIp?2Ke6faW z8FjR56Ppg_q*L=n=X_xEm)LZ;j?v0CvB__sJcmDA#3tuFk@eBqpTYJsHx@zg(7^odQM?@?0=waifGGoo{% z(>cZIoJO5dqC;%%@O^7)k+>7ircoV#Hccn(@?{<_Vzc`#%14Ww*yO8$tqc>JoOAb9 zmWWNx_arr+6L*MB&Ud+{Pi*pa)Ymj5HaXV@_U{>jnIJa#M&SB3i6iI#Q)dd^0&HnZ zZ2H@%qZ8HJsiSF2Y&tuf&U4h!bR#yM7pc=Be!WZ`Ef2(|^9JQw=7~-I9&k!0)4QV+ ztr;WfLu@+LlpiN@Vw3Zoa_uSNFR{t{1NT!ovB~*f#pJ{$9|T;J7x#%xo}qlK$carp zit=$HCpP&s%K7pa7qQ9t?%L9X*yQsl*EAtEc{{L`D`Jx`0k(W6HaXYIr4~y%ECa3? zFJT}yohyOs^(DnRhp%<`M&Md~5kYKrZ=rmKxKC{ITY>wjKC#K~rd;)jO@0q>%>)S> zvB@8z{F_pqiA}x}ICYlz`=Z0IP+$8mV$*+%a_zr}P0sf%H50{OVw3Ydi^+*i&i5-O zCpP&|Cnq*J-?dx+NNjSxXR-c~*yQ7Zt$!poIp0~;>x&=Gzgn6Qo6b4FDJ}@X#Whui zS5RNmgxK^ird-p6*yPtxu4zJS^4px8*yMaCVsRuk`DS2?BeBW(j>O_fZ1QJ->(7z! zk3bxfUk*`8j3eeGvR=to1t1#}$;Varq4!tezACn@N{8&g@)2*fGJxU5uS$c=y)bql z&UQ&DM4CasxQ$VR>fylHbVSyWiCJ%$4Z@G^p_vSqZaJ<@%t%uBu}dhYmxd1A%izb0 z+lrqlF#Lz~25Q2OdKTW5&^s|`$RG81jls{yV@h83Sz$bw1~g+lxF3rTAJ6hJH(*r2 zCj)zbsi$2X)e3qiC>}#0t~t(Mz8*1uX8_YZD_YOPJ;M+OGn&uC4{6s%8Lw)*QyL^N z{8NV)@0KRyBcQkINUR?K=A#|`t;UaGu)F|F3`PdMsP9e4&Ao$xz20)fV;L3nGCe+c z;vn(Ad*7B3!-o$G+qMiSzi&(50TLdTRX&*>h*D_#luUeb!^(!jt_0j?;QH20J$fdF ztQ`IL@jaJe4~Ij06nFjD*M0|nUx6t-xtmLJ!nxyZrvcf~pyI3C-y?Z&-Q(QNBeSw< z+n}u*E-3oj?JMKBTgm}%V-Js+<75|)O4!)2vbYz-z~wi(ogum&IV90%@tfUdj$8Y7 zk3C=i_Ij9d|BtP!Ca>ZiAeDt3K#IF4$j&UKG3JgBjBziG@hHUj_f;PpV~bl?(+BPF z@WE+eq59x7!M-m0ktR$7mtN<3*7Zm(fxTSDJ@CE9F4;Y1{kd;o-yNp&1He zB)P==Fr(^!F-&6KKQbQ>@w$kk+0#qx7u(By^TDRB{ZwvU(8pVvBv-6h+n>+{OU-5 zUBquH!*7YqH|{6DE7Fho{gHV&{%EAXwG4kMGLQK)k@>R`-x={&9OrnKyeEEEKD;^0 zM>)P5I&vk$_?Vn|Zti(=y0^c4k2sEhDQ_`{ST8Z}8F9Zxj{YAQncF<1xqnDxeptl& zmf^LL`4JHx5b?ng9~N=W-O45Ln_7lXi_CS(7*2@&nCrAg!93>rI9@Pc?%Y2OQgUB@ zygAdm9Ot~VT*=TDk^A!F&FS9$@++PDv>$W7W|8JMMEbYvC%-k)zb)dM%kX<5^DXoDL|mugp(5r(BJ-H* z>xF`T%!ftxbvnPGuhZ!TJ|@zSxlU;o^mQ7sz>jzKIaVj1h`Xh~H)nc%SU%DDNB3er zDKeiLalTiQOVaz4h@V=9&x_1sK0h*FR)&8oGGAVXuZYaol;Iag=9fnNvJc=lBBA_v z?-p?1p8gBCFCQDhefil0?#tgj;66MLfcx-o0r&C$33%~JCVmd$!^^Rkug|{&_vMRY zslhIOuY>#g@=m1xH*oKM71}OeKK=oGj&tu2aG$^Z!2S5X4&0CDjt2MR^P%8OGr5w9 z;o$chMSCzhvfmW(N#K5bcS6LcgBP!4g46Fld~?7LD<~wx_g2Fk=h(zQPn`ok&6#to zF~{-M;C{UDZE&AImxKHM{(InC@RKVU%zXdIZw`I`c00K5pEiMe_xUc|kAEHp_u+Xw z;y(xX>9-@Y|6A~$_*wW~1|IAmS|n^@FdmR^n&wPXzY$@yp=8zMc&3+mB}OdH9+A z*}%U3E&%uCtrPqPQ%CvcH;TS}VcYh+Grs`*I>+hvbBL_ z+?Urk!0&S9My z^t0eq&b?#7S*OhWIB?b><9uh&I%E7x;C?(g4cyn)uY>#g$Zr(c=9qncqqxlRcJRKA z^BcvbjxPtdi}UZ_jrg4r=R0n@sLyZy>>}^k-I&bh9~trEB0eMH-%#EY&K!)L2!aS@t4oj26BI&Tk-ac3G-z{+EF_!Gh0%Tib&ZX1wa{hfRF5heAxUP5B zmCLe@IjqCRLidtY{b5x$gw(_$eX*eH_aT}VzU#p1>wqOR(Sm+maxZr5BLUIZ1>j+k zbm_W&xEtadExXqb5NrXsEYQ|9;?cr!SsZRl@+I7*E3S1({xH$BmHDC>z8=AsAd)h= z2)}gswtb)>QPDNy_9cZxTE9R@OE@*_(vpL^qF$Hq+qVXiO1j)#Jr7AM9|ee239zkZ zmjLU6cl{DU*S72D3HtejE=kX6+KcP@A%iW<*UXX?`MQ){SI_H5AiCT>e3euDl%u#( z9rdEwSFFNHPc9~vm9PBjD11@m*Au`0I@6*>*3T06oTYfZw}r!1cVW`s1d2cq4wclZs!H6uk%Y;v}3HOGpa*yNL)oY>^2QT`dx zCpP(N%GF^Q#3tWKxu_?IP0l{v$PHggtPEKs{=}t~;^7)i&S`nL^eQM2k1RNK!$=6Y?;U_jZ z`~2!BM4$b=r4_O1u%9Qe8 zkNotY0SFRfUWFg89Dc=TXU_k~6|ZR-(I0CqFs{O~mSCT8?2X?bHnVh%vgOHvtW z56mS%Uc6ge$vJlB zxsmjX%_jY=#xGuja{1wj#Pt?+LCf-2aU*NMo@3S z-?0Xz{}B=%mMyM9`3J;?XL9fyjup!tLc(@o(OlQ3dL+KN-yqx2g^@>7j|&FKL3_4OKT|{6iP10_ z4U?`%h9`b>;i?{9M)$gXzXw)*99XF_fXkJweJWRt_yJs6)g!y=<_fOLsoGZe_@J#^ znZpL^rR9kP?J^u2R`&VDR}!BntPdKpvUpZWaQ~(riLRR_6i!mva6#Rw;;No~X$)C? z+v>@ywiZr!X_;DC6?{WTi*65D8SIA8S5{i6ZYbC?8)jm6t{z%@_)$m~SwmD+$yG$A zU0fS8WM$JP^WnIItG0ahg38Le!WlzBAF&@2#opX8-!{0@Y+^Ihv2%Aep{#e^RLRnn z==w@kVt9|luEm$UzU0kIHZ3{0+uGHKedVM}*1k01#DUlSJ~6QREz}8QMd5n>a{}Mt z9l!hW8*p6We|fEogdtgISKf~!itfT(1{j+q{*q`pt-TQ?aj)2H3GXF_!3OpBhqGOZWhz>VI9tQ)PIuf06J?yGl#KM@07XW%&5W z{P>7ZjQELV_{ov^>@s{_WWKBnUmlrXR)$|0ncoue4IeSTEpl&T#P5pu-4TDV4Brx& zKU0Q38=1dWhWoiY*1vZn{XG%yS*X-f{(61H+^;>M)Amef<^8b8znBk*%}Q#AMQruN0Jj_h9-@f#w3Q^aqN z_=6FDJmSwr{Dp|W81YyCALDOC;oTE)zMt~>RTXi*pYrC1M7-}u%=<^~@%@+g-}A%G zDBLR(9E%m7_bU^hEHSSN&*Vk(s>G*ZUL2oRg=c%;K6C8l`vZ=>eEs8jSiU{TgBP!4 zSYzYEdjbr7`I!#x&1Zo7`a37mUj**!#}aT~-uWrs{Vso3g8TA*A-FH^99#MF{#|h2 zzFr6J!*eq@=OpDyCb+g_qvLmgb3Rh8WMVVGcE=w8f8Oy&!QXJ4(}vw$_@4&%Yqhxl z^-yR20=RE){|N5eTaI;nd;1sgbDVv2*$LmD^#J$r=h(#ew}(dh{lWcsi2GN2{UP9f z{F#pQId<^RC!EUk`s1mOFw2!pd@<5L5xjUM6JLw;xsJi-AGZ^*k2FZ?S%JPOCc?8X*ZUy;>PlI*;u~a<10D7 zhzoD^!VBJgy~3rsZW@O-vb0y&xlLaj+Fn@lich!1vNvyhV+VWT#i+dqmbZVpeVM${ zvt7*eJ)^vQEZxP*w(}C(_VQ7zOSnq5h%0@4T>6T*^xZHRgRa}TmA=yj*)oz3!a+cthpU6GumerEMu3%`HN?SJ2|n*Z*+2Ele3MqbRahQMqo<^Vw2ws++Wj& z*yK++IkCxKadKjlvp+TWiA~-eZJxPLY;yLWmj1*huK})R0CDko-tvOjbod;fx zr%;DOL1O9>+JH#f>Q2vI)lN=XkZ|O>u|VgT$AK-6h)w<^u;mf4$)5r?cZf~?EajR<#3p|g*wT~O zfBiv+Y^u@F($R@AnqwFZ z$vzw0#1h+iCK}o?x>(XMqqDPp?##uVtsPRN{;vN4&_Z=DS%*-3?k&C(kJllbav1h| z#~aIDYM*TjlWCB0L_J(n4JfByyi)k}#LtZ1PcID}+Nr^h*U7L@EinAk4gUC&&g*e+ zD$TZ_$MEs@Mf|+KozNqn??CBa2K!{jvM?-cxC)P`HQxOWuOz%J_W;vL1O za6JyaOAnHD4KG1Te;KcMeZeVx@C}%=Xzm>hT{uy=ZvBK`J1zdv5F^{pxeHJ4utf&t z))!=kW=F^ZgYtV^yo$tRcyb{WgRw@VS7PLuRnJY^Uia*v9TT6K{PfhPrayV=wwaI5 z-nwB;#r+izRyt?JWj)rzZHdQ}b?;@*T$ENFIp z<@1R?hvyP?S5@`+?j?QR9-i26VapLc1|2u=g064Y_BnK1;*Pf`BJIP%=jKh{)qvm4hyJkmWm+`;mhx*IcmXXIQ;(@P+^N zyg6RU&YFX-f*+7$ImV~>5_a8hW}TWJp0VR8@pEwya~VC zx+ex+*S*5xQhamYHQ^MvF)6tH?>{|vQss5af4uxjldkH0Lyrf0uYI;RT>E7AmcQ+( z_>PNnS5sx8+jy*!7|(b$CI(jAnOI-(P-0-Wr*Njs3yFaPx+kug^6+1mKY9P--`vzS z;Z|r}vzJdI{V07xOcR4HYFTpt-rRp4@&0b&+@IXAa_0r-{)l|gg>U}V(xK~9O`n{G zvSQrsC__Ph%5gvV>A>qwPY$eG6&8cNv>dAe-q+5<1D;z&*NUYg*|dAg%oDetnE&d= zuhvb!Y2IetZ!Ix)rRwuO+WZC*Dnlu-x~7pA*>bbgSrKOm*9clGw#ny_)E4B^9fpyp^MrX(tPkfl726D#KA)WE(yJ(6735tcOQ88>xtu*n~WvR`|DD3&7r^P zHsQBuF=mLvnq%PplYNNj|+|eYnr77+6K# ztK0e>yw`Rc*pv4m-PYsY?U9Myx_&vYTi2F(-3A`;3i$MH*LMx{OJs#}wKv(PE`uy^|#K7+FCf0X{3pcN+px!Ic+p!P5 z^$5+t9(BjV zqVL%6^f>cx^y}}{E&5VS`_eoq*4~~yO~>wN0}iQMy?s^Bo-3{@mbS(_4j%X0J1{re z+A-&tS+hHjIcjK*a}mZ9|4WOHY>W}Qb@cH6+q_CV*8hF`-?yM6<}v5Ivs_|cXH?_! zKh1|k{xw9rIF^*~aqdd4ee=m?tl^LOiII8CPmRoDJ|{AtAMwtJ^Zk}w65ex+YWS9w z;mafQa(qRkzcS*hBfci$7f1Zkh+h`*%OieW8Gd7AeoMqRMEtgh-(H5_6Pe#1@rNS5 zL;q6b1_@s!R7V)++d}U-F^NS*Lo=xGyb9Kb8 z`CsNYMgGP7w#a;c`9qQYm~V;9`98#_Pt3PR<}rURGJiGVd&=+%%yfGHV}3|v9`pW@ z`4JHx9P!luV|-K;-k6V$%>CKR?B8NOG1A{(J~^_#zkGINKjw2H^LY{H`5?Z$#C&CB zzB=OPNBq(<{OZX3mWcCA5FehH^K1}re*b>*ha&xL`^mRQ`Z0ehGJm=ZeU6KCoh`$l>J!SZNk$LzyKNJY*uPg9&#g~t&{p39({g_ur z<~#$&`&W*qBK?>*MCLIc9hsNolOz495uYCMQ$Hl19ob(J@zrJcn#la(|6zVvUXb**F?N;#QT@w10wUm`^i(0{;_5FsK`9OpL|NBUyh#`>CY^~XGP}o z_LDD-^jDPO7e(fmM*Q**$*+v;$Na9yJmz;t=9~AE-xKMVFOBlDQQ5ShQY zpZw)WfA@#v??(1}VeOr7Pmd_WGm&{Yo{#iB=Nh%*RT;kdsV)dA6IimA@beRggZuf7 z{@{N81zXTkma-3V|$f5~qF{rqem+|Rd80H5jRUnYV3 z`LrqEx8o;QGVCdIiqoGC13&-M4DRQ%W`X7@7@SL$NBdIa9_UpZqv7~ zSkjR2?fc!}zP(|e~eSPP*iGKX~Yw+TgO#BYSmuJ3P z^v~mej?CW$FL|EA1Fe6a>Iv?jhYkYw&o_sG`}F+;xKID1!2R<@J-AQrMsPp=;}&#& zyvKd5egDgE5q#iX$ANF-2!l*AB(|#f5UGNeS5zO+~?P~!F_woZw-C> z`cL4~T=`*LpY8ZRgZt;_JHY+(@qd6{?eu>Pex2h#0r$_x+^70>XZ~w&pP#=2_xbln zaQ{5@XK?@g@>lS_Zv52^ZGnG&;l9*ZfTdS5(Fc6I zPXhb-=)vGio%u1qe*Sq_!Hg~>6Q2e5;U5R?*Qa~|+`rGC3hv*(e>LI^tAD?KI=Jtj z7lQl#b}_i`pO=CA_eot5=lRa;^W{n=E(Q1Nqj;Y4cr!-)m=}{BzXALd$8P~=pDR}~ z!MW^fjl%xFf#2i!J>Y)5z>mQ@QRn4KCboj#?)cBZYmw(>{tS4#`@e$w{=FM?N4fO)7@Trcs1N-sDIp8~; ze=EQzyY#yN{Cvm11HR1h?}GdB&-LJb{PF{EKYsZkINKNtFXxv0`1?L^|NdzU_+aPX z6X5+Fe+qnv2Iv3tbq?Lak+Z+6RXWplf zmW*LC@o{kWfpR4i1Hk?B&8NWq^H2l$7E_1)MsWXp#Iot1uf~G==c|d}{(11r;C{W| z$>5V+c$&fe^VDo`-~TKCzs|MKo#6g?@*Cj(d2%g&$|QsI;a0z z@XK9#@Y%_)C;Ah(@BiNd_x=BWgZuuzJH~GQ`TJwwPdfK&!2R>}$H9+v=`jG@uZR5< zIG-8iN+ue>efeqx_vM3QM<4&O;66MPY2StC%Mm{r+=sUr+?R*h;6D5dzB-1kS=Ft?%@qk0`A8bv%r1-Hb3H>;JnyobFZ2ItDLfG{Qe{2 zKaTjXBK~f~|G`bb(Y^YJkB|7Ah@TtrYa;$baE9IX{&^0Z{okeVi}5+Amy8b&)A)@7 zw~OI9A>wC89DBM94SVbO-E_FqOO}UDWVi=S*hq&P!EjrfaLh(HGb3yp6VB2Io7rTj z!OdgBjx%9boNS=M7UbcGiYy(=g+IC<4#voFOPP^W3rB#2Q%J&D7vY4Aa3V${Rl@NZ z;Y5vaLP%&yVD$JozTMvW9lHzHS zKGTr=x_{76J?A9&PPy*e6MQGvJ&5dB6g~7LZ6~7WUPfu%%*cF8XJyBqv>xA*4#fcO zg^c4}-PHp}(s~+6I;Yzk>2W6Mkp9ruGiB1lbu%PAyQKAWob+%eI`s8Wm-KL^ z5;@~lx{XnM4$KHik`a<3BgEneNskc{+>!LXbo--ell-AQU}7N@9x$<|q1Hg#nKbmT zboZouKEyYl4`nppB)5Dhr(m=IGX^l9502qR|MK||YTP8$l86!?Nf3#Y#tAl%B%0D< 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≀le?79MW=EuU=s&(6Z< z82_1uFE+f$@QsF78jj}LbLHVtfzhnI0GyH+!j|_){Pr?lL<&lF?6z3S`cZb@a zYhHd87aM=eeT@I!=DsF=%Y%$R*WuL1W4YA$e^ci7nR-g-03x(S}bp ze461&S$MMXuQNO+3(qzFmbn(IKHvY-e3jY1sh07XH%scV-8E=v?|O?`!-mb1hmO{;(|E$M|zSS{;6*;qiti8J=nQV#5mz-sif#vhpUS>9p%Eq`MCG1Q_>`LW!|`1df} zD+{NLzvVLHUv79<7LMk+b=RNe(I)%^!&3~`?IB-m>=$L>%Z2{={%zW)P#x?*p@NU*lh5IAM5@;UQVL)cB7!Jl^nWh9?`YHGD}HUSj;O z$imkff6F%;|Gmw(n)ofZ8vjSK@T126oAQ$;KFgbo{|koS%)%cS|If2<)FI@`yX6j< z4kPE^Jq!0R{sRn`8Xjf%G{ch(*BZXW@S=Y*US`r``Fi7T`F7)fx8X+(zhL;aEc}k~ z|2zwKz_$|4x$xK|b~G5&)MACra4jQ?oEV+@Zqd}bD|HU5_CjQ=Hu7i8f@ z#{bqVyvq1nzSsCaVtBLRErz#d;n$46PHIufWf_Sa2i+-M`iktlRTbVBJ1{G+4Lq9}m|314F^OeRUXEx0jv>*6pn) zgLV5Yzgg1lQ4_$$sy(0ztlOt1gLQk?bfA9Uo(b0P&-Gya{>|?b^!xm!VEukEAFSUO z7J~Kr#^qrB{&F=~*AK1*>-xz}VEz1G4%YRDJHfg>+6o?`o>%;&QkO@5HmJ)N`=WLE zTnpCac>`EqKhJ>m_4zzlUyobCk&A`%I_UEH7Cd!*g?-Q3eP1I4k~}{19wyW zOYmWep8)In$gjb=KJuSnT_5>9Sl36kfpvZ4U9hf?{0*$@BYy|$@{o(ZH2pl-2dv9q zSFpZ6bDgngRQ~h^>+=6yuzr8%no7ES9t$o~?>9ri`u%nUxUcd*1w26U>EPoOPXz1t z+3Da3%Kv<@e&4(Ztgr8R;ER?0V(6S%V~e}4fVsQ9noK8imDw|U<~--V+qfG<(;9|>NhI0@GG+hf7Hy_9{Uy1Z0^b^GHFz`FgB>wxL@#wze;)jl{C ztlJ-FfpvT11>kp-{l9{B`{P2eZg1qeU!7F@&2?bie)w-NKs!FMbFe}Hv+AU;QF^E~Cc zUi$fa09f}Y9SYXx^KkGaRbS`_K3DNkVBNp+FW~vgzXGiLQ%(Y3tNh1-Z&!R4c$MO6 z@Z*YSfOY@JY_RVCxD>4WKbpb1|KrEtK$Vwkz`FnA7H~J^eYGK7{M4^;iCPg7x^1 zd%$}9$9-Tu{^Mb=9{;fptjB*m4c6m7egoFyKemFGsr~-}tjB}A0p?uNlKywWs}*kt zZ&3UxSdaJMwV>Y@3c&jPVqdTxU$;M4=WkE29)H#wtjC{~fc1E@Bsd4pEJ^P%;C&VU zA8-%F!@&I&a~(Q8K5Q&lj}JQotjCA(T02LDpAN23TnpCY!!7{NRsNTOFIU_Q{)ytt z!OIo5fFD%MzBxS}>^87|zq=c(-v@sVj$ABw5Ulh6S71G!_X+SNnEVl;=h5PQ~VkDb;U6}i}ZNe4q!cAc0aHlFUx1I z9xr`(5y0)OnqY1u5_l#m9p6c-d0$Im*8htjEKS2J83rabP{Z^-S>-X8$!K>8%-vQsRcsp3PpM3__?O!>lOY8P5 z_Kn@B-kuF_>wP^Irni?ExvUZZ9|vtlII=GsM0X ztozGXgIB5ic^Lef;>W?de|!_Tukzml-m3Uzu&#f+4xWH#i0uCzux=mP4%Y2KpMj&b zOk+U~@#rS@fCqjR>#)^JYR7!SdX760qgow5?rjF_s4*B`xpDVbbHru@L|gS z2jCux`R+7K@!4QKUTg}(tMtzV>+y1P!1{T4DZ{JhaT8d#-z^2}@vO_hdc5Wh;4fA9 z+#Mnfj>~syFY?^DvsJ( zSYl$qd+?v;3Qx$}!MgqRQ?PEY4RCMJ?X3miDJuN8zy~Vs3hu1MP7=F+2 zKKseu-TCZexXf^s;Y$qPV)y~WzcH-l6AD*_5#6J?|8O1MaEaV-Io4#jK5w`dY;r)DtZ*UUTmxZBRWttlQG zRxswKEL?jStL27?;(Eqzp4F6JKQ`qTkWKmZcT;|S*py#2Hsx2AO%3)lt@;IeQ{iDC zKEHHq%CGyI@(cfBDjV#b{yv;v`#0qm|4sRoXH$dROsXlrAa2U9eViKP!-p$AGyQJz zrBs;BWH&KW>L?%HucVvuYwxDQ{HL9d$FIVh^2^|+{2I9_zld?luVS1EGkjQCSQwCp zF1M0?k>aFZ1veR5aZX%+bbgKHlwV^x<=0kD4RBLQrNR@4)PyIGTc4@{eo|e(P;n|; z_!|Cxf~r(FT`t*8Pn8O%ZmXf|KC4E^+`m&VtWhv>)Qqq^Dq%TWJ zUzU=-3?+|tsZIK_l=NjO=@%$Y`ZAUDWeU?0hDVX~D@!N+xla0XoebBJ##!@aFBzV5 zObW)6fJwpJxk&oFN&37=`n*Z{yh-}JN%{r9lYS-Wq+bd;=@)@c`h~ueex>iEU+Oy< z-Xo9-U-FZ__3y6JSRvU3p`Ti%Dq3~vh1`= zk}MhSOpp8aX|XSwa7*Zx%dGwoNcmIceXKO~8z3rTW?%%2T^GRz9> zE-n59`26?T@9#gdkhhyO&fk3ey{Fv;!2Px3FCAI^+yxJ>4 zV(;#Ra$@A#K^(kMg&Vm|_-B9%C-(?{t8#mj8->45xt;qf!px!V!pVB*-qK$LDPP!A zNBbL$UnM@}R~1kB8*9qnSW|LC^%qO(7^pE4DPjAwvH|fht(&tywAAi#4ThgaD=^wXAU!;?Mze%6&q%W39UoMmW zd?x*IB>e*+=^v{}Ut*I!-Ll%dJF28FH%b3^k(KFP9=VDN%9y{nlfFQ?nhIudccmf8?0q*Arl%*?)Xa*O3}<+m2%bx#Ppqx2nm+l$Hu1OdpFBC5 zV%`Q0C%XD7knlXhKcH#zWUkG?ClJzyfBx2n`A4m`nu?d zCr`&@_YIi&zQzT{{P^`VuyQ$8W8Yoy3*q0!kAZiY-acHt9y8;&v23$Oy(}0$DOzHk zb3&@3k)AT6P4L>f=`$wQT~vjTQMQ{f)#+)oP^Qk$1Z>}5m$}Gda&>K0xZe8gTC9QD zUbx~jrN&&K8Ncd_>Z@i>k0!Ten%j8dJhn-18&8z>ITO=uZ;eb50@Ynq+x8Nqe%7QZ zv+L8k*qS_&#VK6dT;X5Q_ySjsU!h+-W;kW9XM1AN*{)HP@<9CP8t^Nsa(c?5XMb7I zIZjVm^jA^uVt+67lboKi=-IBA*y+MPLK`2J zve-OLy$?%S^lW2H_>R<maFj*A9dc2%(^D4xm(=^tY09GSgd`SC zb@r4+-<^6cj0{Iv^u^RqcY4aA?@#@?PET3%VO!jJPET3%Wwftxddi|djrti*Pg(SA zmo1v<^pr(kOZ_aTr!4xbsIPT;%A&s>a^hqB!QHBCD2vTX$o;%cE9Fn{2e%3vNdslE ze@NLp2f6T5{K379jg(2sV*jSnQx^RP)cbNmS@fS#@5>2g(X*{SK?NM=X_2s$#fEFL zOIXUHXS;oZ0}A2#(8iZB%3?E!dSAvUi@ub4U&bhleiZe-j8PW-Y1I2NMp^WesrO}! zvgm86_hpQ-=-GE)>Qn&%UI@KU~;jXyeNOWw9xz-j@N&q8~%OF9VcC&s(aL0m`E1>5(!( zS@c|EUCIDu(a)#emjTM6UqZbv1C&L7E%l5Tj`kB=G`VVE%UrfD!4pJ69$I3~0pe*_;sQ2Z8vgp~5pU8Jlv z(dVImPs$i&(Q}-rU4aZc7%~g;KJ39MomAqWZ9HUZn0d7uklqDXHPm?l9S@ay^ zEp=?lqTizIDU1GPWlvf3A1HguqW_3`U*0H-J_miNQr;+wo?~PZo!l|*OB)}Sve@*X z-j`L%qUU&-1V5yJ<5-!Z3tc`?7MnrTU*zV4U!Ec!a?eHo@K`pc;I_esj4=h$*7!<0q8jCx;&DT{tN^%uM2qAdDV)ca>2Wzj#R z^pr)v1#-X6E)O}rNWxMU8;(;Fn-3rte#_bKQ1X{b<~$2x(+RSaH_8%cPi4b-7Q}|K z*rb%6vgkQZOyVC&d0&^FF|_yB0%fs3oBFd|UQrhPxk^u2^mWwxa!6V9mr?J_A!X5X z99rRiE)AUXK*CZMo9n6fVJVBA!SKzQDn8jG-J0WwGbjM6uzx&q96x2KS_rpHuRykR|<;B_59BlJZ7b z^c=q><&CoFKZjh{&Fzb0xFjrPvFS{`FRPSA&+(^)`@66`Y2)v=l*Ohm^}ei97X2~Q z`?5+|^ySpcJB!kvOua9wl*Rr`>U~+IEc$8G`?5+|^bOSevPxO>bE)@blCtQRP=A># zOO!?b6Uc?#-LZ3AY|+0u8_Hs{LfN#^X0EfLEH)2PKhNnYi+(Nj^PQfu=$}#cltup% z^^MM+vglu@zRBq+i+%_7%}!5Q^j}iH!09QAo@1kn7CJp;(RZVMk<(KaJ;$esJ!R1+ zs9)^tDT|(Ck;R^}=*y{J;_NAlo@13I{gg#Nh5Dt=p0emUmN{{NJ6{d7@y|rcVsn|& zQx^RS>MwV3QWibO2PO`5ao$fGf8U@iHcwLjV;7dP==m*YKOdIk%0+&G@i&a?go(j?BMJ_y${!>d+M>OD&Fk^6=FyLG@A zo_-w0*9Skc%O#8xrBXT9%7MIw4v&|tc1hSU%mDo87@x>w`tf%he%NO%HlZ61JEldP z?3Y_PCi>OF?zLlFTFycQJdQ&Aa4XHE4PtO|1;*T}ad8r#UC->HbMb8w19&HP=w8vw znPpuk6uti`w_<4a^~?&-a(TdWhuU($^~`cB;=v*FI>zVEr4(N*(joIiGk^&3`~#^+HxG{&%p2QFmS7cU6nPc#nO zA8{PsCXR7GKJFS93u7-X_}!J^9vaX3aXcQyUi>8Y-@LT>iIOJSQ)A^}!RpfD^7yCNczlHXXdfAF0t zB@0`wTM%@O=YRN@E1$jchTq&WKVGqTb8h7k0amK0NPqHX@bGo<{DF5qg=1wbL%S3| znZF@QXUnPk2agx5Ym8O=_=()gydYi?UmE*OE>a(c|M<<|JJpCGKJd=F!sC(j<|4Pg zGqvT~g+bSXf)78v;+DqeuekcDM&#cY2ef?r@qW1*a7LbnO?B4;n7;Uj)35A0ZcZ?8 zYC$YEtjqe`4TlGpcJDgpqy3J%7U`_q8a#O2z`NcGx>g*(ly;F7z4AA6RXWMJ#-}<4 zUB~Vpl;t%q9XdBQ;_9bzHy#;WdQjJkKHV=`AtU#xyuck-%bWuO99!kp8*-mIEV%T5 zt`~f~-;nFLzlA~Z4fh@KY0!230m1fCy`oln+RC8+H3R#sM_Ri3T+1DoDS4rUv%&4W zOes1w9(4WqfS|dt%Tp{v1DoGM$ga&imPYvD?Cv}uz)^?i)|DLUo0rae%9X=7&oDHt z3tPq`p2y=$;}uAuUt?NU+Vmumo9#) z5qs|)V{9yaeIC!>z*rbtNz&EL@H@#e*gfLA@QqFm^A%{hP6I1_TzJZA18e*^Q- z?L!~6?4z|QzSNza9f3aXZ29@Wc}*F4=JV;n=M<`l-t8UcbJRH(UpGO&zi-O=8x*F$ zr-}cYaxW9#VSAbTn)niiQ7!S#^!fQsx!lBOIjYyV{f{>GmQObRr|o4v z+r+oGd6J2L+Bf7H6FyT}_2=&rb& z&oLg(x$^p`pwI8MhBp}A^bJ{mqsIHw3nsp3UMiQqmyG|bhF{;y{HBTT?JWGB@&CZ^ zhkMAM8T-%wn;ECwJD1;ihVu<~*h7xiyLRz^Q$En_zo+3t4fo2zCB{GT4Y|JwpN$6? z`;_59hL6d@#~J_Q4VN0`_$KGv`59?=l;P2Pna7&=ERQ$-md`f+Q@$ZjGvUwOL!N2u zYYjITzAy`4Z2T`VJlF7i!%c>l7}noB(`%XW-`jkxiT_5!D-G*!u<6xm{P&dgH{6UW z8$W3FmyI7b_KzCgWO%dTEqll>82hbz$gddt*Rt^I#{Uh&ZySEc@OHyH_A*BeneKjO zSx^)`>x9j`!13U`zG%U>p6tDziiC0kIuRMAG(L!*Vt!c&ZDUJ zH`ws;hD!~X?ID*N`(b;?qm2E@S$K@`A8YtD!xIcoGCbKZ$AIem`=;Dr;+tc5zTu|5 z%u7ssSL|h8X5zbcFY}EizFYS)uQ2iLZNA&Ye~)2~{nh2|-aX`pjQzuV$ZL)LH{~Zy zd>pH+k8hLVXAD1Qc&p);_A;(N{Tn}**u{LWrxj@8!r^d=!=tnC$;O}K`E~ln8$QkOIfnf(A4K8G*WPA7#3mEJ|19WhvmZX4 zvCqbSNK(e$59P`5Tyy;Mv#=jZlL_yKru?_@6(&8)4FAONt$WC~8~c@pTMe%^e81sG zv+(1_KO1i__L~epvzPe=6QAW*jQ^{K-!}Y?;rG5F?=a!*nz)wp^H4NH=dR~$+{xJQ zYq-$xfqR(`HSt;2a|ZH#v5&F0%x`dG5)27%M6do!g>y9 z?w{ZFIOo!D`84CN=Zt3fvyK0hz05TxKFhVnzab0HG5+%nFED&n7XFFxzdj4!Z2XrS zzTGgtZPMpwZ}UAS{?%Fde&heJ;V1WypEmZ-7~X97r9I?VjQwkd-!S~1VSeMK^Z%19 z{JHVZ#sR)J((&gR&NtloznS+n@$>sNoj%KY4prU{`WpKIhEsdU#~b@>TyE_3oU=@y zh@;Nf2!MuzYo^!m!;s7)%#)vShvrO1kY9eKLG3Yjj>?eK5#l%zptMS z?xyM=X|R4DUVH-dG2Z!uWcN3H~)sjla1!1{j8 zHK+9TdK*}mhr7U$iv>Ri=<@IoSYOYN8GrWuYyZt)eSNa8USCh_o7c>~bbY(kGB_T?R@{1=0D{G2;N*B`G3>-yhv@F*3YeQElA z;^$x;Kd(()zh~c-u8(g3>-s(Wt~9gnDPQgHRd6T8Z-SSo>*sy2P7nKnwEyQ|{eGB- zYg@k`vTsJeUv&fP_bK+JOj7&fno>Ic664RlkaLy&abW%a&b|)KBMq~!p-zRLV3_wR z-JUcZtkYL({4WIeRPpiNrtd$Cz=M_lRbbt|cpX^pk8R=Fes3}sg0I|;0hcdYS06Ri8YCmXH->;CBm!%ydCf|CR~WtrJX-nR2iC{;FnGN3=e0OR@g}eypYgo${~eh3 zMA`qJz%v#91>8+B=dIA``PlgX1I&B8#K$$K`YYy|Q<@I|-zw&459Gb{b;XAp|9)US zKJO^-gUbGR!{vr~FV^)dzU%7oaA$y72XQVIOakllO*j7MgC~hO(tibjm1V!Cmmzyb7$xD{~Dh&5wZfc;hDwZvr2t;(y*S-?d7W{~ry%3D)Ch z-v^IU_B)I}*QC<;BovhPg)7wK-Azb%rkj>;BQXh8KcYsPLR~L-RG@waWiybquV)#k0j{nzS{ruSi*7d!Y!9DSFE*88Fd6MFHAnW?+b};iy>_3C7>#I5W zZR?|*z`8zK1lIMt9^i*i#w5OCa0eBC30T)BQ{X`P9|zX;JI=kK+m}XySE%^MfEOs9 z0A8th5?I&o&IK1M|2ptFiZ2H1_P_aH-h-ys3U|ql41lIMtEnr=LdKt`TqNL|_uzvq~2dw);wu9#@`_I6O6m#AV zT_5ZO*7d(4u&(cMt`6OQQViDhuM)7Xucg4Ob4YrR1MB)7=jkX_{v*Mo6^{Yy`WNTv z_)J|-lfZ$pKNs9haUEE{-(C#X^}+ez&dPoXm~}Eq?=rBy9&Z4@q5PMF_51Z*VAk;@ zJm>4s^}h$ebCmxh;JJ#Q0MA#v34F2Q=fS$Z^%A&7`Tr3-P4S!H9*W-wPf^VIK6HKY z@8Ai_Kc@rMh*jJXe7533u&&P@06tmy9}3p>sl&l*)$x;}Ll_zLAe8LaDb=YjQjQqC2k>wg!4_495nxUY(DAy|)Jz5+Z_ z`CkJL-?7625({ny>-yXsU_D;B70h>ZDNnxu_fq^2Sl6E(13xO}K`ht+*7dPx!Mc9O z^>lT8;rHMM6`pHQEl~Uy@G`}mLu8WTkHL|P1z&(Ow?CvO7Y%Z{e$^4oHaX{F!G2&} zzuF(nHaYP>7_94C-vRd$Z^VBD_%Ox&zylNy1eYp44y@}}L&0Y%|KZ@*6?4t1_Y`wJ zlD8F~1=jVW$>4l-zRm;d`cECWv+}OO54D1CSN^{M>-x__;D?m|W8jAsZva24_*t;7&%6NMr2Kymo~H6^8(5dOcfpq_ z|G$B26#pGut2h^hNr&GDtjjCcsM35eSYI!_!7EgJT$Ac<#RI|m{pb5&eSMt(UaRa+ z1nc)5u0h2%MCW3`8Q_-$QC`#FHx-`;*5#=ltjpVvz=x{x(g^OQcqv%lPg)G$1RkX9 z?*Qxj)z85Ces~|aLD~NjtjF^|0bZ&6e+_0EoO5U&0qgto?~VU9r;LVB;2J7cZZ{z=6<3A9r$B%y>teL|2ue;ia)n=+w|-M*8A&f_+aqeDtvG7J&L~z zW*ea#|3I+5-+kZk3E&Tu{fXcY75@;d>zij7PJ{LM!1KVmK3fm&sp_Xc0v9W81nc_s zQsduZ{BHv5@pE^8b$$J3;Nw;N_knf&{Flc63FH53aJdTqpI|+H>-S*&KC%t0-zVM$ zvkg!3|8L-175^Q)QgJTUY-?4#5BPq?UBUYO?O?EeKkE(Nq3pj4*6)u4!F@6nm{{aJmU_Mx%;#~r=lj5~L+;^u3z+pOiT|%)*1!2pJoncLbMvr%FX4NG z`Mxp9`ws!{0AJ$ybZ~8sJ4S|Y0JFX&$KMQQ{Ys9PYv!>&CCoMRSbvh^*$ifVN%G?j z@LI5>_j54cAB+6{yB50l+5Vmn2lM@Tq~~M7eBbZu`6TcXaGB@nV75<;^4!euIRB$P zUk?^X@jk;(gQvh=^6U4;|3fg_dnO?)^CyoJ9eGF7!@z8hIukPev5L!pUcq4(VjC`V z6|Q9!uB;QT2^Ow<6s`ypt|t?&7!|G;6|NQ)uDBB}w-YYN6|Q|2u5uHuYZb0s6|Phj zu2dARdlRnt6E5JB4A+fIhKmci<#gP7TyB*uxBQM2gqyOmf#Kpg zWfgu44i~KfyTxk;hU+KM-!BstCYRydvNmpuHGRVMsfLw>!4SI-9cBlt!==y=i`#-F zcCNw0*xgz@vP4;!V~B-oE+Mq6StJXbh3ofVUtD4dR@~6a$02b!@3L?qAXsrJD_F_$ zWRj9_(JZ9EZQ<{aE8Joqj1-~6be0VaGalA%3--qmE`r8bLi4h4@u^`I;ijz2Eg4u= z;kRHH%B^KZJ@b}!Zr^S@tSnp_3$cXSGPgn%tilzlunh|dw_L#p*5Rfi+&~+yhD2+Z za<_gJ_7#>iSaX+%JKSK;A-N4=bmaHz7itTaP(p;^$>7!}IxOdi*lo*FenGEr877$d zv*VU+B>Q6ww^%UHr8?Y{VSzn&F5NPUWO^f1SnRPAw*~v1hsz?uKU`f4{%#8nOAeS@ z?8P0ePqJI?uM8{T@jQ%oOLJmp;SyThx>cIo7J<3K6V^232EO5fTHLzqacc@PG8Qmc zyFwXmU=hQR*Vw*cYSt!x%s?C~`2pgUx?7?lpe$TE*SGe^8Vdt(IY{T@r zO`Emh+Ad|+cC9@SqxI_of?Sc1)%pCvxvL?((r~C@=F0M+ZZStBBV3dY$@PoVh2;g= z=gPcWuMEDvT)L$k$zi_XiV73qHnN%oA?i$=qeRO1qYttlgGb%gx8<7Y)oT z+$ak*W)^Pb5n?}n8M0`BNS_YBwpnID$XynobZe4D3r#Zr7@rTHS=)`J4|-Y1(k~#G zl#?!ZR9W2AFBY0vLoTzFqmRemDWY}Ve16G2cbBCieR^ai!pu^XK7ajUsJkvb>GQ`g zlIk9c<44I_bS^c1fk3|monJBTXy?~4*FO%DPj^^#MEsepdtACjAfXTIlHBr4@bMb%2ai{`mB+7JjhK&Jo>$t3`++@A zB=xd&@w?TB`4|ov{$YOLdFIj=ZCyH3VIhRQ+v0)Z(;>HU|KxM43)9Z!hg&2Q92RM$ z-&K0Rem_z-32%%H=gy0(oA7ZE9ycBj{`kY|6LzwdN{c^lZtZA>bNP_j`f9FQgBsy| zxriP&em~*80pVTc8IKHdATycHun<{^4B=@q~+$f@Pbj61wu^7CEKA z&#&+W0xa9G%7}P;If%B-exR>zMO)Fk>tJBGh$$-5?);)U?DE%Du35=;=OMEV?>VfZ zyYxj{AFr$a;mPj9WnLS2t)f~T-Uqn#_U`%wyK*$pRkXp;%9?c(FR0=wfA!NZuEs)o znWg30=xcV>*Hq8MdWKl1a3)qR{A%xZLSxCusnuKrv98_F+FOO@+H_nHutu-nDG7C9 zkgTZ<({?!u=gH;#+DU8VsrDt&)>qe5&!|ezn%(|!YVUSJ&zV>=z1@8}k9I=Lnp0g@ zGqJY4bc&Y>#Z@hOFtcZR)y`(=RBOd@ zHAL=O#VU4f%4F^Anwl*83QcBIM~hx&!XWan{iQP+THq+lyx>zHCyqjc5nL-}-`Kti za*?;EEcTm}p0eoQgPb_p#gl_(n#3_qX5UcaSSP0_ALnF_3orCC`@3adlqJq-wEw=d zuT%0RkPE$@eK85&A@Bm_e{uG2&}N8}* zc?{)|PUhH|!V{g$B_tBQb7C#!lboLI&2qeyrTbC4z+ zWzmm;ocMtYdm(LnSju9vi25V&2S-`-*FsL5?80*VV$qS#hO*dvMw?Td4aWeA4P~+6 zI5Igd%Ay|&IWfkC{b!lmKKdpE{dZxG>^isoEBILEZFph`3|ltCaSP~f2>N)&sSDlB zI6m!YOP9cp?Znya_)QSQ48V_$@rg{PAAfA)MqIVngzg#GF)iX`zud|((QgOr?k#g^ z;n*{tUAEn#>pYV-h{1~C==)XeyAmH&atyS45{>rZC+cFy@*=Jlfe*_Wib zm!OZoI13+U{4Gbi1D|KOT;^8Z<+lz&N+Yf!)P8O==aCIFz1{- z`%(Tod6Go$_dnV2v@CqC@vq6kbBzCmhUaGCCgZ=r@Kt-6mznr(G|aw9=iK@Fro3FD z^XKDk!}siEW?j)amwr8#iP!T(;_cI;na>MdUU5qf^!35#gucG8EKH!!ANz21etsLQ zkC)f7PS26x$i)IaCv|%GJk+5$eSchK-ZotpESa1b|xt@6c;kT}l!&p#&j_(ezzJLA{+zUVF+_$d%1rgr^keLV0 z#e!c#(E0T^Sm(z^aH})Me=K+o|2q9If|(}gV!^8rbo%}bW}Z103&*J~5=4A|gM6Xl z&mcD`jn$jsJ2mddJ&#dxh;$ZF|PX zk8&Ma=m12l=q}?1O6~)eZ1{wd8?=(M`3{@VvQ1B1doAc}%R)phs5H;J7^Kaf&4~!g zFSy`>1@}- zDeJ0dOhjsD?s{O-D{0)M#*zg)o zR63hdY>IfJg)7BRYj@>x zj5ylRaVy6}=C>2QkPxP2Hhw(DLi{@7CuxHiaGd@m6;R@19Y@>k=-mFh@Qg_fRq2}P znYZC=@51O<8#L$`z71!87w+35Cp<1bM>sO93yxs^+~l)EyR=*vkBwZLAFgq9an}X>E#?%iC+?sq1514>&AHpT8sL=`-Vb$6eEN=+6Iae6b+d_HRdg!IjmPmFJA$ zT1g_uDoAeaGZ*j3wG!KRHkLGDZL(WGo*Iv6 z?zg&hQ*)o@oDt#s^TIXxL2xvGXs^IpSV7nP{GcU%&av1>W-X>zm;BALx|!_dtc}t8 zKaVh09vgAPi1Z~pa$Y%;NBi(~*PjskP2;d5g7nhC1-X?+2miA4sJG%Bx$ap!N-IKc zo3`Wg^tU=@bWC&C=JHIs8=u;dxAUeu7Dh*yTYgmJiz6y-o>YES>Gsks<*P?*YAzcQ zpE!SE@8tzSJa6J-lHS}A@%$NU+Bw>smiTMs*^YMNvn7iqCU>;+Mx-y>k<)m@#@v=} zhXpIIyZMC0zsY@SVNO5%^H}@6+uX6`(@*#7-Bgfi8)3+J-nJyt#ckVimZu5vxb6Y~E7NBVKf(#F&dz&8zHlUAGf@-<==y zz81e;1p!lXOC~=W%j5ae+sTg&xh?VMPW%6#9~-0mL4N$ok5MO_}8%79Ik+ykH&fbMdp069BiAh<8wJ*o zk$+esMigZHkpozv@Qb!(V)oa_gG>xK+m~j}c5`)fwJ#`WX})HGK0aCTF1qLNZg$qX zOk7OuoE$Fx({<%KmtLpY)hq-}(qQbZlvUV3|I`bZ)#)tV^FwysM3Tdh~|qPL?i+chAIF zv47^uEm@q7#k;S>eN%jIsOZzY2G1+umc<=|mgW)rL>9cuif<(KM&o_&VywLw4?2i% zNz;r>TW9XL^|6+MwK)UhJ2QLl@Jc!!FBEH9bjsw)@K?@XFFq_sU9UMJ7;;VI-*;_# zpLn;n7Fc6YTfCI+xVzZZ9i`F1T;uTRB|| zO7n}$SC{r3IW%@(^Ph7by++!yu{vtz3^!Kp$Xi|Np7F(*btLmQWQ%oLJFyNkvEsQ} zup@6zV(mM6*R(D$vGVCI;1?oP}Zz~IH{kMHWxa$U#R zx`pYo4?8qIwIZ)KzOrauy6&yj&Bd83kNU++H@>xQ>K6y3_x&_)lk$tK;*qGK%sp~kbp1O`h;EIdhM~lOWN$G~17w?O@aQ@kueKj85F^Fgl>&(q@rPm9M&!2?{55#BIl9-CT%PV0@7Z|7;+%OSV2=C*3 zW0<`ok2TDA-ow{5o$&s1i-vD$KK~D5)pFfI!OPcmU3gG1@wbgz^MaO(KHjhQRWD|a zQ)1aRYsY8YQ~HLEL35|aJGH#rDK>t|wzog~Bt5@!|J-pSa`q2bhL(6+o6?=)Jy;99 zZRsuV$}ysbnz^P*n$lh3-E$9LoWCi`8P-wWS{Sg7a$9xpLr;&lG*=9Wo_kx>(~zmj z9X}%Hiv#ZKG(Ike}FL)~F(svsV-Wa&&!M3zFnp3kWatmnThA|ZEW4b#T~bu{Na}p$Gl;&VJp>{DOqyVU&N2Ov~ALk z&!h7;A#+So>bIXfY3!DaNuW5x422bsHL zF6X`O)4bEy@R*NVppW{|oD zeY~UzSNpd<&XkuU-KD(kp0XWO54e4cyf;#|?^-nmi9 z>h1Q@#wdx}(uNl8ezMnV6Iut6=}Py^9_>?u+p5hgxFzq~KG6Pm3{6j(>c@ z+LESKi&L2+?)YqU3?)rn)?ZkGdRn(nue{-19qY1@IVbXt9o@0IUc58-Y2}tB+upDI zqGfD#(6VF4ek}{%_y<=`k5@L19}%SMKJIi)<+fWs`fPOO?C2*%>*CY@knYi`M-*qt zl1Lu$eB)gmv2u9F6MHwkm6M)7x$BRIrLTA)FTLcAPK{fS2)bUkB)D`=*QrMbf4yQ+ z<+v+*U;S1P+qfmOCx%{hV&}2AXLp}e&b9!)8yAmsM|~C_(VCD z>_^aeDvscqyIyxk@RuiYUpy>mK|X#lr{%4qgV|RuD#wcFSMO+>k2qR}%iW4&J>a8P zyF7N_(8kK6gAOOIyXn5Sa6GZ-j=>}8eK%SbuKj=H-4C3NWx_xH`^;Y^CJl{YrO8Ol zO7qV&tnAP$-0Ix1_f7)Z1;UUXOpZ zRn4-L&gdK*Gyj6qX==5#-ih@N4=$^dHT8{|*eVZus=vB_f8!^mLxT?lVp;2C#mxVr z>h&{oXyjh!F#Cn6*%Q3~r)AA+Y|7v8M&1MIPP=jD%)y*N@Y%z#-6MC7-cfS#w?EeI zvNk_9A6NJaPC9pW$$sp+fE%{B@1}qH&Ki9AcLm4)$)`u={>;wzti8v4g1ATelBdjj zY&1Tb-~6G`)RM=)z4qxY$ERJs;+A-}OYE%UU%pa~Pw19`htr(whIN9bW=_4^bC3H@ zGDqmrqWa&320Zju_@Y)t zE*`UoY+X3+h1XA}dlDbM9q+V{otUC8oa};YLIU?*;{?9@3ny>qFP*@hzj6ZKyW7co z??ESU$0L~j3FoDv_dPMQ9(G=u)zA}D9O`+g_!TGS={KF1o_^nnnffB-Op{)+Dv+-GHNXt2a9I3$DHK zxxkNcC8+iT_5EAGyUiQ6a*hwWTrsuklg9hk=Wx#V!v&{9KTP!;rmDQE^8C96L7%yM zv^isW?zuztgX!7{UUToYlTi06X;=DtslDjy?N(fe&vGum)PP~lz)KtEAsPh z{&W|-YmUBhe(F7*dup%9TU9$KxbE3Sc^}ttKCJu9pQ|nH;2$bJeaBtfrC}xCUAWd9 z?PKPwa$@FQabikZdt&B|^297J_QWiB(i2ly?0opf(_OMX--cxW{S^o2<)PmO6?VyP z`fZRouQTUz)22MzB|G5TfakkpH~iN7`-1PU&veOd!gkC5cb~Nz_oUNt_nV<1PRBh@ zI==6F?q1Mw?@PgGx3aZKr`Y`8|0OT&4JUg>P}6>QJzZ^`vyVL&ke9yBd24TA%k7S* z%eEPfmShKg91w`lvf$9d(Bm0fDpqEhBe#3j-=e_#&cH7-!NIXJvIl(RK^Ccto-)r{-un*VFo@h#L4TG?*yhVb4o&Ab9NW>syeop<`4R^ z{;aTIe+}+8hSL0pz6^XhEV!(yY~K6jK^X-lUo>=Hno(YLy)R})X;5HkSe4B_KlQGj z1@-6S>f`*ds&5Ns*}GO<=gjN!n)Al{d0o~yo{VR{cx{P!mOZ{as9#$BhK-$!f{oAR zeT1za=3iU$Eh@8?yMCpGkALJYt68$W`M55I<#NlsRdtq7_l=)UKj_n~Z+@6{>l=;6 zb*R^I@0+2KPRD&6>PJ|DkGA2ud0o;1g1h|C(42!GANXB)Q0gw)+xpNabZLI4 z4+HQ1HmFmd`cHfneEb*JT=Z|_YI|G}zFT#8acD`w^|Z&i#|8iX;{IiMf%`o0f$iAi zPGFAAS>HD?_Z2TG+8r>o>eKP%cLG;#cfWb{GW%slfxAZrcFl6KYt;(LTah0a zl~zA8%Goia{rpCE6})fGEAsBgne5b8oUIFE=HP6=oKY;pUoZfr|C7CTXvvKC1CBR3 zd1YTeT<408^kjQ31%%Zq2~BrO@Ex)9{004<2~B=3X7v{pCDV7HhW`gv(i;~g<_S#C^5mrt z@w`-ktMAhqcwU+o(5H_9$9AYiJ6~;t3bhy`<{(09QXODuFL7@asgM1%>GvL#Vt6(TnHLo zb+p*idw8wFsU_bA*YUsdYwx-#o$@sIdER?L9@0nKsU944JeP6Q!ID=Vb+A>wDGzFr zR{y!iPS47tPC>P!&Zt`MeyvBH3qjoreZNP$Wv+h>XQWQ{#WPOuHT9qP{@RVjf$u-y zWKWpkDY&NO`|q!9UyQRr&&KK5-<)>Jrk5-X@t7@XuEgDM_E+ak^Br_$sPlZ6n3)%x z4>R1o+r7@|-wJnmk89PJ@aC_37Cif>#On*H-X*5i(!!yCy0_1u^*4;`;QhP|!{=oO zXZqfydzSCsy>su5{oBj79oo|W$l$}n4vjoGx(uJ3fo3$k;Py@@oc)IcwRg`Z@Vz?4 zRcRr9DN70b_|Hz0d+@zKCGX>}99+dr_I;vx(n`MjBKY_3UrZgAmfmfBw-y=mGeYh@ z|KQ+$`}=i%XzfF|(v@~Ij(B;m_^xf@xATAa*Uoz$jBB5`CRg!B)>BpQ>uSfTS@>j3 zHv7$8RmZ8km#?Ay%zvbE_q@FY?(@Kp@hzZi7QPLo z7qk3wfWHQ_Mx91I)dW|1({8$_;GSc}*%jqMX5H&Q7mIchi|%~-FM)^5doj#hr|*UL zBF-}Lt!bIexOdJnz6)j`uo#;f2WTx{}lYPPohP{adujgtpX2IP z@ZJKt68pZn@@rm`k}ta8y?i;SYt?%>@1tEFR<{6BmvLw#5?b{eW$BE(kKgyUn87PC z9#?j&_L9r^Wx%~o>U#fn#ThoE1Z7GN`^voO z89k!}dC8}BJq2O-+`(4%Z^6?1o3_NvEesr7b)+k$PeXsHLGJ|OePdp&<8{9~ z(D8b~XZsd>;9b_5?h&89{bAM}uif>Y`AyU5WLiA6*cMxO?@srq(CIz*d1?NwADE+o zC#}={=4deWFMM_RFxo+xJ^$I`{xzz4-)CQ_@Rw|Rzqt~f*QJ}&q9EpX*b};}#3$i} zkiZ8DagAz((=4rX=qJBhn;Ot<(>~Lh$$w?6)&2MW$@go}zy6-!`<8&CT9nf%wkZ3W zpeT3Q@rxS?zlYQbj`SYc`uL7)1@HQ==$Kyvx)-eNW3J=)*Xf@e%dk#w^!fTt|GHK? zmKEZ78*$T+lHe@&Sax$5&W8P^{l_x*FUzZ)=a0l$R}s#-N-NLv>AhW;fn!_#MW- z6+Zv#Pv5KV8pIY2`p})bY2mfM5Wmr4K5m(D@2u=I=p8+Wk1cxq(@);~u+Ka1{CBW@?wJPkvwfqnM@m>%35uzN@Nqwf(LLzZQ7EUDmGJ@9Lzw z$4~!W=l*4PwR8RI-!Avl9$A{-v*6Pc{D=Db$+v@_jwUhUod&G-F!kKf^{ z=HIAtZ*%`rS~%icGuN;Gt9M#ni`t>nLvdxUSEy4v^tF(fg*z&aFZ`mye53sO?RMju z)atnH&CqbC$4lsF;eL~*c; zx;i-41@T^YQ+i2okf*D=c3t9~cf8jxXfOQUvKQhThJUH#n}mNaL|YHu3xlh!V0`qp z_vlxxhCyGO{qf7cnf z^3z33?bB{xTujYFa+b(f}YnMKMe8`9&-ERl6g>?L)W1jzP&A(;+|JHx( z+iPQ{lsdJ#PVIuZWo`A(t*bk?ywdytcW!-nZu#zKB%i1MtGSi@7IXVa%Nzf1xvlR1 z`>c6m7{ChXY&^9t90xFN1jd=WIa^0oGz)wS}T)0wlgo6vT?*>*Em z|JJIU=P$mcIRw)juEQDS%Rx^)5EJ&fcMg|dhzZ6Srnj}csokynj;*HdpRQAVvradD z9)Mq2XdeG;Elhne^`8x@|L`qWWi3qoPd)JM3o-RS5BgVY(bjve{nNGZzA_QtqOD7i z`NsHZ=znKjBFwsU`8Tgi>5SUm*WA0cB7%b+eZjoq|LhgPAVj%C(R1Rq;bR^hdfTHz z#}B{lw_|c1xoz;Mp|{14&o%!JFn=8|A-+xgfFVOC3>`IQ?4ua==(g-JkB%KP8qdbx zHaPdTq2n=VPi5KLOxfEW9W!L;sPVT|b^dT1@4Rm9m@_nc=m?DSGv4&rsQlZY>|Fe5 zfE!i*J$umDL4!w(8j(9<=y-qGA-UrRjCm{v^eoTrdT8Z@_hI`!Hl8ZQv~HQICHqOSI|rGbY0*^$c;@$yeq{8R-;SbTgJ9XThD6&VKXtSl;@MAgGrfPCnf%SWd>-iiyRSUwTK>Od z)6dNJ@YRQ=N)cy2r$|M~YP&P{zk*P~E}@8R1XYIBU@ys`@|{^Tp4?~nh5 zXG^Z0FZn`?mrA}|yhgm%;`NfdeNKJrw@LDC;_c#7vy$%0rT)Z zeCwmW;*Tp|Km1dzd_8fb#nF;Cvp80AGxmY+;agra_S^r>d`}>=J^f=N`1enBy406p zu{*YcZ+X;a+&NypzGA*dky$?VSShb|$8PY=-;80$^D7b;TRdCxdE)uvh2ljPFOhs% z4ZTXruN9Y(&A2GWW*_yxzc@GB`)d0bEsvR>`n2R{#TDX!0N<-WXe|#<%nm#QC4;bIWxBV7ayh!rJ;-%u{7MDt{He+1!@~PKJ zZu2H7zfF9SY|d4T`S`%O+5fJ#&(rdl`Kik#uMmd^`nI0`{SjetQ^}((He-kS9=`o2 zR@}zoB+1n&lB@Y1TxR>EOZg0o`5wGxdUY?EzOQ(g#b&Hj-@~_k)O^n{Gk?D4v2l@1 zUu^Ll$>)m~h!=_Z9%N?zDTfN1oW&g^PqjEx@*XvGZz$yf;Mt&0ojgR49|NhOn*`Kbq zkJ9p(`KeDy&iDK?<<(|W^n}NhbyNvAAuf>3}}uoO({2SA#N#- zvp7NWByp<6X_BkEORnxId9D~;&nh3j?YBXUM&i}-E8?cLs^@Am2BYuctG^lfO9aNf z@UQ>#gmbg~YwDI%znNYgE4jM0MfFQvv{ZE>b;bkal?&y|KZ%c{x$Uhs^3hnE|Xk+Q1Y7kuuOkc zd{TT$d`5gud|rG(d{KPK;wzGem;rjd58vm7%@I;w9VvN~#Z4twH>dm#>_5h)O@sgQ zi*xh(*VM68znNa$T5@$8$<=X^Cx}zT?Je#sxy{|Byt=34Sr+$|Ts@HT2k?3s^ZT81 zv%PETVN}1FUOilL^+?HU>d`WNj(DPYl6bOsnmAuPT|84y?V3c>MfGj)Z1nHo#MUXec}V+gW^Nt!{Q_2 zqZXf#{A>+fF6Gq~l4Iz~%7^dsNL@>EbvWgwt%x!2Kb)J_zou?L^_%I{k&>&UB(JHP z$n??T7UGuT*5WvEf;dT>EKaewgXHNobWbU-?j?C|iw8=s9!B{}>_5il{tW)(59j9f z|G6GX^E3605>FIQ5>Kw7=Slem;-wZZmt4I@a`igNH(0z$@|_m%k$j)U2PHpY@kPni zmn5%)`+N8vzT=s?p5zTIj*?v6RPtzXGjW_aLEPEm9+IoGB=0RAE}kHsB%UrV63@1H zj^uO6`|v(DHf>b=?|074`}1mh1uc)6pSo1?)mPc;rT%Re?~vTw-^Taw?f(bFM=d@f z`FXOrk5@D*H(zNzI8iX$%X_0F^Ka$vI}x~#jPK!_e^ZM)NUlzmJWZS~&J_2sxVPl$ zev%Iq4-pR+j}(u#c&y|(;#~0r@nnnhC7&rS63-UT70>^fUM$nAmrA}|Tx#)Z$=8ZE zinmz2U2^q7$<>D?S09!91oKo7h3{v^%jx?W=jQv(|KGfiwvSo=GZvqh{F3;JIG{oG z?^>-y@)w>shoaRZB^Bv&_+yt%lA#j%pBlO)fy zxQFDuEbc3LKXHGHM@g<8E4eyH@(JQe;>qG^7UxSoU0fudEuL%fe96@dB|l{G5y{oZ zBtI!WEk0XApO^CLi;`cm_=@CCWcBx_%|TLL9U^%>iz6hDw79Y4Hb+bOX5!}J7UDJ* zCrfT~dnw;h+*zDvai-)p_mJ{g;@;wZ;vwRZ;?WjQl6*+!4sTffcv4RsA#Na!vN&3Db#uwpEhTSV zLnlf3WN~|oJ4oJ9oGR{aaX-n`gC$oFk$jkVxOh|zJyy!+kj+@B#-<;azr6?N=KJ=) z+mmVjrv547h2lju^kON$R9q@vW$^~d)f**OZzC^s#;uVsw60Z@j6|b{+ljQ2{ zlH0sf%I~eA4@&uC;*&M>X(_KhE4li-K#LX;j zF1fme>-xtEg&BSpQCrjR5+(DcwP7`+( z_Y(IO53HfbN_m@eq`W#;^2rt#Nj}fw`I4)bNN)35DR1+7DZlY5dy~|!-YNMpi%&@Y zzwJ}9JU`c`rM`3G3*t-SD;5VeseZhuV{tvnBgIkTCgSKCy1A5ZA#N#dEp8)@6L%N) zsG)mG`7Cj7@j&sA8hW^tA1NLs&Jjk7EM6tK zdbQ;L(_Sm{-yq&(@pj4gTU;jj39`8tR~!x(eExQha&xE&xS{&-B;4ZGlB?TDo?vl% z$vaw{DtTv%GbC4cm%OLAm$IXu@ow>+ zf3x>Wefz~_79W!Qu=r>VeL~8sPf4ymBf0vV|r4fi$_{KUGfDMFOgimLh@4aD)DOZ8u423 zdW*M7uHGy8e(?cunfRc^$0S#umfYsEQvRa&lDJ%4VR68X)jz-0wIo;9kz5@qc~fz; z#myzRIZ4W^lO^wLak}K0;w*80iw8FzDvlMWh&x!^Rq_mryGyR_ zD|vtMVDS*~FpI}ZuAV5l%}+}CDdK73e2eEuKF{I>k}t7%ndB=hUM2Y&i#JMs(Bi|A zAGP>|XL} zvEm%@O(bt> zaWl!)sgifDp}R|Yb#KYl{Ulcpk$j}ZlO&%ko?>y4hISeamdefJ()hj;--?Tqb2{} zc5_*t7UGuTHsUyOdy6|r-cg(?PO~^ua+`Zd`7Cj7abNL3@nG>Vi$_X6N<7x$iIUqq zMaoYTPZt-7i!Gibxq5-*>P3<-7B9KVUMlsgS4+Oh;?0uVyiLm2)H`JQ-QvAJ(+6ex z!xo>CTzy9J|81X> zHS`22Z}TK6Klv(qiqx+zmVA-LizT;tsg(b@UMBUGidT!*h}T)XN%HL$@05J6c%S%y z_+SlvSjry}9~GYvpA?@GUlCW-(B2<_yoWH~?~4KE2O)BZI9wc2Lq|&aC~;$Pw77-E zEhSgSO0G_lJlW#TlB?4szuN99^UDzT6laNhS=?W8^=Sx0a zTx9WV$>&?VNb)5XFOz(Q#cL$rZ1Fb9_mMZ?eAL{Iq89%1->>vA<>q|!thn6bs8-&C zhqp#Ey}GgFO)PFMd24Z84V^0G)tx2pVR4q^eZ_;tBP|{)d9HYZc#?Rsc$#>Qc&>P1 z4P7ebZC)ki)vG1nVDS#g_gTDOa+^;`d7Dp5`HL2pOI{%kh^_v9QrD8a&Q*4})UR$V zd91~)CAT?F%Kuy^NPQ{d4&qdCn#GxtXIb1^^8Vt1;vwSUHS{PcKUzFioGYFno+vIB z&#s~8Ncp+q`QpXmr8V?&DZfHoDqbUAZ}A4n)f**OZu7d7BfYygEtpjuvN1-pk_NlB)+xZgZ}bw|SD3pKfuH z+dEnXn`qO0u1QvVW*mr1_b;`NemsG+w=`E3^Om0Z1F@-p!u@nP{1i%(0gJ}nf9CmB<<4qlL_*Hg2sb3u-d89b1hK`o<%`9#$xw?(y>Nv?0#7W`~;*R3Z z;xuvk|KrY(<;%3VhvWk-9x3@)ajtkm4Lw=PPqTQoWl3x%zZK@w{Z4Q(2jm0g*u@<+H zJWiY>P8PQpcd$5J@(gizaSw4%i+f2vSUkFho+#yKisy+Jh!=_%iC0^^R`QMFZ5D5r ze8*MxPN{#lc%S%y_^|k74Sh+<*VF;GRewJQSzJ$Yb%f;VNXZ*p+(h!G;uaRSlss0P zBu*B$7k3bMyvk0M`a6r$#a+cc#C?CJhsgB9EFLSlI!AK#1j(PYc(UYE#M5i&nNog^ zc&>Q9c!7A~RrVsOf3bL(c!hY4c%#LeC9kP>%JjP}E|Xk+P;&KQ$&ZMSiceU4MsoF8 z$ zsp8J!G;vppGbOjVyOi%G?k(;o?k^sAl|5MMA0i$p9xa|Ao?>y4-OC?t? zlU%(*@>20C@fwRaNUq)}`6lrW@lNp`@m}%1tL*(!{{itq@geas@tL3Li!%Ksi-Y3j zcrFgHI85?7;&5?<#Zi*08%y3y++5sJ94l^3K8@e=+()Q$q0(lEIgbMo z_YvY0z)d{m$jR__@~_~&&cgFZavwZj zO74&6{m9vPJ~!B%egxctJO*w+ehjX_fByMBf#>;@PlY>^XTVLXc0iBwG@KghPG16d zCqECTk^cbal3#{7+jkl%slli!6C$h+Xaw7h?T*N{JgLu$Lr|2McZ z`7?L{`3v|g`R{Ogm^=M9@a$_`UxwqzKf;~K!PvIF$=AR|ZuxuQ9_0JrA>=;r7V-c%lROkIrurX& zqs)he_u+BI!Tl)zEu2O9Q*c+x^WethLU`NLfEBfN>q-wa1l{!4fc zjw9w{5SAe^8N5ZD*qsSiRvE&FCae*uc7jf!sjR- z4+k`Gm-lhFCHX(#baDaA_cNXa@1y(~xEI||{W*9e<-dpde#S4sD=1$H^Zj@K6E3Fw z4Vdpg{x;0_XWt6*{h{B7`ToowzEU-y5(BkBImpTm6r@vmUM|L@l@ z->>{TnD4Lq1I+iE4aBjZ?=M>$4mT&K-iODz7Uuh_UJqBhKP=4mo4g6;`$gUY^ZhPw zh57!1i7?;qupQjjoJ?2F|JN|zfAB7t?`L>7%=bgQ7v}pLJ^=Im z%=fn&1M~gm9)tOQcu&B5f3~SG-w$pE%=e3X8s_`cmB4&|yXRrPf6*UczW>t8FyAlf zRhaKT^%|UNz9dv`zc=A6v_0Q}`TkGu!hC<3T`=E2;V&@XU*#h>+I;z`tp9H?-*4tK znD3AC1)M|W{|*l!e*+IBUxxX9H9x{_C=bTD$g=3l**hNR8aRM_9nAN0XbAKDA#Q;A zei$)u9jd<-%;V+X2J`&_+QNK)hF`%vo_{AegO;ZY%;TBg1M_(4_rZ0jd>@#{Yaalw zulhpbafZU_RQ?f|$15KP&!POcutR?u95a#i(e+TpU%Fn{BslFHB6!MEO zkJtVR97*F%{}JZ#s9%Ts()4e^JRa1a;LMwx$_Ku$!90HGpJ5&k^+TA)PyHC?@sB=* zOJm&nj>9~j*_ZI_=5GEEn8z#p7UuB}zlWzZbIW^huFK;uhQd7FSzVaNf2^*;VI-_!aQDJJj~;Z-4643Z+E~v-qoEjkEhoS=J7Ru1Mj8nbwAAGuRRE# zr+g3`K+E?qoKNfbD9q!JjfZ(W#m8YDFZ4fP9^bA2UUaj&y=TEZ{>(FQ8s*Qy!^ppf z+ml~{+mKhn18;Hb|4%roh3hxqIP%*tj}NjHE~on5hq-_K2XHT{|F3Ws`4e~u`M+Qu zpW$=3BjsPg+@Jbucv4GudB1~Okbi)=e|I3h`*8p2+VBCY|5}*)CtnX&>kkcwQ~fu= z6*T=VF!%4i73Th*iEutm-wy6Y{x!Uv>bnc({$O{*J6pNydoRrW5(Yg^y9b3%*GH3(W1EKZ3ircI*2a%wZDP6z5Qi4E7q<5N0{5M2jjaqx9`3N4!hMYe;v&2ZyUngzV`;0+vCQ- z+`hOK%V>1_EEoux&6{pFt-=WgWI=pw_hR5?csh0bNj7lP5Im0@-M(`$S=a&{@@k3 znDRfu-izJdDm>2X@CC}>g8BEsEpX2`cYg1~{Cm${cnjqp!F;{{Fx)iWo&GrNK0MA> zFker<0QbGtU&7;j56_|R?*X_LvzqcSn6D>9z#A!V4D zhR={QWcr@)Hp=_LLA3mX;SH3Jgqu*F1Ggkkf|JP8;8b!EoJpPw^Y&N>PoViNh4aa! z@Er15cma7M%-3(W!K*0W4G*LF?}u~9hu{st?(6v(+^m-CQ*aW#6Z;+>=O1tf@VZQ#o8RqNP zJ7B)Py%*-|-(@ggA3p-~_4t!8|33V8xZ3dm=HFwl!2Eluxz@|Sx7LLN=y($e^Y6Pi z!UN;n?b8D0`QHk2`+&AE|9*c5%Ie-d;rYz9|lKLJ{nFYPk>{| z{~@`#79L6YGcdO=TLAO?{{VCQtXE)eKlPt5x5wH5AGpokURz;qAGRCrNco2_&;KCY zm-3_VShBg6%pKH(MmERpbn^4? zK(aY@k0QScPb9B{xqbIL@Epo_z}!E?T#M)a8|JfgGA;jq!NufLF!%2`2XlXkOOl(x zVmPk_bAOEM;Bcxx3g+#9BOFEfEpTh{ZE!R>MetVD3LR0OtO9 z!{I%x-Pd~@%>C;ghxvSYs^o=|KLc}rxP@>XI$wVg=H*`jbN|iNFn>Q;5A*k%&F}`Q zZwI`eY<^qe@c}-D_fdWnK0rPNXOh2$x&M4Q9Pvwc`vl^*i5BEKa02;yIGx-S?n%A{ z=KkJs@L0;*!Nugx@Ivz4@H%o9yo3A@%>AE-!QB6O3>;0b_e7Zc4^M@;|8Ei8i^`Y4 z1Idfv9P-O>S&+NER>6FJ^*Vft^0(oOH#a;d|nD^i7U>^UbA2Efy({KN2k@)&pxc_O@tJQdzYE`kq}OW?EQMQ}O!WjK9xwMgxGQb1MsR=fO>i!` z6?~G~N5#RszugXp(EisEP9@(3n>K8|hsVi;%c;Km;9ivXg@=&`!4t{D;e7HKcn^63 z%*!_!=KDVsz`XyN-?~HS^`8efB`<>Ok(a?u$gALJ@;bOVc@vyT-VXEi`#td7YuxSg zS9n>t>qBsB@=hIEsFMoeT5* zAQ!@Xzq_R{{~lTj^ZoDEO1=^1`_XNKN74Lto1DBKE+!v>`F@Va;8m2LhBuJU!w1Oa zFyDVMpdrrx>G#SoxR@LPZy+~@x09Q}`^d2{|Gt?3ms8#z4v%qP-_CF>IRobVrS*jQ zerbJSzTeqknC~w(5}r-<<-mM@ut_lA|7#lDxVgJLMR05KTsVci5Kbj8g?p1r;T-Z> zcoKOd%)j?U^7e$e{Y+n& z+usa^=Tdu@k?<;V4!oE=2`(j1gIAM_;J!Dw^PdZIdz*!lFNH@^`BHcSd96&p5#CMt zHh3GghuIBt`v@BL|=@)d_MKe2yFe2hj31hQrCt z;8=1j+@72OXOP>&^T?gyrQ{5F9l0l*K<#ZzTe{BV!Ek@_NO&wc2cArx1Q(H~!3)Sm z@N)88nD2ML5a#>WFNOL3^QCYY?Z0c`A>@tlX!16A0(mz)le`~ZL_P$ca{LeU$AI~G za0;$P@8^HOoyiyBEB?tHkMjfEi}IkxI6om@15YGJ!1?4x@G5dN%*%6&nI7}-Jv>eu znBV_x;k9%;_!V4EKJ>uPPbNuJ8?>;>5NPZB{RpM@tGY`1KfrjjL(Wxa$Pu+d_7!Dz5(X` z0yo3Sv_7}OS>(1b_aC?ec4+!&#&N2@}2Mm^4;)B@_ld}di@@RlgQa{ck&}JA0KjHKE6E;V-r*@&lEV# zPaIEXz*U#);HP13pJC2@Cf4##;Bj7nTa(SX5cgMG2@j+EHOb$CxxOv%UMl}SJdL~; zuGaqz-bDGQl79|!eP`h2wcX|a20lpBm&4qjE&%7I5mY`5<~#!C`WnFlseCld{qam& z_U@F&NuDCp{~BIT<yYcgJ;+h;Fmg0Jf!q?FPL6~5czrv}=La3(Mf8487k7s@ zP~HnR-}!wHkN3OAdh#&j<~zAR9}P$1JC@%Q;1y)^U4;7+O_zMOxYr>PI6QD0J#Os?GM|){QGD!oD%9(K0HoGIF+0ZN7M1EJDd?xSscgjUNHA3 z?hkW+=3y}RUmgvg33e(U9`AR%3*^bjxjo)=cwd}b{&z5sFR=jT_MR`o&ElQPhsP;} zxqayCFpmeZ3Fh`)@4-C o-&gMADSq~$pZuOfd5Zy}$Dx0Anzxjk#pP1xTluM2bg zuSl53Pq`81_F^qzZf_M2r&4|GVQx=*C)|s2)7OUE-`)@N_&ojL?o|F^IGQ{b=Jr>Q z!#tkVG??4_&Vn!9=2SjB&OF$m`hE`wke9>N+Ka(F-j%u5%k9gy!rVS)^pu{vDXx*YAM0Q2rN~+rN9SwNw5X@{Q!vFt=y_2Ilc@ufROsY%s2! z^LVr7T0M^^+YpYU`lI0<5E}*zxFK5?YS1i2U@$!`wGncFV?_ysJ^#gZl7lQ!f}6# zKf~Pq>;TN|+dhSPJol3@_viQr%5SaVhJPPyuKPJF@Ka2l>9h(14 znETs211C_v5Kbn)1atqLRWP^LdjpMd@AnnF zo^tcsW)#iu2blZ+n6?Sr|L0nGE=?Z=bAPCtU~W$s3v>IxM3~#-{0e?D*nNHOgn4|I zyI~&Roteh(Db*$+#fI*=Kg@chPl08SD5<)-V1a8!#*(g zj~oP7(DohyJ1yPy83%KF!N+0lk2w|Q`+*k16KMKp;AP~6@OJV`@LXEoRWSEgd;{kG ziksm8ntlh&{Ws0M%DFvb8O-eykHFlX=p-CT`}0|N0r?`#<1bafJib#1w%ukb9}e^Q zOp)+n%A3Ng$t~b1An>xb#u+RA(9w!~<{<_^^?$2xb>T>_v{_qg|=bwHU zo^$)W(J=S-HQ8pG-(;BE-%W?PzwvDNN&M%pe?FdXqv;pJ>DY$;d^y~J%CE+Av&{Z{ zJ)SS6@|)phw%P;w!z#V zegj-Y`4*V_*YAWEQ*PQ0b9=ypF!!H73iqe-r{LM-b1=6ryaaQ5K?ldOepJ2|%-7rM z!RPC`uebT^FnzFm504WKAFSiLCES?uIGD%lN`ZMityK6ZT_5WTpC?%;Sk&g1J4XgL91pS{`$* zu#{X6Hhot8>mLR4cx2J=Jepricr=wa=jNu*sek$unA`uQ!Ut%6U11)NtOp!FV`8jZN@&b58w3{!1Pmou@JRZs# zn8!=m0P}b!Tj2dP{Z2Rq--&$>kGHQ4kDqc7Igg)m6z1_xPQe#r-09E3<>X876|#fx zM&>)3e}1)K9*sR~$w4nZ8dvUQA1P0ZniELLG~Cmp29G_O7Wgk1x~}=Ju^U zU~b>q8y-f>GZ5zSe}=={zGn=aAK=b^0?gyHJ_YmmuKDm@DnARZ@VL{@g`+8d9&S!v z0#7Hu0`vH;tKlNb-+;G}H^HOG@4`=#cf(g`c|L@>z0xNzk1zHa%;SZ937UzcGX|H^YK&VO!n%h!hMM7zEYZcc6lwQk+#=VxHq{F=JDvBf!zVD z@%qCdv_HHEN0L{!{fXK^LTAr;ib`Tz6;Kx_4yFy@%%o4xxMjcFt;E6 z65d49e+_ec;>$3%_x0R{{f(BlHf(-#_dW3X!^g;t;8Xq>uWvLwmyTDrz&t*;`7MUW z_ihVsrt;>umwMzo;Usbf%;SIG3-kEhz2P-fegM3HZ0=?BB>7Ren4AlTlb?XO{azl- z<6X{zFHw8V5_kdm1(@4|z6A65n6JV--sJ1>273R$4KJel-i42m{|paA8%h7`^H-S1 zxBMHtk@DlPY18O0{}s&RS$+fac$eS9IaEFnzZFg(Ujy^_ne}0AKl=-q$H$C;d3?`b z!rZ<#5xzp}_bZs&+ujNDc%pa1y=i&wgL(YT2jL2;FB|6ZLLY&-{qA^}+v7d~XVCV` zg9rOJANF_i+wha*XW+Hu1@LzAAK-oD@J~G@MHLd6>t8Er&BG55RB#JRWQqoJDyA+?Q7Y}(NK9v-JN%-O+z$~(hDBHa2i;8o4Lta6fAQdLHKSz{_DC-#Z`?+rOc^{$VhWmmLA~c-oEOBh((YnJG{6i-mc- z?gZHMVe~ybPJ7t&x%Rs=Z2DCDodF*p_k>$e{e9uqnr@N)7r zcmmZ|1e-pV{^gkq^LXS7;RaNGDcqP`3h$%o*TSX`w!glO@Okn!*!1D_=eyx6l<$Wf zs{atYm&zZ5v#9)O*z^JQ*LNQ7PkA}Kh#ZiF?L+m4!KRO@fBFd6^da@TF}#}G3_eJX zg}FU=g0X*ceBP$ORi~eDM>vD>G`K%G10G230e2<$g1J3(e>kI-zktUX2KOhAhLgw> z;9T-#IF>ve=JwRHVQwEiA6`P`7sKnw%i$vOYIrw!Jv@cH8RquYJ78`vy%)Yn<;&o( z+V1)ufsayt5{{<)EL=wUMVQ-LSHRqUI;1VO7fl}yr;{V$6mnCzAGrnGn%oBF_Snhr zOv*dLi^%D44!JwLmfQ;-PVNtLd+cE_x33-zAEELS;Pd3k@J{k{I4sQFzO&)Yl+TB` zefDCQ+gmS(lWF?Za0Yoj98KN~4<_$`BguPVZm(SibNlNf@O&zN5^iygyZmQizF*8m znC~xB0nefGA<0-@sxKUFPI)BE_oHbFCsW=6o=wxYfv1p@;nq~XBb-1^hxvXr-C@3; zO)t2Z%J+x4z4DegZ!&E9So7kRzZq^%-T|9F%>MFw;a=o2*!1D`=SSdyzH+`64`l zTmerZhun_qvE*=g4mlE@Pi_jYBDa9gH*}Y;4b1n)NQRqI`HpZHIUVNvZFGmZy?ZZs z9hL77^Zho4!T6Y|e0ZEkVZI+(F3i_Ao`Cs&W7FWXG<_k=_Y<1~^Y!WHV7_12Vz{E} z1JL8V4DAyx{Od5^|7#=6pFdm0JK;1sp8o~TB$vTG$e+R^$tU1Z@}Iy*$)CX|$X~)0Yq=w#n-`cRK5|MLcR&^KyC&1 zBFDqM$?f2QQ8c!=Coo9`)VwwPF7LdmYUEZyUjUed8vWzt6XVxxRQaeWY7| zJ9q=R6U^T?yTO|&zZd53M}6Qj$_K%R$s=I?zB>-)^Ml7>K0lZWJB{4sD}>KAbo~s> zpNG%G{Q37He1XcZg!z2qHJCp?-;(LKO1=wrqTKm^2nUcqf%)_GGno6EeJTDL=Fj)b z@EWSm^DCU6lWW8Ld3+tr{m&YSZ-UbryUW`OPAA91d_A`vyq10+=>%^ecZ2!&lY3$Q z{iF}vpMEbI1oQYTBVhjhXq@u4k2F$ zHy}5HqsTYG+}@@Y%=We1l*F^+l_;{ zJ>TPS3(BX$+`h07?oIhK@Hz7H@CEXVFt@i|Dfw$Kx4(T0ZcXh`x5AgmyWn#2hcLI- z{RHOrr=P(=)c*8K@z-z|<(J`lWX~Pd+uPQLBPqWQ=Jv0RV4nX?aMzaZ{?iK1AjiW! z$?ag%#>)5bIGx}_n(UE)wdPq{$9J_So}uppZ|w2_dojt=Kf!w z!Q5Z#OE{UP{~G50Y?t8$lzTc>udg=D{o}5K{SR}R(o)=2{GfQ8_&>yR#B0RwioX;` z{@TBE*st-lqj;2fiFl9rb8)%&rqt^5>mq(sTp)f~{Acl5as5tC)x)gc?c(0zckZkz z?%f`fC7&l=A>JuIE)MKmz5Zt6j^g{oQ^kJ}?-iGeJ+gjn#CM7B6ZaE8AzmPUOZf7%|@vp@Ljd6ZD5&uNs!pI1CBHTH^=NVFdwRofWUD&i|Gkvy9eV<7F zow(s$zV^78mE~h$(|&(d5`k#VLf5thLeik-`}?P`>CZc*vi|zAeBUEC{gM6Kr*XP}YTxl75jOp$`{B=Kd9q;B zpL=AbN5iInxj!$02f|}3^H*WhKi{A4h0ViUqPPxUtUrUzcx(7rg+p<2GiuD>0b>W{ z*B_8M%~aOmjV0gsMeTXA_;xVkv-V)){FWERlQXHZ8c=5chh-a%&N7Os}U^8dN2E>8aGHpCQdGCOs@ zv+Hj#_`-kz!yX%*JzxN?6<0k?cAvI&pC-Cb6Wpiq-aTu~SiEgU&Hyni$GB$*-!=2^0NmTYF6WagM;$|ad{$!1PTrbvo; zmSWOmvuMetzGQD;3g2#~ZD(ebVuBPiZ9DJZOwH{~xpt<4c<(aC$C*O$ao)egnd;)> z%@px*-v1|>;_(S)^7sUA8Sj$DCwc#p9IVO3xUZVH)O-eLdDbc$H61}f`;_cq4Za05V@@~~c@0LmO zZh<84Hc#^I$VuL}OpLrQX?1?F0qqr9Xf)L;&GF~AZ^J{Q_yu7zco3wqBz6v3~c^N-KPV=G6^PwK| zp)Lv`U-?jL`7kWy!$6b|ttB7Yd_L4;UIwEOS0U6?A*8Sn@?HozDu(u12&GpHV@@%& z=VB<;LdaJk5OP-txhsU+6+-TcVZ17YloZ1_RtRY*hLNNod6cnJ@)B}a z2&pZE)>sUEq!3D`5K5*H%D)iWc`?*fG4zgN7+Z>A{4a(Xp%{8rF_d93lwL8ERZ(&p z>bDruPz)tj45d+&kVD%jhEghqepG5^uPKHU7DEb4VcIB#QL8Aa4K2JBMzCUN^Tm+g zQW)P#VM-~6nkt6;7DEd!g|V&_M&n}W7sb#cilOJ0GVF=P(6)`imrCp%rO@h1 zA&;ftw-o%ALVimjzopQ#N+H*!&{j(!v{IPyN+GAEP>-e1o=ahTD1}y03O%9}%Dg1$ z3B8~cdPFI-gqF}|N}*?!Bu6r_$)pzQq9wG1meBTELP@rS(rXE&*AhysCCqm%AulZ< z{VgH2EujQj!id)ra?ujf&=P8}C6sMT=*2Cec3MI&XbGup3ANB7lWIs|b2>DX=5%P+ zm{&POz$k~%1e((!{CQIs&SM#4)h(c-HMEV6_HbxzZ4OgIYr7u7+3m^05u8niJRDn_ zLj{e)B7*}JkE~iAIVAGP=y+sea17y)Gdvy{4vwLadF0T-BZp}oIV9p3nkSFOHNH?7 zv}=4J{q(2qVZuW$=?%H$p|v&CS!;VZjKeZQ{5FSfOD<_^4h;xA3OTyIp>vW;*~sDrJTwI!rEH{*$W^ChZFSNd zx((bzXW@}$g0i4@lm!p1tvM|WIYN~Q{VxDbudFrTk@hDS!M4G|!eQfrt6 z5sS%Mn~E$HtoGv~|#Qs0I4ao{|nT z1QL?AzM8g9nzmk=wr-lX{+YH8nzkOAwl10ulOF@L&Y9Mc3Kp&2w2o1*XzNK^4^3Ma zOwwst){ziETWDxs?KU`tnFJAsL7zt*yuwTZ9>#qhS#&%y6drBR(<%?ELe!vi z)o^GVO$~}IG;$QQ9Ko3*a>-eX4(2VPc&V5CwP;zi=pf#r-Bso;q#+%uJpirmbeL3w zMbnoK3#(w!oTY8JNQZL^I)&v@0GhjWn4)R1K`Cu*J8dPFwxUXhvg&9J<9jwe45g*(0d3aSP}s;2n@CW73=PA(1j+-l8X77ZnKsx` z7);eMS2c?!!^9W5wjBschEsZ>*Y0K!0nb8?DqpO&V_Q#B-I-}D>Mw6e> z^k;M&$!NpQXxiiy8LN+QV!)$RlbrH`Ym>=_^%}WUQ&yWyRvT+pt39htHLC-7Ry%oC zJ9kz)cUG%EtJR&=GRf*(lMM@B#HZDr)rlsn)tn78GRjPb7W1X+9&3zpx{pw_@yTgB zxUO@uI!cHwG9-*1ddt_<2{ek@JnGl0M{8ykKi&<$Z;ID zr(|R=X=g2I$(M9RQPPqxX=g22_}XbpS`%{Og7CCN<)njLYD!Kp$faiGR0CYgOinS# zHT~MLo}lOqb^88+7KqYa|dPx9NI=R|E;Z=FhRDq z>#;Qx0teSf3R?dKt^Z8OKm3Kck~-<-869Jax~3^=k16U3MtUy%g=rK1^1e23%@=(#3Fr;o|z%CCXFpiVG zVGa&~X+yV>M4FKf^g2ugB`TU8+D3;0Zq0-YqTuBS&WOpS;0oH*3SnqMMQO$hT5tvJ zFa<3z*%KKzx}XIo`!wW|BH60}*8-D08gj{EK^NWyZPc>g0(V{B$!-g|rq3FrcECdD zcxcqj9`ecq=XN5w41oa3;EDQS|uOmH3KWoHsxyN>KrgX?0;*48;4Ds!5toHps4E}iW3K~56j zUt3L1Ysk*Ra#{m99UF2wIOO#7Hm6NBrzI`>ttbU)lHq{%AOn579LMRNCy%m7$m>9! z*MU2)g`d~d%5Ez3I&jP0C^`Kz{4gLPe5t#fb{yHYMecOUm)%rw9WZ65mFbYG&+EXG z*LIuNQpxKCB>TM3YrD^DdzIZ%*h9xg?xkIY12!bsTCgD@>msHQEhrqY{t4+1h1uF_ zTL8N7Xb!_Ww9=wd1z=(&_!(}0#82rZh2*48loV&6xLMJ{b%ObCly%;A#E zaG**$Uq%Z-E@?m|(T4+6!4*dx12ekLmWv)xO9H|HDm}Hf^Wuz-JQ*3XT0`r?nI97Z zbr>gklxC69l}siy%8pj)we5PMB0DbFtAISzQfhbq>zzCW@V|%S9DT3>v;%SRt1# zBp2Q=DC!!eyal3NsaZ?4+0KOR{8#7lX6+iy+U%QcuOy>=31?6;m;*?414xYkNKz6njUZ6wH8 z5iA--vyCD)MZmj7q0=F@v$R;syNu1Y%~;-NEN?W*1y)93Rb1YyEH?sF7+NNUaCMmo|X%Mn<{WG~0$vc_X#F$st#Y8L92%lpCjvKXkGd)od-QS!Y!2 z*=b`dZvmJ0fNhY2cdLu?TESWZiq*0#13YqJVx2}{v5K=c)@)lC*d|f$wmAZ|TCCMI zTO*Nc>&%X|OgX)#rQGUl2P17gC9QKhg3*SZwjP((F%r9JS_o-9r@(BWX-?}1g;_*% znzk+4v~6;y%X@FOSDUuUEN!hNZ9Ca%Yh!60(~x#cn4W_pc5SO^Yy4@exU`;)Av@Z7 z(>fg^7g}^_U11|+t&6lZ{nP{51~P%ZNyCL;tEa0 zN;zCSqQ=^8+FEMbI&j*C&b0MpxyTekmQrrfp}$3^h!(Ba7A0i?Y8K6*ix=r zYx`+y;A!h0Y3ng*UGlZ)xlfC2MCm-(Qf{wS^)>=&W-W`>DJ`c~DpnS@m00d{(g0i3 zzg+S|W^^Wz3wYq#iduAhYSA&MMYogX;vxNMc)D6?(bb1sR)o9Ntez{%ML~uy4Y);{ zSc~?(7VXO|IG_lr0WQ@}K)#|kh zkzvB>SV~{ptBwjTyCYibbGms3$9JSMQgN0 zN9K}t^cGzrx7hktJ6~2Oo2)kQtPa3gEs?Aan^_%ZGTQPoI%;LLCNi2mxm5-$D2-2U zg5jyRl%DN!*ltBe)0fe5kQ;HJ*Ysz#MPzmG$!bfK-4DhitO9R&FMM zf6c$#5CN{~mfIxAwbkqHSV{9+()^S({Uy!6+;9PZI&{g65a7CYkeeI8wX4a^3*b8E z$*l;?r}Vm#)Tg?t*?^y_>$IFNxNuCM^3qc1A3i3OFCl6 z?H5dk)N@Hk>5?vs<+c#`(|ziaj)*1gPuje+7PL@xs?eE2=UGjd)}vOJmbzA&ZP-W? z(vsGU6?F0|XvPX!kOduR3YyWPR)E|ugN$iRa#swvo^lm6Jh{sScAd@Tej4heBNQ!M z%arD-XnEC!CU?%zpLEosrmLtOTJF|iJTi63T}!+PZRD1a{*|&YF~_E2q_x)6)&R zwcH{)AZ)7MQba}>5!b$nJcHwQEt0sI%IgYn|*RxZg$6r+&)X4REOP7l+)&v z)8-^M*g~h}pVM;8X@|EvbaFaF<+NUMI)lrNIPk9nYEGMfP6tl8@fPkn@W>6c;5yLA zO|;lE({jjbzU7uy*lohmfiG_}mgXz3?JTe5owv@c1Do91i*U3Zbx4Xe?!_0Qs?5?tm_I=xivr7%OnP*#g8SUe8_ZoJ6wa)DR zHrwHooBQFeeaUtZZQs|nF>N2wHXr47I{4GmZ`-fT=;UL2oVI;wH{{utXGZ&C#?CHu zUXe?02-jv79a`-YTt-)K86BGC;Q{D%h?i@v;M(RgI%dct1+eQ-p3%N(m+&$=W@K~< zv1_{-UHoLUuV(Z-IHQX*xka39Tw9BVlh?&XUKel-=-$j#vJXKOv3;_^Bctd*2eMC=3^Ex)z&$_?m@U(;<%R-KyV)^tp9HU{Wf zTt1w|;bIRv4KDVCgIwPLV;_PWhgq<2klX3NI0nFt-3crlzz!JJ9F3W_X zCJ))cQ8FUClC(>5SZYb$Cz!wv0v466{>!!!uH z99v~e7d&(g9;Gm3Uzl9O)k=}uEn(NfmOW;2O@CN-BAzh4!Y)T}DM&qnt6q-aq1>R? z@(WFz{zLlV9`X;a<)C#Zw*W(@^(A+!l54s{lSO($Q-xiQ;L@J-2(EfLf@^x^2(IO* zO;xTdFuaftxNG|5h^wlSKRtqryB@(MJUxO-{>sO&tidHPsSn&OAbmqFk@3=)q*sr) zbf)3S5$@8?^aytiUyg8>R;x#F4PTDnnqE1AYxr^m*YNBZmJ3Li_S5pQeA|kYrwpmM zgcr^ip_h8Yl|qd_3`MkS{Bi`>_~i($@oW9c4QB{f>J_)QX!&S;%Ek=cB^}+jQ%OC^ z4QIHiE-X8Fo0Y_`M{tQ>kKhu&9&tB>h9gICX0RK4l|`T*e*Qa3T-+f?m@nM{rG_j-PT18}-uO zWkZTw%PCATh&N0vu$PaaoN#Sj+M^zE3!LObkKhu&9>FDkJ>qh^_}3%2`qyz#mifF< zJA?yw^)E+osUJOpOa18)T=JnuaH(%S;-*RIFFfJ_>IFOLcOssy zJ;2O|t>@4>asFHYK1W=37q@A1rcN!J7!n`2of`t0IPsjh@Fk`LHL<4)W=+8}-X9)M zNZvU!@M!k|VThNxK4}w!t)faF=bbor`b7sO{lkK^XMcTReVA_gOg!g46A#uOP)1C< zs1L{+9$I(miC>vNb$;cPEWji7v!Xf(;m^mjJ`+3VOvOXv<-AMf%$+~^0z4h>)2!J~y=Fnh+-i71eXGp6Ds$0s#%zhLSG2RLh1!?XDa{{T1k z`2&*Qos_@O%nt~{N^-{3bLLE(F@5fVja0f!h^CzH1N+PYfqhsH^SuRmL#2O+mna7B z#~0NFp@)T$4sQ{dF$*s~m^pX)+-Z0rzy!wB0B3!bLm2G- ztfj_&L#?sFPMm0!1IiA=A!$= zA;6&=qW2spBW@hA`;4hrrs1^|ote4wy1Sl#HAMMsA_tU(wE`K8*mgpD<6xu(t;IZL z`T}3f<+nlbJrf6n=u*a3AC-ON8j@}K4l#$rUSZi(g{%I}bSZe?)&VHH$?ql^j&Hgy;TSQN6_9ub+XgI`Xe~NYuhuG{pY1eRw&He&#!xBj+vDx>~u4P4R z_Wi)Aosu5B`lwtc#HMKgPX1Cf{ee@@3m!!KuLP%QS3C^Z%9hx|>7f1v(er)X$zKZ| zH5_8oZwIzIB{utuv}>IboBeg* z)Go=(o78AKCpOLdz{!_I(;J;L^@`vlh+h@l*Wtmy77nq6QvgoBCVIX@J^35KCpkT_ z>BrEnbxLgZNls5}c7BJ`>Xg{*;ay=%rJWO-eFJcl=7sNUw=@%*W)n59OFH@8QLAfW z(`=y~bu=9HOH4cQHrlO@oPIm7)itq&vx9aGhuFe-j&==)*!0f>TU`^IeK+k|*TiPu z2b}t?G_R#t7~Gj-%PvKHL=+r25!>4@csIhW@6LuJM>L|kaX?e;YiD@T(j&`dfr+*&U>YCWXd69MvhuFe-opud}*z|7#TU`^Iy}A~5t!rYl z_XJMumb@GR-1HxU`vWKU2p&xQw%|0dl?kzhGn|@tL^Hx^h)u(H`6c&?<}{}vHq9j3 zwSI}sKF{fi&Aym+okNMueyh_Hn|(cS)4P&}yMV3kh)r`h?I?4;+mD!b;`?aVGAB0u zgTPjI#Abh(b`6Kv!r4Zxl}a7rb*OGnS=;{&0Y)KaGB_d&E5-`dFPMV>_<_*T=c|dA3*!%Vkb6xiuNnS zPHgrOv}<07%{~e^RV{fLO^ucVv1umJu6~Klem-!rM*PmCM*R|-=3?5_FR|G#1y0q9 z-{sV(Ut-hTNW1zaHv3xOWS#h3M~(U=HqC>yt6yTXZv{@)i{HnoQNP5dd5(7VOKkRC zz^NYMw;HbnZMag(nbR2*#AY7=+*j?yW*-EcI!Mwm z7`Q<{+(&GhR^XCf zp8;(Bl-TU^fE%|;yu@a|h;|K!*zAjd`>3AS>{rmPdSbI*18ngUn|(EK<6{ypvDt5= zUBe+Z`^~_8R8MU7J84%vvDxnews?unz7e=_o5V|O_6KR#aEQ(RFmNB$6PtZI?W!j> z`wn1>m)Pvj0XP1e#7k`U7iiaTh|RtWxR2_I&HfhcswX!49$<@?*zEg(8y}Z=iOpV( z7wuZS#AdGt?xT8Qvp3ML@e-T;C}4}1*zEjvV5+CI|I?|tTKXxmY4|-tn>UHg&hG%G zJ|=$epho=?n}**OG{3}V=QsUQy~OYP)Tm!#)AYo5e9SMg+4+6G)FI+`7&Ypb*fjj+ zpZO&=JHNe`>Med(P@{f{O~dc`nO|bF^E-N}L&fha)Tm!#)9~AT=9k#){3c#1DSl4^ zHowHC;dl1TFR|JAy}aaM;`bupRD)oCmoBN8->fst@5dRw)8YGoQ-_P+O~4J;NL>?K zT-&KRLNreSTR1zZ|Ay#^P5%n*E5uH0_BUz&rr3$i{tj^JND2R4YF3Jd*fh2HK3>Br zu@jrU0XTJ(_&owRd9>hDsMov@n|>Vi$B5=^YBc@CrkMuZ^l{P5q~=!;4{yy4ujw3ev!@$YD;&&@G>X+CwPt&e`iOv23aPkx4 z_jPK%C3zt>&AYU()-reY1csi*UN}+X57_jzz{Y>Cgf5Gz{UI5(i50VCA^Sj(>R#T(l z6Pso&aPn9Qb3O3@!S@pn6ugO8)4UzH;RcC|*uvp(=hsm?}%Swv!`iaBX(l5cK|0pg@5>+ zjzem&;InXOxJmTHrazyW6GStcc!=P6I3(46F|d_0vH4w2&EMc3em4@Q1mBE<^+96O z-$nb)k_KY4-v^v(!aw}(r$+0P*fd*#lS4(bof=)^5u4^&XD2rMi?rV&@e-T8zIS&x z#AZ)AJF(f10d6`G0pK@)8qEu_X;Q!`Et3p2dag=rnhxM5)tpX^)(f#|CQ!qQ#qVrt zH2uV;IgfTN2V%3&adu*}Ukq&NU+gr*rn$mtu5lV-(_HWD#Ad%0*uq~=jqWoLo8}(i zRI}vkVc=v&@D}R-AY%)$>9#*o2I|B6PrEd?8Ig-IXki0+nk-) z>|!JYLu?v;XVNr}6aTH~cTxY3k{4pr?*UF~ zn7#20%H#;qA3?14M&O1!#V@h>9Yj0M>-Zx!dm7l%kO5AfEMbd=IqYpTsY*`5g?LI#u*Tso5YJV$%!*PL2}IXlk^-6PsoNHChe}oQBvmi)q*L zAvXJRU@ISDvtI>l8Va0IaBm)JCYfi1tpX73Md`6V{{aln>eVzZ}c*ZdNj zy_I%7S0Xn1>A;qk@xV=EBrlVJ8-679PMi%bHIbM}jkb;1)M%K*rdbSZVO~Rx_7`H) z+yLD4d5P;rYBU^T)7%Mc;oL`!hC^(cZNN>ZY54;uzaaR1VlLkCt420bitB-GoFukz zdOJ-6H9Afbo2IYR3?lwJ3I7!8b(|zN{dizY!xV?lcY0#eFL0WRh{sC!ywxLlhG3rF z+qg<>ez}ZJjS~&KV$+#|?*>ke7knSE&A-IvcN;Zd6wP+vCM~O{sAmB95u5%6;N%3+ zzd`)J1@8uK_%Z(BM{N52z*hc=Bcaimqq+1Jyq z*CmO~&hI|kctULU-N2THT70Y7=00N6^a5_udO3<%>$fkk`5o+V3fSTzws1}YPED0E z>7YjESz^;n0Ji#?Ogv5W=M!tZvz=xkaPnNy+z6aHPw=h4Hl`6<`0JczJvBO}5u0YC z(`+K1E@8e%y{_MgP5%yXk{cfQ?E`N5vf!S_z^>`xcd4x&iOp{#H8VutpBfzph)t8D zM#CBAG{mME?KG!3JdS!DH;7F?3E0YNiqjCAW;U?JyMP)U$B0d{7}&z;qDJE)Hq8oP z3uiSonnz;O-0C#zfSWFmGPw^pHB&IZy=`SkY<{-_CufP~ao{E`t0$?~`XV;{`%Y7h z??onOi{E1*&lj8mZv3f) zLu~pqa38f3o4o{_Tp)gj12;Y?eu+&p0=SRbiOt?Y{m(>CZ1z#qtDV^Fr%}H{^u%T# zOTF5O%|3zpe-}Nm+0Uk4?ZjrELj6;sCpP@%tVx#)?_K8Jd>6Px`;;M9du zR<}BQ2XJzs*w;JzUBK3^h%KD^sn>8eQ~y=*yB)acBEe5m^Y?;x5??I%ed4bPJ_z4@ zZ(1a{C$QO%BL2GA8>!K_`q92v?8gCHUIqi(m_}^rOgl}E8XeP!O>>gdoI-qwgwOBK zTi%IHKaO@?e-fL05^!>f_&uK*y^cU^ngz7$bp&FwF9L3S02lx9BR2aI;67?6Hv4j5 zyN*C?_G@X^>j=bVzl(OgjzDbo`+!qRCC!_F8wZ6XB#2G38Mu$yiOs$Z*!I|o&Hfay zg}IX&-D4*<&2HK^>e|oQtMQFlD|2GgH`309Dt^RfA56RM)f1aN2b}7Xd<`dFCio=a zCe3dfa8mJjVB0?@ws6j)or`7sh|N9+ICZInxqup7pAehoD%$n@j@azi0yk+JTTP9v zVVq_SHJ3^FcTl5gAhvKe09!fVP5pAwZzR_6U!&%7vA^l?9^m8^V&CWN`++Sz#1_{< zeWBNIlEA4e#cv~U(^Z1|QggN7!Nk`H9!vZU!DmyyLhvMKpF#XhvCpPPO%P#{^>2-03tMfs?Bw4fj*8^+jy@t+eZyKy3CM zz{zXH?@nrTOdvMRYqaZ_Ky3E6fE&Lkn_t9c-viu7?Zjr^2W(>kvDxcC0lSU~#AY8r zyN(IOW*-Wi{FbCSLyh)RV$-zJuH`^%_A$W8)#7&o@pXbHQ?Gr2*z_}d z(;P?q9kJg=yhiX=;+q6N3Eaesa`-(@`z?ZB1h(`OTN>V^=2p?{BmS=7_la*4T>VMl z?+I=oUMsi}xUn@vl_0h-j|1+bc4D&+0k$!m*z7sr)a?@HFluxRCpOJE+I8$DHv4(B z->+k)voD}sue%YOehKXlh@RN&D`?knh|Ru+_BEm>Hv2l@)E$!M4aDCUd^d2D=H))% zq~h(sHs%vsIM36r<1Mk-Ujt69lQ7?)M#p?&(^U6|UE4Xa*?R&v=@^m(PX42W)1UZG z!5QKo2yUZ(z2H&6jZe!OkJ!Q-1KdaL#AZJW*!DVz%|4BGZsg!cZ1$PJws%2n_65LA zKa?~qrbf$z*fduFr|uHXHPq|4aV_=#EO8N={#I)KN%U)pwM?D{PHqtU^A7IJ zvDxpUUFQX2vp-I|&I`n5e-=2oQPRAV8l4x2P4g}_|16q=1_0kDxF4{UC$Z^E)clKR zP61BcFL*5N4+uUBxamQ`Gid*b;Mu?yCb5NiF*Tb+)8#b8rddJFL!!Bn_+h~}6aTB= z+lV&{z6;p;6tRVKKkeGiiOs&1cI|7#W`B})-6teA`%d8GBNEpO#9IWv2HdzXRCR*b z^lt$7Q9H5OcLUpaPHgu5z^O+i%=&@Q=y*LJp4q^u$3(w?`fFv}AU6G_wCngoZ1xqv=J#4^bWA2T%{tn3OeQw_ z24L&In~1kb8nyx_|4s0-#E%PpgZK%-`-!&;?sXje{#0-Su(cCni>ohi>PgWYM~$`_ zV$-B)*EU0J_7d&dW{Ax`0=VgC66PpiYd@z^ulXf5{RHZDygCcm_PvQsGYQ!Cy@}0! zKCtb36PtYw?V2`Xvo8W}()PTB8ch$eX|AG1({nv=a);z)4eg5W0JeH3HoqIF|98=E zq+Z9RhpE?neqz&ar(MgO*zC{Iu4PVa_7`c_d=Z=dO<>E{ZemUU9^lkdlAhY*fqyRe zAYhxnh%KC?(;PvK&R@i)>E|>l;-@9dR^n#_w*g!KA~wHcfs@aQW(75Ws1Ab&v1x7q zZu*629;W^|!P^{u64=sDY<{10n&+v}^b?!rHK%zOIQ4%d{G+g!klHEu7+_03vH2Yg zocyI|h5|P|FF5V=#HJrkyUw%3X72z_{!09wMvcz1#HKl$cAaO5%{~pdaXoHE#*f(S z=L7dqJF(ek1KT`HZ1#(3*LjxM?AOz-^DMF1Zv#%gAZfmX8l7i}O>;MJ<9#7%31YL~ z58OxX#AbgO*yaUdvp)`;`nANhgBqO|h)web?K&?In|&W}>P7LppBf$KiA|II6!N0s z_XSS9B>DlsHqH~9K0~{X^TcK!4s3o$P^05Kv1!K9uHy``+0O>H_A}Yx8PscB#HL>W zY-O^L`dyOdi;1-z-b&5OV!y-T^~A4;eS@>#4Q%B@Y;kP@PHH$?see`c?f`CjP4H9H z{6_E##IFmk9t`|j!M%W+-Vof|*&B&}C-#2SXj}tme^cy(fh{j7VC(P1md>2hl&I1E zPHdW1rx`>1dkKFW_1ZRwO+Ohp`Iczr5dT5&Lg1#|f-eF#zr^Nu2{r#Anro=hdM7r` zT52?$JE+k#5S!+1+I8F@Hv5CX$vqPOR%&$IAU4fYwClJ*Z1$bNjc4MHhUv*>TOALUutyRAU4fl;Ko16xIt|8G;kla z6PvvNY~u#8*+&4U-jTRYp+?6IV$)2fUB?Y#v(E%h?G?WZh~E{w5V%RhTm+o_qu5sh z+gL$t;oM5Q_FrPN-wB-BCw}juM#leDM#lkS(>zPNjswJIe~otC4Yg{D1hHFz&1V* zTR4Mh*Zxav_6%_9F!5WUM#l$Y(~O~A#|L7wj{|Pf_Boy!ZJ)%ZnM6&4gnvFYng(Li z%mYpxE}DyoHD4=%lShbsHL&IP24ao(M(U3g%?9d^61)-E`XI5zwTXJwY^Fy0AhBt- zJIzzTO-DQo8}#7 zCpLTaQ0VpCme}k)fg7Lc71Bd&_TIpK)J|;n24Fk)CpLQ{?T<*BiOoI~I5ntu2tPyo zDZwS+ronZgNUSiV>0ZyrAC^Z@{v1#yT^0HaV9p(?D#RTb<@f;(~<#9QB$8V$;6{oGgmwO=>h=V$-|> zoKnp`YBXMA)6_P1Ym!)MRJ~Li+FM`Zg9Q&JmSspHNBnwS(C}Z?1aY9U>fdUD{UG9N zWG^d8e7<1Zww9>s5Zs^mZv^ACDN)r!Fp`EeNSGz!pJ>EG=YI8qdFM<{48;pF<#?W< zIa6nxGZe4zotGFI-ZeRNGTzuYbj~ai%A1GcRnT*lcg~#$7QBcBPNHWhs!9yy3uvd# zM2K^y&+S|=^qhI~=1iZAx0udFn*OW5{tz#J_(L2M>;Ez9sw?&JaJk%+UBk)Hv z9)AeG!Du`(GYO}Te}9KR>MUP)LwTYt3J=bSG5Di?1pdPBGfSBKcW(hk<(C zjmXCpCc@Ele2wSaISYn%4xM#kfBe$?r$52+zmUrXE52A$ECe*E=hxducT`nbNDT8o z%HcAqu8k58vW(wgr2o*w$%hTtT)$;V*LASGx;T+I@{y%yw%2^^%)~>h_V(Dc>eao6 z4(#`GVqn9|)dL&ft{(WYy6UR-4I>7$om{nK@d;=A@+T)BR=;JyX7hdQ6GOTNpKNS! z+rWm}T4RUTb=40%s+%u8vkmbKtgfx^j%gQS+J%_*Ag0bH|>TIO!0uWs&&Bv%Xk$ z*nr1xSvqR#m@W0&2W>lj^VL_@jU3Xo{_@P_oman_SaxOSw_okGd&K0n9c`_rZa8(o zsJe5OEFOIFmmXSr#^$QJQ5Mb@AFDZIbL|Ort#v0~VzzZ%=lpzWdt1$zWoB7bH@kjN zH#_?LM0WZg6RYO`@z8E7!}YAKx|>}-va^0)?Li|3UAlc))yPXaEZoU$yGKas1})ps zR(HV# zXSCO{JiZii!%`V~`G(6al&?I*Jgw^*RnEsPQ&%m^r@O;BYy6;PmoG&-?DeCU|5z^R zrR`H{x;0BjPN})&U+YG8E_tn&A7JO6zbPf!gAR5q2+L3DID9e zs&1Z(``7n&*C%VU=FE=7Eh9T?_9m7rt~zYcw)*V@9%ug7bshUy1}(wj8*=%v4=o)z zwdR&bdyP1@~(tdAXS+n0@6w&B#)Q@iWqz<5!I`rZaTb*ZPJv(E{0j$fh8Ka%AGivJ{Yd_Ahp4#fWdqQ`~eD8pg zVLc95w&c1Erwtgpa%}Y%+tJ$p^SWxfmp$Q|+7rI|l`-3`EKYxX+_ni@&)%}`@?)RK zxE6;V5?b6XzhC<3l$yFxos0I>4=9(zx+}WzkgktELCwJ|ajn$v;{8Oj~v5>e~}bpV?g1dG(n`9@a5n?1t02 z{cl?~Xj%0aSB`BjkB0ll*LA$~{=WS+&+Mx2oOW45&7-wdtLhWgogaH9S@+rZj?VV^ zZKCt4eaQ*s91L+eShwu-vb|j1&(!ueP zHxGUJj<)yuTs<;-(M44Quf%-3W^C2Km0i^XZ)>X=xVC%lTt0T->h3xHUMvNdey>M) z1hrTPuD-1{JAZz8mcC>2@g0Z#?5c9B#+cYKXxYG6Wt@B%&2IW=vkdN z^hk~>mm5d1t4A&!cWPqD6)zpLcYoipFU@~@|9eN*oQayRc{};inpgG>Zu`|sbJfz0+N$JfqsL~CekQ>r z%Gi(f14jAL{y*=pzj&bUX+PTgYV}K3^?388>)(0(=MP+dz*?!M?Z@@)p-(?l?$e{5 zls-LXyY=ZImwy#~x_g$xn1?<+wdSyn?aLl{w7Ul%K4EHtYll@m_JuhGb9d+7o=YD+ zuKq_C?o0go-)?E|)~;KI`El92a{K#u#|gi4u21L~Xd@qDIedLfUJI~)+yY$hv zy3WqG59(Gtf%RDDd$(7!cP;yDXO9be>>Pi~(yOoR?7gp=sT`!Om@U^@a(lVgfB49< zv+bo-`}Qxz2=LNP=l*HwGrMYE`u6SnFh^GJ?N`+?|K4LerrvvS#~Jt5JX2eL-({V1 zUrwyMY~boW^@sOJR6pF~p{1S2{Pu{tk=H+7^GsLWs!Lz}ptIwd#Nn4c^FeEmlb0@i zdP?1Ijvjd3uKH_wbpHD@i3cw|{9E-^Cts4Sd%1emWtaVN|FZ+Hf2v&b)*9?s^XS+* z#Q2$)8{QhfXY|0UcGdsr=ywvG|G{wf?CgAV+~F@xId|{!(Vbsj+hBhF(~)B3ZMA+y zddH^YJ6<}d?v167j;*zl^0JWwm+YzMO6J36qch66l=gk#Xfp=$*zQxqtaRD9avxrIWnFvr z$f@PgZQZi7%WjrmjQRD;AOFISQE&A%Kd%S2A=5i_2JTfm)v*p^v(k-_oY975iQS+~DiKSb|CTg}$Ni2P&D>3kp z+i(`P3ukFlaF%vN4bIYPzI({sI78cvGqk6wmp;8Y!E>>?kpqu;s5j;B^*zYNv?LAe^wVkE8pWvMQUZ(d;p#WTbH+ld#>n)BroC(oFA zV)NX2Jj%D*7BmlSo;YRdf~hlR&E}5ZiP-s@J!>Y=+!H6yJ8|mV+4yRVXiuc}#PEHW zxhIx4R}cwaXO&27ZPhOU$ya9h;i*~k=LOfL;eYs71FowWvS7-!SHFkw$7utlC`QauF z#}C(I<3fMp9&;-VSvm^J(5og}yC;5r_Omo)!&8fgIirizqC~{vM@vaK|s>pps1%7Sh{!#h$ zk^dVj@HLV9%@JQ4@pX>>8#*63(`fC@yZ46uqw@7GeEPpD;u|7`DV1N2=Hzck{@BYs81uZs9J5#QkWFvLvW8-G^+ z-ktUT-_7rK>0x{uBhK%Y$xrHca|OO7a^D*9?Gb-A;?G6=wU5a8Z8M+VHzNL4#CJ!0 zU&QxU;K}j@S1F&EH$?9JBR;eO&qVHR5kEcRlPd6Ok$cP+M(!V#UljRY67jBxFR#G) z?KWSZmH5g?e{ICqM0{Pu*H_>VM(&#&ACH8Rzk{RoXYbDb_1EV7_MH5r{qg&Ap7UFC zo<9}wXDjfXk^8O+{FTW4oru@lNv6&hF+V7B?-_A>y}r#i$;iEL#D`SiLnHTe1zw2U zTO)p2#QBXoU;Z;I@Wqk)N99W*|H~tOMZ~YEz*k4^F<%?G-x2Y35x>XrucBbcxkk4B z;@#O_{%`riE#!|ug#Z7;m7={$o-m#uZZ}y5x=nl zzcq4?`E8N=+K8{Kz&Awh_e6Yi#J5CzYs4Rq_>PD_74c^y{(Qt=i1@AwoZq38pNx+& ze>ZZk#P>(~YV7&@@M|O9P=Oy6xgQhp#)$We_~3{Sar`?-82NG>t$%xW_PxIg$kVCRrUJ6Hh(P&|DA~A=GX(`KO*A%wyON3KGG3CDdPN|s@IQ? z__PXqVdVZ%`QpfbSH!Q6_ze-itpdLza$g_uyCS~H@y#e0a(;u}#&hq^{`5c1`Q2Cf zN&Rk*_zMw#@gwrrBK__Pd{5;5*XH}8@MB)f2Qk7=$|L5<$lczJZ|DCp?;Gi3-Y;^G zIlq1D)5GuFdY-GmhehtgBYxUPZZ;8zc9=5$_lA{t-Ve;)5&jROBA>bmSiMT;v|} zQsh3O0&k7nJ1X!ok^8iWpI?D5h};)e;1@;i7f1Zk3jC_beMQ8tufT7P+;5BchKTd~ z#=iY+iumS;Z;SZj75I+Go!?OQ@x}bP$UWveBli~~{$d6GdgNY-zZvOczB_V%$MK&d zqvUIFP0Q9p-ks~A|7rfNOCRIk7x8*NtQdYWUiFIjQ5Ewr>gpbJ2j`T5~6uD2Sz^6s-=SO^I#OGAt^CI^J75L)FeMtr0 z6}ev;@#PV}q5{7ra$gXC?!JG-{I$sa^@zU_ z@i!}Qejnb)_fEw3Mg0AUSNA;7f6RMF?#T+A->CQLiTQxYJ?4WV_m~fj+%pyUh{(M) z;-^G>bi_}O_}B`3eB^$1#3x03_DAFkB7Mv+irg1h;Fm`3F~25qzt-{JprXl#;hLMx zr{10O+5g}8%`SgT|E&?fJL30zM1Fsy-%^2Zjof4Yc;xW;xGJ4qlM$C_i++*Gtx%aKW2S@HP9}>C8JQul_B7RcDM^xZ#k$cQXNA58n z7rBp*_=F1l?8rUllOy-@J|dqH>E~47^CI_!5x*$nS5@HGM(#0R7rDp$uE>33#5a9J zz9rJfd|Tum^X-v)%y&fYF@HXCf3X68C31f~;%`>qyCe6Q?~B~)%P+vu^Ph+(EAV3? z_W=#cbJ|N;lBc6$PDdNK_@Q%p+yok?; z`0R-5=hn*gwT#D7!x&%2ciFuX?|w*C#*>)q zYq!hc#av&fU3S-3TbH@MO1RAR^}uDWul6l-ebwxLnU{Fd7k-ldm=BBGM@4)>#Ftdy zH$?7hB7SScZ;SXH75JTz`}&A)i13~T?~nL{75KxEd(5{)?lIpMxmV&(NBX}u ze>MvLxrjd>@fRY#s{(%|a<9bSiu5tx9l6K6mM>3q{h_`BKPYnV8S!2bPgdZ^MD8&k z9J&8@^C3}usfd>%J}lzHKO*ml^f5mra*z4w$bC%2PmlQ6h>wr>gbI90;JXB_!Jqu968{U> zKOa2;+&|CS4(^|q9R=>6xBfi1f8LeP_WS3ZzXX6 zf4BmCo!jqcU!CLlYH+{5bR)RGUU4h9-#@zpyx#5iv2XkR|GUBc{@8uset&%vxZe-k z0`B*}9tZdPi95jk^$R{r?)Uqj2lx9Ge0F?*JKuU8-0xq!1%8}czwp`dV;tWP?$?La z7;F6c@gVR6)~n!t{dokqU%xkk`}KW)aKC;Y1n$?jDR4i(WWX1?`J@Ey=c|*z{e0L4 z-uWp&?*u>J@$yF0E5Xaz!;E-6xL<$Y1n$$%XTkmYY(2PNfALxFQaQk?#Dn02UHv`+?!$i^+@DW9 z1-{7XcYkY0;C{cP54cbN0C2w_ zF$CQ2H)O!ybnTzdHrKlFTfvWUd=$8^|1W@_gkf5KRf+N7$2mR`JncB2Mc!m`)ZYc* zPdYviyw>Ue9=v;vQlV4SMR@6U_R)Cx5CxJic!tVh0&zFq>_s^G& z1NYCDaqZ%tFXOY7{`s<*;Qslt1>pYqvPIzIUHp7@(m!8z4Y+@PY&G~|r(XkpmE&u{ z{rYJ=xWE7S$Kd|{DL$L%-T7?d5pI3KXA}MU;;D%51fS{F54*s}IR9^eALZQlfcyLJ z_JjNT^=gq9@4pwgzn_$4@9)p-3-0g7JP!Op7k>)e-;bFC_xE282lw|=wt@Tm6Gwyl z`vb><4|DlB3*4`_rhxnV+h&0K_ZQ3s_s=_D6uDmlz6gE9+VADy95alsi1>Bj4Jbo% zzX{wwKYu&;gUz`Y|xrVXup8)sob9xHAw{!nL;Qbxvvvxxr z{|$JX<8OhV?)YBtNshk{&NZOLUx&4}KmY0lzQ(!ZE!T+$9d88p=|2|SzyE~KqHzsn z;hzZ3HInfHxPPC{r@{MTjx+Z*aQ{A>&w{r)_tU}s`)j@k?%!WC3EZFWoeRF$`JV~y z&;RCw`}f1}T*l{TDY$QMSAhHXt$Z`$*Mq;{;=2j_dB^!In14UY55VhPd%7FEzvKS` z?%yxMXSX;9TX}5*ALBTm)$-|m4&3*TUxWMk;5G2!uD$cwF3;Zu_s`>VGvO4cKM34E zf1ix_G2nMOegDXv&r)%WxBT!~s5y?8!2S8|2=Gm4!=@hz?#Ej`yX2oo9T)Ml!Ts~5 ze71>w#=@HkzQ^$e5nlv;KFY-Od^YJx$FBk3>G*1Jma*yAfcxj?)`A~}KXYFX%sd*u z2bg&>{va^(V0;TO^I&{CFw<=OX<(+&`18R2d8k*wZ+7l)0^jNQJHY;Y`+e}aw2k!6B<+CfE=fM5_x12jSyZM6W(*FL&(cu367d~6! z&j-(n+^2y1`&DLu`}0{otKs>@;QoGuE^vQ;?p5Fix%1;|!H;qLM({z7-v*v@{7!Ix zf9T!d{`~%a>fQPCX7J&TKMvmJ_*38u9p4GQ-0@xD{{E~t!2SJKd%%5p?gy`T>)~3| zMQ_J@fj2sS1h_x{?+f1M+>Zkv>v#%$lH)mWe?QG|@Gj@x27Z;}d^W(}Ps6pu2y31= zznB0%*6~T;e*f}Z@U_mJYq2{VpAYWecYHB;mvdhV-u$lD0QdW=-vamh ztKSAc$?0za_vf462lwaq{{-&$kN+8bo;!bi2;86lKL+mivwsHe_XBFFGj{gDNpHKf0+@Eh&p>6y9kb}Yf^|HgjH@ox6kAwUDkYmC9`R)ne8=bxx-0!cn zfRA_XCxiR_l2gI`_0=zc`|F!u1oziB&jI(>FQM}YhNw!Yy0{+{E&Tb-Ww z{_b#`W1~Oc=h*nB8y`3}`t$$M;Qsvl@4)^0gC~G5a^-anIQQt~SCu#qe2(L@z?VC| z0Nk&)7J=X9))$w8Z+GjRYry^a_iFGir(XlU!|B(8`}6Ph;C?^<9&pa#mR{bwn#LGz zocE&o{czq}I^4N)>^}{C+VszZ=bZa1;A5Qoo8W#w{T=Xooc?`qzaP%Iglhx~pL5Aj z$BzQ{```V*SGxEHflqMyq2TizFM#{~`jf!@^JN|2ZB9Q1-0#1S17G0cI~&}ee@_GV z=if8I{rY+@Jrx2kx)$)uQk6nvs>y z$H4vdLXIu|eZ3zC=QSnM_XqdyOXjEB7rXP#q2Ni!`RVCP9Ul(PYY-ORXTbgSMegnS z_XB?c+@JrB2jAxWPo&=6(UVzrH#jyvw$6vbuXOrvf%6>E!v791pHbT z-V@*(U3@%ZRu&pG{f!2R=u-vjs8hkpR>uLu7a z+@Fs>0KU=1_XxN@KYs#zkxT#2!3Vkce+lldKfes_uQ&e=+&|CpHn@Kt^F8n}F8n%t z06gWwKLos=b3YP%mrL&_z&BtGV&!){cu%Kq0#7=g2lvmLei}UG+}pv2xcEN@?w>a~ z1KjUVdHQk`OrtoT?E?4bqgR6a>#Zxn7d!nwfOk25 zGq}GVcRP5-&9Cdh{rSL;!TtR&_k;WS4$;)_sgCPUhVv!0$%I*=fVB^LeB)h*tt&xU+nm~;Jn5qzpBJ6aKB%AA-JF4z7Fos zM=k^R^V2sX{dJN4CUC#sdwZn+A-I3v=)K@KyY&48{8q;w1^4GGKLz*aN6&!!`SMrb z{(R@vNdJ3q|31dO;QoD#AAsNG<}-Zi`GEQJP;fv09u4mANBShVf4|(Pz*o5W;6!l$ zKDi?J1~)(aE%+wKM}qtJMSUK8n{z)C+@HTq1o!jNx!^v%v%vj)ej&J@&%Pe%F9Y}Q z@B0S$1ec%dz|V60CUC#Mdpo$#-w(lk{_X|$`TGgD&)=iqe!l-HIQOirJwF5P^ZzUG zcb)sI;Jw`W+wZ~s`Q%=3e}4A?IQIlC{2oUfcz$>&xIh0r8r%e{ZH-Y=`ZwI#@mS%}ZBmQi}e;e`L5pUoJ7WK#QPKfy5M!fnMQ_Fo| zpNrf(BibM8t0 zUORW{%qj9Y+sQL#b$)pwzp6Wb?$GIT=bSS%o#=L*H|Lz0bEi$66A9pH^2D-R=Q%Sw zr_M+OqXc*E)OkY7nzCj3%xSacTyW03>9b}|EE~&-n4|tW&znE<%jFoNu#i~jhK@dY z%x6yd{ORe$#EH}9&+MEy5h))!`ZM8QGf{^BviQe8T1xmU5a;=?$bU3tf;%0u^qir; zOpcVEvLS>Ppgeu#D9O<^Paj3P<{3(nuEk&rls;M*QHefUXe-fM3mux9L!47N7qa!hD?sWGNCjwIfj|Zh=n0%(m~%G z{5FShLasBp5OS!5Ovp8cz`wJ3&$eE<&k;gk@do( z>Ov_nRO%S2>O<`!RLT)54^R~}?r=mXp}q0Q-18Wc+8P=M;58xGBq-_Rmq zWEOE?>JVEvw1)#@3$eEA5j>OtxCEHByoMHp*h72bF(kS*^f{zLqhQkEsQD9PNFj_G zV5qCsAc4P7BCXAmnszy&qC&rFgEOo$z2nr5gth9-#m z)}|Q*#iRPuvX%Y`yOy!^RB}mWCMQKGy%6?LN<2!fXS5VDA(u!!+-R*B?O|Fip;pkPCC%Cvw9|!=9d1$-+VjFdGERnclt*Z? z?cvbcDh; z4>KK)8e5n>$hAd=nGP*W^Oy-EFS)j~(89^Zeur9=C1=uxN{ zc1yHW8Ot&{Dr9t2kRw8okr8U90{u${e0Y<#EVCSkALC3NbXvAqZR8nkIT>v;GD{)+ zFzVx2lGJ6i%VezIYYWI~3&?6I$;`%hWpv4EDP^^kvRXRXQ0LHvIg>}#>o}d&fjS#T zYPg5;;899F8^#@SDfMh<1?VftB^r77Z~fQCH8E;wOLWq<1#5K%m3YZ&rn4;?sWz2t zn5+@G_KmD|j;t0=R=Z9%3@p@X=1Ll__V#R80KmPZ?%E`>VciA04$)byjI35hR!4-a zR$5kv@T^UfIyhvta_oloz zV(@2?ar6OFBxnp(q>MAejEtFKCi4a)6v;%zAMh`NsHjw}T0*I@Lcm&sN)S=eTH>O_ zr7oj}P-Be}|BKr1JA3apdyXh!Rnwfc-n-wo&pzj#d;adZ_np0;j`ixWKBJz@EY&)( zR)=u_x!pUyjUc<< zYsm^)nKE*rXUh@op|UQ8T<^mL?ZJhDR;QLjRw2;SRYyUurl6gtpp8<{nkZ;Z7PPTt zWyf}y7)RaWmzr@cc*c6nB} z5iZl7&gI(7dK1-4(l*!IpVpuDUG1WJk=l#2%5}KtXb3A!%mvc=;TZ=^da2&xbX@7M z($TK>1s$_`H_)4b+{$qO(>|fInvVOtPJ%kjb@c0GVYeBb5c4`g=C%9ewF>e&5b}Cy zdF}Xlt(3ercV4?iUI$cOYcg+3d0h+SZLOn)%4=~7)=XL>d7aA&w%XBp%j;a0*SRLI ztBSl#d;OqhRZATYzh~D_FPExh}7@Rj^rGt5_b((5AlW zH=u%c%klzK=g5MU&&p+Uxs^+&fr8EH+U*NkUjO9kp|&W8+E7L?$wd}iMO}Bv17A^}`@&U1 zGpxmmp>JaStxONHVhQzKTeJi3)L5cRaph1OE)6Q2*lV$@l=9|f=~UEXt*qA(uZvxo zsK_;4dHKnfggo>N9yxPh!5C_oT=NetMlR(oFJr?9hTM)}LPq*9)ln|jAS0EW6Elvs zaMhZUk%e?xNqPhi6;sqBxRzIrwfWE^ke?lG!K=%9d9dU8Lb_Uc00a-yCe9~K3ogwl zH$ujT>qNYsUzeWpV90pQFN`E`JBC>i`C9vwk5Z2^()mazjVcRnJ~D=SFX|DTb2jwK z$Ixzg$dLNeBe=Au9+6JkM~~oA{_@e5*5QVV{N;#8Ma@@^;94Fzf@^u~SYCqb`N9m0 z{ItF0(Un~4RUTo_eR@+XUwqchD&e*2^!l#)Uh&PHO-*G%S4$go zf~c*jt;CnAE-Q)s^sE}&XEwK-D=%4HGQKM<1!-MfeF=r=3a?LlWnJHjx59M|vzmKJ z+e+uwHFnLZLqYJt3*@dYy!CZi%f(SGym|If$g8f@($>-1R98QJdflv1y%I*TtxcFE zd}_&<=joZ0jhiNoAL2HMHSP zJ6<@qw&R8Q%u-9K*_h(#Ewf9_)eyGLY9;WO;m*@B3+4U9bv8D&^sdpy&=Pnd-}T80 zq!1TgzF@6{GXJbIe|r6gf_+8>X~9uLKL6JCb9)4A{FeIGmbqvg{!pMLDkqS-lq<7L zKrXP#HO>^$%#$An{q7!vB~@Mw=0zsn|wIsS_Wd1 zkD+{|oR`?-wENF?O4+7RNAn~$oo32uG>brNa@rhZzN**jvE zmf&5$nPVj_v8DaM>CpdAMmN9`n-2GUXLX|&eg0&Qmwbp#XBg!th@9Bu^x>1CVKM@- z$;VSZTI9qgKhw#HP2K>UK3}e-gF0W6w8W-!8Ra!1CpP)Dz*(&m`q;^wC_2QZLti?% zIghu2cSR`iKYpLX22?}+|$)X{n)HXYh-XXlCz_n}+85u46Olxw{ao1DIDtlo%C zKE%n1OXn|w0m+AhQC)9f!O48DA%?i zHu+VQYg-VTd^zQs53$K zLTvK>*k70_O8+4?`4HeV3xzNYIH%>Q0?uA4a_;rd>ITpnV7o?Q%ZK~_O=l8yw9bi5 zXDW5*j0S=GEA6_7O^0>^c3s3KUqQK+pV;KIqt7jrJZUqQT_l+HV1~B=TbYS1?Tb!l z2k{k>_I2v(+(>NtA5m^&+{x)b#Ks`8=?`#nVv`T2T*oG{$&YbzVw2ZWu4A9r*XKg`j^0ky}TM(OkJ#g+ysYCkoNM9wGwiDT_ z1@nKdtu2TxE$t^v=RM+UL_a~7O@Ci-Kj6%G>BGd9Hsj>PCLaWBc@70mUn}{HaF|0q zy;$T8z;<24mJfX!k4AiKLj|t zOv*;T6Sf{BHk~n)Ynh2nJ`s38tE441`RTv|RZeX3$-tRYq|C%7r*8+l7Gjgnqh&QmJj#Z zTH13QK9BfTNz47TrbF9NJMSD|>nFsPC;cax&c(#HNk05vO~bbXXC_MB5?fmOTCzGP zHaTr%t2LtEh7KZ?#W;PeW?v{}mjK=1>=*2jn~?Ix%5G%*()2+vSoH`NoH{_DVL&GQ55 z|C8t^um{SVCT&D)`m`gmwH&d@2LNYRNm|+}Wlop0#HK@=BP&1cjjTMxrc(oK(_ORo`}!Cvq5j|9`!-|h>JbvH73aYvYdC zO->&$Ru9A`p9!4%H!1Tx>S&(CrbGWQ z)*pyXPCqf0C$Y(I2F^VodEQE_^?8TG+{15mNNj000b3nzp}yAVcFKP&dA{KA4&b!P zcR5Tud7Gn%Er0sTuzdOvua`Uz1Wqfazl{Oyp*siP8K;!Bc^44M1%9 zbO5Ix6`k4C(LPUXIu|-QvB|HZT>Ct+$(I5TXp=mNO}-3xpvs9&z8u)*5MqXCD{L|BA>yA$S*XT5%t|%r)H4;RAt9{}3l1N;F7b?lw`1t&GBEQ2RV}4j_m-A}@W_}~^ zVOWFw43jgCAO2>6y6eCpgjb-)y0<_b1|IEN$-jgOdT5roRN^$tGNDRC8LTa+x8+h? zuiD0tTYflAxy>j~@WaT(0mzr>@#mgdT`jFujaBV`Rasd%0v`*4<@=bUj}GEvM^+ak z{+#~bElwDdN?A@k_ixJQ=UFa3Qp&@=3hN#$q5CKGPaga2Vb4x^y59>!o*Tb?;|1A3tyN%uRP+Tv*iDu(nUCxNB0w8C%b&J?q}HhD^D3N}scL{dL2HtrKcb zz4z23>M!hGxv*-%^~m#=-AS?zwR6#(`zNOxpzByUEW%tL6cklk= z3#ME!HFZkr@#DhovX>$34sp5s*i~nM3n z3Y2Z-r4_|1pZNYGeIMOFsaSOQ%hbmC_UHN5FFknn`AOrVUnCddysNiuN){~qa967M z{)2l=`;)z<-P)5DjWjwLd(uhARSs|LY%i6%+S^-m6USCIl{#|yLRFz^L>=~JV3+TR zQGZb>g5<kl@n=N}UBp0O|Khez>8MSRR&__!!O=BG#TQzFiLrUWU^Oru)R1H_r{-!^tbPYKO4nA_XYD8qx@t3QWPKaSEBfRC%(T*PvUg>xZ_!P&B z;C{Xz4}Q0c|2nvz&-k9r&u3?W`|&yr+|Or?;IF#;W`O(t+6M0XE8m^@_BbEh_uqNo zJpn!wL412%3GU|$KI{4To51~ez8&1(&wdc4=d+l<->d_l=B|g&UOxRJQT!J0*-rnb z;5Cl(S;^=3^C*5NxL=R_8vHPq{+&pl|1mqr#qS5~`@;d?gI#FWD0$BG{h>%e_~ zUk|uW{)!;H)Dn|KZ?E9j^rU{rxN8GhBQXINQw9j|BJQhkLmF`u8Mozh35EZa=i8~DkNcY#+r{&(Phe9^!7C>MV@_)y2M0Uzf0_27Pd zEeG%C;_n3S<2d(*`|-CLJaO^-kJbK;KMd~2=VoyKzT)4(U$W{(M%%#s_O5Ozb_q%t&{r&JmaNc7iq>{e)VZ+})`-5{%wD^O-ry5214h0|O_?N-` z{caN;c;6WDCn8S&^~+rTKLcOx_>15x9seb`pI=`G_w(!9;C_DPf2zLb()ZmDKKC8( z5B`SZ2Z3*NoO|mZcl^&HJ`9|5uGMEQ;zvjPc<^mbzZRTxvZX%-e23$cz%8T!rbS%M zbAk%v)tsix=c_))IDPEtmf&*y9f)UKrN(nB)^6ZI%DIK$FqCJwa&Eb+0UxZKTc|i+ z4^aL*IPW(nD1Q^2{mD42Y)1q)eCmoWSn3C3YW!M0fkvS;+@&!o4M>AEb?|`^>|cYi zbFgF${xyO@dGI_D+&2W%+F-vL%<_XJZ7?ei9!i2Ct+_CBzRZGwHeBHZdsH!1k3AO! z8|v6;j{3q02gK2Q7P$l~T5)bxE6&XjN0V&CiDhTN zT!Xr(k@9H~LInF68b`{Z{wk!l=}DK&9pq0c?O<>q}jqZV4SMjAP4T<-N?ODf@&?^`7jkW3yw-iwxQSlH(8@()xoC z*F70NP#_Rj2PDrY19l4Gvx>-1FrNdmZwux#Pxc+b^NHUTd^x8M!Le7Hv7{XPAW;8!TuJ!(6FbE?1Z`^W#pMVL0>*lQWK=aroez9XN!*XT6?h5z%1;b$!vh uL2kuqu_>kK*049}#kQVlH7MKsiLHKyR;YZ>bGsMW3>HRO!I?)vX literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce019d13c5358f768b89814752c2b8a0c5c12a82 GIT binary patch literal 1459768 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
        ?ZI+AFUQK{`lfE+H6nj|f#v$3eDG63KM*X} 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%0DH3)&1 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򸮫 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 )$LIQj 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
        Y9azy9>s&-wkS^E-%s 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 z%0AJBi@|vO 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�YLJxhH0V>U+# zbMB0(GiLs1Mi-e`Q34OBo;#%a(k>&aG2v$Ixt#GPVV9rk$&Gn9PX`UB+I>9jONUm8!MesT2nH1dTCA1u~qo@ z6}t&ixeiV;F6t{b2}KBkmDU&u4hI9M12N zvVRXLk^1x}P5ha-m+{x34XOBg8@uJc#%{UX*asLMYIxMwr8mdD~x@$;q`_$7~YtHA2W8#Ta0~Y27blZ-!%Nb;V%r!+^+uT z%R~Er!BgNU^<{JXWks5~`%O>dUurmRxOWEbW9)+rV@QYoe0nb=ma-^3AKP$!vAwg} zvBB@l;lIj0k>VG-<;liA+px@A>wkWK^@bN^;2Vv7MFw7N>}w6LGc5Dua{BHzeD4wR zBgX%+4E%(#Z#Mk2;Vp)r%fLH~-SX>XzZMxG{4};PkcYW&iG$%c%|Xh8F;O+Z#29q18+8V%Uj6)9F9l0C$^#fX1kRCZ<@E!{w02y z6Wss&^ZW8ZFghvD6ZU(LX;8~YoE-^#%68oT9#WPcS0D!dBYkl$>V{P=fsx`V*y zx8>|?B*Oi?J!&}5aQh5gVC;n%IBx8glg8f1aNi6()Yyj`mO0+}_(vL^kbx%|`!vHf zhHoU6=Uic_Uqbm{yOfVid>h4=i~FkZg%ls#CB7r&J1Bk$zsm6147|?R@6Esu8~YZ+ zI}E>W_#MOgi3n2e%lEs+zTfcsh7TA%M0^7BTeutLH`^t@j+8&6_$B-o8Cd4X_dkDp zma}sj+jBE;Yh#aQV3~iP_b>DAGj}xHnfSZNKVi;4w#)G!DW5>`OZYAsxT~>S?qTc& z8MxHg;~BV@vG+FI$8cZbamYX60oaE6gY9zs|85>Y>5=^%DOZ~CgA9+zz~>wLk@AHm z{Fo!;amIgw;faPPW#CJUeby23WyXJT2EN+ZR~TMvc%$LXhF|;_EPX$6ujBUgUgQ7H z5%OW<-yGxm{m<8jc^SB!v3D@s(eMcwxVy1i?rH3qSk|iGEV|j$Jk1{;Y@HE3S49_;aI0Ii}?AIHG#b{`~AW{<1y{r_Zu3bC(LQOS%11&X&fA`}zIl zX5gr?w>Mmnfs2j3)Nnil_c8Xq8F+xP56-~Dj9sU+L=O4E z|7+H1s#5+sWmJlFI-nHmv^Xi&DOFOeQ*)&FVUu3Vn~is{6WJX8^$nP{rUWF zWw^az3^#A&U+^`#mkD2Pc&Oo#hDRA5_YLz56QAW-#(w43WLYD~|NQx|e4Vi`GrZym zd6n_skbyTD`y&~6i?PevLVSF(rV#T!!v_sVQUl7gyc+IcxSQdm;XxUAxUpYoc=8eQ z4C7yuffpLP<;BJ>YYK6GTE52EE#GMDs|??rfn{AH-oNFCjeU#ZZHAvS{Jh~;Gw?oR ze>VdkF!m1&A2uv&8u9U3Ze{Ep40kr%#c(&nvL+Jm&vFlAFECte_;kaShKCs*k%7k; z`vk)?GVpw3Uuam?PU7SLck@oOKg+v~-LkCX#OeK}d9R7z@;kyek=oTGxqI1HWPHI%O=f$hYq@@nLZds>iPT4K%6ul{XADKkX{d{^WGw?8Dw>-kwEsrwx z35G8*JSzjwHuiaj>of2oW53?;GQ+YC9_QBz!z(lJDr2|2(bz3NZ0y?%KWBJ{;WrGw zY4|O}vPK^t?*YSK7?ySU*k9J>`&ZoB*xMQIV7N;L?rQAa4fix${tfd;6QAW##y-KY ztQW}nHR%ZXGUIP~p|RH+US?RkXZ&Yp;JL;=KLal^_UjGH zI+2{8EB=r1YLgzzvTh}(-}2qYZuvfA-)Q&&!;fX)=ZxL*i^gtwm$6%Z)!5(6!0#CQ z$A+`zgD3a%?H9|Cm6fsF2>&7aDn08N64}kE$3Hd1|DSW zN6N!Z_>qP$G(08)%X+w+{!5OKry2iQhUXf-G6OF(cFT*6UDn~{^jltG?3Qma_W!^6 zZj&C%8;$*ue>2Pa#GJpDw;B6$8F;6$TYkmZUp4%O;R8p=9~l47GVmA1ex#h8*Es)j z4Mz>xQ7vtaEaDic28=B95CN4Gpal=W&eKPO}W4AoY*e%O?)13Zsh9?=G zVfcy+TyN|vGVmS7zS{7*47|bEGx0{_zc~YMF?Ly-n)B}s!|xhCWH`5NmE?;lrv%JjME#GMDD>LwI#=iCl zd7bg!kb&_F?P$c2053{+;+OE2_Zs{Ah7TD2!0^Y04;glgD7g&t&m&)#bKCjc5AT~S%i8Y#=l2&ioM*V5 zVOay7!*}_HxzNOCxu>!B$-sk*eWYPoPo9rwwBZScWu1BUm-XeD7a5lIFk$TL4+ zc$?v!hF>wf%kUe9-!%M|;dlR!b2iqP=lrtV&e$!VVC_^IDO!#qzFEKnV1J5<~c}K{X8UOi)>kThHLSA9~Ew428wHbJwv2V!0 z_Zqw9jmB1~V)#YFZy0{}Yw~^*{(ZxdZ#BLiEO#_^%bktga-p&JHay7iNW&8{@HAt$Tx0CB z4X^x$d6kLpo96W_o`vVzxld)&whmHSc!%rK2J_GMG_E-PSyw}8U`5j~5mw^u$ zyX6mz-SRT@%&%#C=PnA|TX(iS{9AnYB$ z^NEiK*ARCF&m%qwyq35Syq{R+O59D{3;Y1_ncywNG8bYp#aWR`Fwajs7|ioU%Xj#L zQhAmYIS0)1qmBkYM)Ao~(Y?uk0+{Fbyco>$W6E5Kl4t&x75O1#oOy*kT`NwVs^ZZsamm<$UwFb=dXRQbG{8smXd48{r zV4ffAAu!Lk^%$7v`*{k?^Vd8JKA*l%e+k^3_+>E9FYyO3&qwj!V4mOOZSXh>{~nm< zOZgj^zd!#3%-_HN9n9aKH$`6Zd;l%L{QdSZVE+F3STKKo-3iR!>z)Ya?_W;>^Y_6; zVE&#v2IlXnPXqJ!%ijg__sA7s{yudGn7{x0zJyO*&{>fmfcg8;i@^MSXcd^hC!GT3 z?=@$F`FqbfVE*3oaxj0tv;fTClU)Vo@0qRz^Y>uO!TkN!&0zkX>}O#9zUfXdf3I~H zn7>E+PcVN!_7IrAhk6{$-$OnF=I`}>1LpDSzXcDa@$0_>^Y;Sa$){`5y+9?$t>Fpnp#1M~QVC14&u^Aj+SKe!3ZmD$V2fH84<12m*=J6L#f_Xg1R`6x?e)|P5kB9j$@JbpV^m{OmSNtQG$0O|l^ZSiI zgZX{(U%`3we()nOzfb-g%=KiB|!Q5YT0l1i+KgWaldF)~^ z_fJd*bN@>%n4j-11@rUWe}MV<6^l(p`1x@un4iaQ0Q2+lPr>{=b32%yU)F%LseSoN zFt@*d1?KkYgW&WpEAlv)+n3wG++Kgl*k1v2`}uWnH`>3<1;*{;{a}86`Vh?Ve+K5~ zlO|{zaQa(<`FXVsnB$YVzW8~vi?R0r^L&}7f_Xm2B$(&3>;rxn*M$F}eG2CJE2VA2 z^H+`n^Zb=#z&wBDBrxx92AH4k=YaY6t}rZfUGe;~OTj#!=rV9CO0Ucvbpr8fa1Uac z+bK@G5j=?a5irLub2o8+>TkfD{vF^vx_)+pI}^VN=KjTf;3U}(fH}TH;GtxfwjcM$ zH3xHlTNGSR{?c~j{;)1!?hli;Blm~(1oQRR3(WmteZkxxHVDl9VZ*`PA2u4?oSuir zf!h;L26rH?0e2&w2QDC<4~`Qr2A@uRJ$MlDO7KYHRp4>N>%m-K-3R9L{ScV1mnRHw z1M~duFM)Z!=~uu{NSodLvLdg6cM;26LOkF2pTRBBMhgB1z&zjhCt#jm{4ltf{BzJ& z=J~^0fqDM$wqTw=yd#+B4?ht+o8s#MzJ~ZzFwX~`1oQLUnP7hYlev00KZbz$`W*r0 z`L53g^Yfp~#l!DEr-1qTlV=mQ&ja)O!uepnU&`D&qv-v^^@dl1CzE{@nBU*62lM;K z`@nt4U!G<7eWA>?GneeofjblL0N+Tw8@!hIP4E`tePDi{|5q>{zdS4TqW8sz!Ii|h znA>DHaceNYKbL1Oet&)fnBSjw2lM;$VlclyPlEaVc^~k4+FvD@-=_})^ZRspR^#{S zW59fTlfXQFWIC9~W6TEcr}otq#*Sr-8~HBE}N&xzd4xO zt5GnwpJi^FwUnP-z}FG?F!r8c9>3HJJe-cFFPO(S4g&M|#^GQdzc?Dq;|IrqpP=|A zgL!;l4VcFV&I9xK!1-VvAGjFI;{mS+pFqdA63pZGR)P6>U_F?}?>ESSsFb}&DG?E>@nAa8)5rstt|jQxEue{b2pO7J#%o|e85{vK--IGc`l44A*4ngs4b_8DOQ zK58zQzmK{S%-=^X0`vD#*Ma%_s1@M(6#pGy{@!UFn4eGY1@rUuCNO^w{J7ZZc(;JZ z(D$A%g86&eSHRbk{dF++C&=6@_mO=+_-SI9J7ov)7vR0b+30)W{)1Lv{+_fQxGSZ% zGnl^*?FQ~c_Chd!4;lya_n*DN{C(#D@GJ^1eN+7X=14GqpLrpe=U1o#bN*fe?n3=R zv%oz6z-8buWS6--cz%GZ!L!J|49xvUw}81nO8UC^d-)Au?q8C=E&e|K5io!M{xtXy z?eBSTHl3fHVE*3yRWN_A{ua0=`M(S9OZ)+t*RT2%%SYkQv0+uxIOW) zVDA6#3?54MeDE0J0`L{YCE&%xy}-P_(s#kPkX_E*ZNz6wcsvvNAJ$g{??M|V@C9I= z@3#uf^V3c>Tnpy;W-kZx{I_-B&9uLz;9bPa!SYNO_J1pw=c8Q%mS@UfzYDyM_#|HLyGr1^+!@?%#h8%=4*!23gvAd|@Ag z`TfA>;CCo|Q`FsTKME}Oh!B5U!=1o9zg0fCBl({K=J~>6;9Rnw0ge*)2cJ$n1pF4I z?;Nn)Q$l(!0Q38ZDlpHlG}Uk|nCDBn9DEJMR|lR*yc9f-csY0>@vUIFr-k&a0rUJu zcY$9g`~Bc)!5!u25%7gnUq1z2L3a7Jel_uL!5fKpfwvI<5xj$VFZfO3_rUKHe*pf1 z_){>iCmKOpiPsZt1}>)bwg&V2=wrd7$le*8s_t>T`Cz`j3c%y=Oyhr9krFVM=U(8; z$S!R^p1*Vucoo@)gL(eZ(cq0_9|z|7M5S%W^NH4gc|Os3V4hD@+KxP*=wfgLZSau( z>%pyvr7hWkcomrE6I~DH`9$vn%QIAn?_sb!Lj~Rp=J`XP1Isg0uehAF-Yevx4e~awR!91U(e0$CFS9Somqw80`olX+>01qJU z2_8z^3w%CtU+^?ydDf9)ciIo;^_LDB|IfjFDSQ(=+jk*u0p|6G+JM==1DMyp z_%?U|g_mzjdHtLs!}4t?ua|QMnAgiG2alun+F4-UpY(0;`W~afSCYSc>&g3{4CeK3 zYQVg{%{=fTO8+;Fqqeuk#9A5 ze9LoSUf*R0nBQOR2FFtkoUF*3V1D1W56thY4uJW6-61f)|B0Y4h5O%|gL%EPD45@u zbO3Yzau@KJ)D0vn(gV!ngXCQ-j}Phv=J7>+!My(8ATWv-OnBS*f4{k;FmEd6%-zqS_KV1*z_qq3h50L-EV16IF z89b5Ve-6y=M|ObudGhyQ9`E%AnAbmj8@xGHp=7zfT3&zjL)f3D_YI$cdA-;y^d<9n zGx=7I*DE~+%)^ZWcoVE+E;IxxTASOMno0e67;d!Th-?*G0Q z{3`xJeZC2@9CP3&AnzjH2ATW6w}TJhoCSa9Oa5;_=Kjuiz`3~Qga7+r9#8QxnERs- zgLynfF7l51*IWNT>fQy+%CcM^Uu$3nB({!&2O7vtgA&r3k#!gjMuZCnjED%8jLZ>+ zK|l`U%z$Xr4;es3Qxi{-+nKRL9D^F)0{*V!+ra&LpQpjk zarU1B|CZw~f}ijBYv6vp(Ocktzp(ef_c;IfZBU)#2ZD19Y~ec${9@-mzXe+1%m;z5 zcDw=H@At%a^Bgmqd;FH?J;%p``}Id`dpV{x{b}HSJ=3Y+hd6V7OT#g#=`RH5nAG?Z z@KYWC7Pz19Tn)Yl&*Y|mF}Pokb|tvq@9|o2zn<+T@b{ek+ra&Lw7bCldb4}M{rb2q z;C?;aHgLbb?P+koKjU-Yetq1F;C_F<*TDVyx3|DwcHw&u+|O53p>JA)IV+3*f#7~U zAlDi^@63+?_v-@(fv>uL0*81#|y0aKGMn9k`z#y#d^xzqJ9}pJ%oa z+^;9z49+z$=Kh1=ettEq#d7{{hk0Q*gy;EZzzfqG;Lm~2H0Qv75AN5y{}J4;hu;l8 z&guUJyw>r*f#)2r#8~uX$9sbhbG#3@pFijaKBy2t%s+tp`J+#R`~9@D;IBIU&w#({ z_*ig1-}D7=zhCtU;C{aCYv6u9tp(iguYU&kd+zzP1KjVY{|#_I|JDWW*YjQo?)Ot) z3qIY2_j}-Nj;{yz^JD)EeuFc=1AM+q&&}ZHJN^JT&vKP3nRpc3f4}fk@MUI<{C^t! zBFBFNzTNQ`z;n*MKZ5)3A9jOJcjkWq_s_q{kE1-h`G^C+{rc^L!TotU9|wQb>34)@ug5+P+^;A9Jh)%){bg{!e*CN8y`B3rz$ZIC7u>H0KNH-a ze{nYWLZ^Q&xS!8BAN)p_UYCI1@A#GAPdWZi;2Rvj5qyi|{|x@L;~T;K{K97NQ7(NR z1o!Llw}Nwxh+N6Uc5uHwe+T#!XTB4hYer1}74Yef?*{kt9q)qga`X2UXguC>ychT$ z$7{g-_Xf4#RnGl7aR0r*5b$beo&i71@ngYj9nXUgaC{>8k&aIV_wy~&!MnTX`I8^Ha1%?5CP{_{p~KVP#M ze7v*&Ah`dYW-GY=er7xPA+EpK0Y267o#1}H=M`}O{mgFg{!ag0aIRUk@=}2h%T9B= z7q~xPxCWeSYE8cu+|L))f&2NQA>cEeeg=HLVg8TW*PlEgN)CYt6`g07puP?*E zr#kmO3-0IZ#)13tItjeimA@0gk8u1Ha95U^Kfgy{dl|%+^em-mk_!eir2HekwT?X#w@796ua{4z!d;_@O zKXoIxpFi6S?)N)=5Zuo%ZUy)AYumy7eAy0gKVP;J+|NJ00`BL7cY}AwoRrn4cftL9 zaK%5Ct_SZG@fz?+&VDVppRcV0Kh>EJ0r&II8E`+Jdn~wr-;j^^L~y^q&Q$O!%&A!T zr-S?bb!LK(cINZI{riJ z#5*E>X~cgR@$C`+L&X0U@sEEpQMeesV-N5tQa_`teCa6)eqRLVd@AQ?m>vtjIlp|O@(UyTn{>1v;DhW!{2)_4D@1sOhx?j z;B3E8B!c@b;C%mltnx1K9pEYDH-qziH=m&xo`?v% zG>j<2zefIL`IqD0aQ>x(PCBTMpkO5as7PznNE4)KAx%euewvyY+R4(n91XHm$x%5+ zYmIa#N7G?c9!BL6R2f0XhX)kA2!9O32wEE%JQ^B&%FuQ?69SPAc&K2ykj~KAbS8u@ zOZ(|;FdZIDv-CbaJecO_cRF~P4k1bp7tP?p@Zj?B;A1ZMo(uBEU~5E>j|lFB;HN_{ z(<6edkwIr<@O>mTGee0pA#9mU2*XIamXR2Zq^-x9VF4)a6Wpa(dg^&)pVU%~aF70H_v>F(n52oXr!fo25 zVIfGoGZ}CXj*icV6dm6bZZu`od8aopr9Uv`jZ%8WI};J6OhuUTHccxN@5aSeIuvBc zL-cqTSJI*K!xfeXxWXIU9?I}R8UoN1Zm<)Q68F&3@UCuzVnj}L+(YKWHlqPIB{q%2 zBt(rN)22;o4276?#)E#UdB|GI#kI!J0Faxx#Hew&q+#O-COOPUNN5^Ebth-x<6Zp^ zjTU$)M!bu^jiEx5tAC+tkgI>8!jNm8g=)m`YCeQ2kJ!>X#8!Mwhav@O$fTxln>Ird)1-C9O%fnfifNNHIvR`6_Cm<8!*>P|VbXlk5T}QRpyosA z9^Vvh`Fti+2;4(cn{U!PIHN$hre~<~NDnQKjV9N!)2Jn}F;rmcX}*N&0v@V5?;&vc z;4MO-xf&`bOhfwduDPP+xiM5m$~E`3JU422ZVXKe%tN{6U2{LH?u15`aw*}Vzk%Lb!k?%=dVxwxIva-Gw1pBpBw=CnTK zLeoACJ+H}`-mo810`AHkTtgF@I>aP2cD$=UTAp%Rl5$#7UO_H_p4{b58Rwr}>pLy%1XH zg$|8()z`K$r=={XH7cjAOHSLUoR&^$x)FM9t8yV!}c%2Q5rBNs|F$^;uD#9G=U>87Sl%4(iwwdQBF>Sr~tvRe7GnpauPtE}cx zR`VpQd63n%Dyw;s)ix@pd63hZF5MwQ8`>z|S$4+fL*kEb(mcp&4bEyBW;KnoT9c*2 zM=Z1#ldhRu@oJ8693^wD4xM@Mg5|X2Pfk_Oy}BXkoUdMaHr;*YHTG&WEy&3}SYoVWMGPN<3~_ zA3`=saKy4!JR2i~jK~KM;gY6*=pyn>X}RZRgikI_U^)~`H&_epcei)&`UAcoxOwx@K;H-8US*yNUxn+qg!Dn>wmtwvNxsc%ey$4WW9%Xv>QmXoxWkF=JLv;{}o;Ix*Hw3d&ww)SZ)A89QIX)OoCG^K}Wy%?sA(lBiqhG`=_ z%$_c^QA%q?7^aP5I`mjFYIqy9d^Kug->B&} z%*I#RDKv&j2#mM1a~P)KX$&J4J{K@Ac$fN<*2Y4uY1g4Wht>ggT1&1Dk+eMP@JmNo zY3 zNKf}AmW|rQG#1A166?moh+4UJS&dfTv^3?kb;#LMmgZukjoWOzsHHcjBc+_CcB6Kc zInAw{rdm$pnbY{?w6)4F1T z1aRvYHQjRBD(5s`a+)tPnE-u@k3MtcwDig(1l?Evv{cE|1^tm`DW|3CLKwVXc9)nfn1BQOvaFFm#XDfreq-3p;FfJ zOVe4VX=tt;ot8tHRDxX7OD2cFwfxEi6wS?^jy*NKvzoqHE8h|CfgHdfF~&gvs~Rtr&9D`!>N zMvG`hvo)g)c19ccj5fs?EvgyKZkZ2dRSfxM(;V8~i67P)YU3s`wHcC(wwW1iLo+&T zm8oC^RGrMID;ceG8BNZNW@kq0u1p5Qp0*_!&DM-2t<2oeT+&fyZs?CbhG<<%TQ;fv zwCbm|*re6{v=$c`j-woFn_j*NfZI8?uz`l-H(>l_W;XCD8mvjUva|@U$kp~lbc#sLXyi7*sWik?s*$5`L(01Yx zhNUrYGZrCnz?i1E1x=Z(0#hHD?{FpDWFi)fMH@Z@6`8cnH-#dN;htEKTRt>RFcS+Q zl3-#lbdMMUiUqmlL;B^L?=TOcgt^{BvjjaEA4ARt13c6>xFdHw)~UYTC7U4+`WTn1y-@C8Pwp7ROBD4E zeJLJ#hqlFlOP*rNpy% zmvoVrYMjxO@=}<2*8Gw75cXv{0MFCG9dJpX;#~@;w5xDWtDbZq;9Bc4`q-~`Og?CQ z-^>g9j70FA}@SV*I@tZqq>HC_`XlwgmbG|PxNfqaKc+cP2Ilqj;jMGaMLJEWh1Kwf21n<}@ zdTs5CmdJX78MBs@I1@}}w$5m8#cG1i`9Z0;%AxQY9;+rg7kBJ!GrXfmVm7zU#5#Zl zi#l7IXU*uGQKA@V3#)1h-{D zTft>|6XHL&1FJR)Vx|h#m$dCw3QXACI=^)RR2E|?i7z`P<|QUl-MD0AA7ZBKV&t3T z{K7?@b7!AjSUnSRW>H(~!sgZ`T)N`@E5@}nYg%T`O6s>RnYH!p5Ov|7X3;2PcdjO!$``0?Vm zW2uKL1IDKdjwiB0|n<@bo3*yI&l)A}Qk6Px@%%I_69vB~=a z*DitsxQI(od{Zw>#zMjRA*mUYBe^C4-Hu*Tpe=Krh zlTV|3Y=~}x*yL@%)f%2o>S%fro6d44CpP&-PEKrc?!jCCq=bJ1aP`jw-|p~Tz%{yA zBC*-MA2_A@+oopF?F9V9mS6w0*@5}W)~%C+tjn|wayTE~e^z67}T zRmoFglP?4Ar*dMGuLQO_OKkE>Dc5$D*yQV+oY>@d0@w2}BV2bo9b(hrzFemB5OC@j zqW>iIHQ$L%pXYj{o)(>*PKVfZ`0cOd5wXd+r&{$d#V+?}vocIik#Tw_fY;5krSKzQOX||IkCx~qWlSw6Px@w%D0J}*yOt?|Eb7{P0l?K zQqM`cz3VW)<*v~US&2=bdm5zvQ}mB;cnGlR6Px}R;Ogh`hl}4=+gOO$bokwW>bIgZ z8@KA6g6H98;}BxgZ>L<#7_rH}MY*;=#3tvy1F7HP57))i(RPE_bgrRX+YMrqZ=hV; zD`J!1O}VyL#3p};a&51OP0l91_Ih+&xQI>8YTQrd#3p|h*xDarlfM9*;vcUn=;&CE z*mQW7nYB^GCg=C*rcZ40!IbNGkJ#j6fU7m#CKCT%{5=)8{zbvulflxK`!Uq~Ov)Is zxwC|F4JWb5R{+tS2CRq)Y&e65t|P8STdcvsq=HuAvT?@ zz}4y(_h71dN_2=#=NZa>A#!4qKM$OGS;EQh&ug9*9b(hrcju<_7Im~95u46?)cJ$B zQ_%xD8ct%}a-6uA8uA%%Hai7@a8z}#k$catPGry`|6MuQut@%Z4 zIKC!exrcu0PvR!e?5f@+_z>Xw*99L2Y<>}&-Hg*2MjdsZ*mSt( zermV4Gle=DHe%D^*;_R`B)-HZUkF^!g9>rAQ|H&BLu@+Sqd)bA=q#g-wtK{;b3S$6 z6rDBH(L5qH9q!$4I_sPcvFY68Q*D*G+$+@S$*?k7M`Yj3P zv&3%;-bwt9V4lNO{TIQn0@waW5u2ObXQ-dbiB0|%aOz#re}{JODPq&%9z^|APHb}S zMO4c}Dsd5;oO=@WQ#rB8xi?Ymy`oQSa_&*oPvyiW=Uzp%_lZ8S$!n>va$=JYp#J@$ zPi%7TVbo9M#3oMxSN~P?GsJrY4+Bp9x8M=LwGR}r+2y`b{ZvkD@;vn)6n$cokEg!M ziA_F<`ac$ZVv|pyzRHPBK8^b9Byka&d^+`2PHggaU@P0iCg;9l)$fTrtEuy!_`^kP zI+s!BZ=!QGb)FX;V$->S^52S_*yI~1*Lp{6^1Fbm+417y(82mFV$dSZvCDn-tb7ui&db!P z6rEkf8W)~jW@$of`W5(o-Q>h3=Q#rPRpJi!%rn1;O{W$()kAcSB$bb4a% z02_Z2o1A+Tr4AJLxgU{@KZ#9;`w*E9_aL(JLu@+Sizs!FxRardhLhNI#sODXi_S#g zdLD|5i~Dw3+=)$}`xjZEUK=2ac zPYON0An2KTvco2d+L+FwfqqK1%R)z-E`&?A}88 z>*6M{$v0E3^U}m7=ib#RJpkiT>g*P~#HRBkaP_Ce-=~Ni=2viB11y%I^?4 zvB|k_cS^%w1#ICbHXWYLXmPJ0K3e>$rT!Lili2imc4NJUZ4hIwkts ziR%TwMtu&zaS@yT9?JDy2C>O|;pJ-UIaxLz zNNhSIDA)NwVv~=fT;~IcO+Jj!#zUFjzR)UQ&h|T>P;8a%Z9!4D2Qxh)8YPtmbS#EQ%#-EiaUo;N5e^MI)i|# zM~hAhxc+m3kELAGD&UG%8Skh>e$?Z)47XstzX1u_kQ5&v10d8>gc-(V$*q=a&3!+IZHtIazKe2g zi-=AB9_88=5u3bcpJH1?Z1Mwvtt}!p`C-7;77?4A=fR}LNnA42(Y~A5bVfNjvB^)R zT+^S}L-Z)<4*o0u*H`+8%i7YL~}YXP)FZ`5Sz|Bl)oi)huGviv&rfdvB~>VuH#Z- zlMkg_$DG6_=eb1YFR{swclyL8pH8{XaS@w*Hsy~?IEhW(PPx9jBsTfCDA%zKvB}p^ zu5($$Cclz$oy#IN`E`_Q+d^#eTPfE$E@G4430%7oFF$b+n|w2HKa~@k{9a(2<03Zs zR?2m*iP+>jot)U@+}|{Hyp)YYfUQj?Hk~7!P91f$ts^#_9B{R|GlDwWCKH=Zo^oxI ziA_EcIQ4l61NTd{bR#w$?vrXd+#}W6WMb3dUa6^x;?6?qXgG;YXE|{77et5WE7eaD zd=d4vJ`$V$mB6Vliq19E(K1GCI`=p^vB`PJ3J%K$~>{@9|2tbCDEy) zj;?tiHk~2BsVSn?`fvZmxyUVDfb(z?7E~Z@5jo9StDA&44Y;vAkWOb9+SIVw0atxwePICO-|h zewu`V=NZ{MbYjz4NS&{UPP@aMz_xyd*z}iDj&(16k!8e`6ECA&*S!#%{&HYjKSONt zm6WSH#OBULl&d?$rhh50t)C$_`PGzHOTH7E{8lF?Hu;^vsgotXcM*S8@ZApI16-~0 z?Z7p|#eHIP=XvT(7rQT0N5epDI=g^VUlX0TsH5%>n@%+n&)N!NllKKq>4y6Ksbl5G z>9E!$e7~_9hL&;BJZ(DOm0d%TXv&&M}$5Y8xpjPb?tg+hF%0n@#q`0=_E?inVh8Gp_AA+Bw>h3f_A zF|F*P4lmv<4&=SD5WV_3Nm~wg877u9_BNJwfQkN_@&0l!kzD2;9^Fdxjz>JsG$q_k zuLECqVOf7eOT(gL2H+aXKfMIY|FB#xNU^!;h!Fvu*6aT?O&Xs}noD%^&joks)t5Y7h{u$4qYI%b*c)6~zx}+)=WSg*X!VX&b*n0_{+Ii@ zePuk-qw49prv_~wctkRB!Gx9`Zzm)~49A9*nN^vU4TZFz%L5O5y%6?p6MmN5*tGVn zH@o#YtH+*SUDDQb(5ef@uXh?nx4d5!+rG1(KGA3IZV1Ui#gOctFuX_N^^Hy6Jp8j4 z%&h#&C69%$d}sXVZ5IDxNX|ZUSz`3oO?W3c`tfDR|GK9}Z}a)MVb$?H&DJI~Pit3K zB`U{H>RC)-y2bQ4`lR37mppjT)=j7!b&n50dFr01+BWgg$y=sAWG)nK9sID#4t`?h zIO^^mvwd9t^BX^3H?eZY;iy!nqsA2Vhpe3Y8?(`^>8J|BLoS&6v!d393ryZ^{81I# zR!uCFH?LE~Lsr)zPtA_qyA7$VH{8|qiyr4rn7k@EVe9I;)fMZCF8*NCXCFK6;JSyZ zwiHYKQ4bW|PCr(}AAh2V&E=wGI8vC(vzyaM88^_d*J1!|{eDp~xmbX4E zJ`Z|u;{8S6=RRC?^XtyXlYVc0c56Dcka8PVe)WkPQ1;F2J55Er361O8RXvdYeJW#cM7 z&lvWpT>j3(_Z@xGo14CT((gAht}J!Ku_T2huTRwh6>BSZRrjf^EQHF+%Gqa*3MIK0 zO7f^sk_T-cz3sD)HLU!X$2Ju5*q7(7rtXPi>F#Peq=X$=!g63gDwHl?6N>F$u~r>@ z(l72ShD&N#&q57jxYAEFti1k-zdu}S-+Z&1rP$x&dm^EI3C1S!Y5Fm97AsPg zF3j6ok12Fn>{jNZk64J`0=+N7{Y?DY^sdVCMSDVY*_ZO7p6_#m(Em*sJNDQCgIn4c zb#!ztS~S0Y@`M2hQ++zqkZBm&j6D>wgWJ#%M-LD|;<%$=ISk4Y$uMrJu54eD&CJcT zrJEOI+J-i_;Lp3S*m}_302Sy#*>@MO@*Iy-?%KD$#hE=ah9KdhEQyl<=$|(y?-?}s zC+?xk)=N0Yd~ylr*u?WXqiR3q#UYE>FUO1NCiAymoIbf(>}kaluOD(%=ulVH!sI8iu5mz zIKRR4?#2A-$o!W5p$8yr6!0ht2+8txWfZ_fDgyIr{?yyGK2DdKd`>;M0qpBRNV<|jwy(<6RL#7~R( zoHD#EGLQK=k$KFQMdm9bzPb!QKQfOwzoqv1d370nU1VO4-x}%1{I zd`n~=^X-xOj)=cfhQAe=zf*?udvG8A?h&tw_<<4U_u<}tUBojHAMN;Aut8DoZrQp`Dy_2-slr8|Ghc$@5A!V&Of>r^Lrw5exEOwr1zGH zZ;SYoW%!QB{Mj=6#mM~SGJIEL{$3egd_b4@_3mC8-@XxVh&cBG@aYrt@sWAVxle$% zKcx&mF)}~344)mDw@3V(h;z>XAD)$E`0B`@mzCjHN9NZ={JJvyhRFQJh(GiZ z^T#9iK5D)#azExfBJ=0V@STx)%wLSmUyk^D5$`RZ6e5eIzSKtCpIOiLCFZF}e?%ER zIWnIT@slHd%6{@$k^V=`xxa&4l3p?Aeh%JzX&HV_WFGTxMdr&Rer3dOEW>Y!%KT@nMplX#>41Kf%6X-eQMU*7(m;Ki#l@$Vqj z1wm!vUf`7lo=iLle52!Afc^a7R&YOm_fv2`U-@(JlzV=quAh(i4Y+?E+X?QU-(CXu z&jYW5`|s4zroW@J^@S4(`X3XM_9nTn_HXljni^@#MweK0H@|`~Kz{@bRwwyaC*gmwo{5 z$3wS+`|-{ua6g{84}6acKbOq-@ybuZ{dnb<;C{UFpWuFc@)Gzs7rsA%`|-rv;Ip0i z-@yI&p$DF&Ryy;8zVG}BZ=V{$ef#uTaNqtkf&23GMRFG& z&K>yv;A`N!op}qm@88Y<@9o0V0bc9)H^6;=)&=hSuM5F_`Ckj}=cm?z`}vpa!Rzpo zE19?j*w6R;E4Xhj_-xH*1JnNz_)^FDtUb!{pMXztoX^q=9sgBi|9Nm9-j~2{a{8}< z-{tt5;9DHu1McS!yP>T5`MzF-vdb8te*pLK=?m`L+an_LBf)oS>}mhg;QoCGpRM0< z<|Dz`=E;=|&%Q&A!v1)e`}bRu!2SCyKHK{DRVRb<*<7w`Cmr7c?&n{g0Qd7RPl3PT^nVSGr5^?Vb^`nPl0SeS=FHjF)j9q)F!NNd zWa2&GQI1!lF8lU|ZK1FKeIniu+^1(9_!{Tl(cr#+9SZLIU#{-(&+ntbefy6^2#GcL zS$Mw)?EBY~zs8>szxg(}e_p%-+_%U7 z1n&Fi?}I<%+Pi-N_v!g>;J&~A5%_ec|1h|3KWNvFe|`==*_97I%lP{LTkxT-zVcaw zdwN>@{{+6o@wdR)hnx9-gZFp5JHqDQ2Yw9vG-qA|?%U6ggRgVu1Hj*N{8QkVm?`+z z0KUhWH-h{3Tcf~lapq&e?{<75_@j=08GNVX#k8iEXm4O%ZQirJ0l(7mGr(_joX-|l zJAO9!I>(oTU*q_B;C{Wpx53+-`C9Omj;{lM$nopJ{rhS@JNWkOU%^jv>Bqj@kAJ!C zke_dU2;9%ta{JdRS0A>6v(J+&nfMj>qmDmMbCd})e;M4@kJrE_Idg9Lu@V15#OFku`+C{M_;DXDyU4k>mR;oCxM)`|^4f@xiTHwuUlH*iNBr%G zA6#6l6YAlRh>rkgd1EkZP(QgZ58J>?mA6Iu7lU(rYWg>WvraEj{rgp)<_BYi^3TDC z0v{PT3Wr-5#tq0|2QU<^25=511EI&$;=FYR3pWaJ zW4LgW6U_9`$Z+xzj$LO&aO1f&aE12tI9QzhBt~LQPnZh_1K}X6!l900Uk+%eTzoDb z_9%X*^}OJ8n&F0?p5InH@{%!xJRHD-fRO5Ov5*#y`BK;P7_q{!Um-gx#r3IWdC*Fo5(4fL( zD<0M=(bnU~^t3fSWG$Q#RC*vQ4&#DtoXiy**7)f8iFQ`6qgrzCmSO&xyJxp(;gejZ|g@P(k4d+RLX?X~-fK5Gma<79{&1E}!G#nR2 zeN7TOXw?p6&5AFDW9IZ&Iyn}MB}L+!*5mFPh3bKip(^7nI|-W>HZ8$=j-9%1hZ0H* z?MOrkQz+6XaAMXdWlN8r)6?!WRCYe5WWSztC)TVYgxs;jk<_&$5L=pmqNjEx-}Jyn zJ~fb;4;6JZWN4TMG_;_&^o*8pZQy=vR<5^Gu-1E z*881)CE*Qc6EQ#~j_vzIDVG*)i|5bZ>zFNZk>7tUTF8Tl_7%SmIK)d+C!C@Zr<_EZ zZiWt(>$OV)9H;F2XzhLCS8TDRbLqZL-ig&hG)h9ScZP(+y5=s#X-#t%%xEt?okx;^ z@hP67G_6 zA66C*0pWEa_^}yMreMa(?5b3Ba2;(H2Ai>y1q1J%jUZcQ7Q8UgqBe|m`G{7lV}D}% z=9FvY`>CARD z$U{5VU03s^1Fm-bYK|6tV$`8t^~Gt5u48Wz%`#1yTm5vd#~!* zV)t(9q(q0oq<3E~)x-33Cp&nq$NrV$&bz>Ki-Ohg9>C-o$or|B z*yN*tYbd})Y;w-A)z6bK@EwTN9b(ft1=z|MvB~EETiqcxc{}A<{NW-tIp?2Ke6faW z8FjR56Ppg_q*L=n=X_xEm)LZ;j?v0CvB__sJcmDA#3tuFk@eBqpTYJsHx@zg(7^odQM?@?0=waifGGoo{% z(>cZIoJO5dqC;%%@O^7)k+>7ircoV#Hccn(@?{<_Vzc`#%14Ww*yO8$tqc>JoOAb9 zmWWNx_arr+6L*MB&Ud+{Pi*pa)Ymj5HaXV@_U{>jnIJa#M&SB3i6iI#Q)dd^0&HnZ zZ2H@%qZ8HJsiSF2Y&tuf&U4h!bR#yM7pc=Be!WZ`Ef2(|^9JQw=7~-I9&k!0)4QV+ ztr;WfLu@+LlpiN@Vw3Zoa_uSNFR{t{1NT!ovB~*f#pJ{$9|T;J7x#%xo}qlK$carp zit=$HCpP&s%K7pa7qQ9t?%L9X*yQsl*EAtEc{{L`D`Jx`0k(W6HaXYIr4~y%ECa3? zFJT}yohyOs^(DnRhp%<`M&Md~5kYKrZ=rmKxKC{ITY>wjKC#K~rd;)jO@0q>%>)S> zvB@8z{F_pqiA}x}ICYlz`=Z0IP+$8mV$*+%a_zr}P0sf%H50{OVw3Ydi^+*i&i5-O zCpP&|Cnq*J-?dx+NNjSxXR-c~*yQ7Zt$!poIp0~;>x&=Gzgn6Qo6b4FDJ}@X#Whui zS5RNmgxK^ird-p6*yPtxu4zJS^4px8*yMaCVsRuk`DS2?BeBW(j>O_fZ1QJ->(7z! zk3bxfUk*`8j3eeGvR=to1t1#}$;Varq4!tezACn@N{8&g@)2*fGJxU5uS$c=y)bql z&UQ&DM4CasxQ$VR>fylHbVSyWiCJ%$4Z@G^p_vSqZaJ<@%t%uBu}dhYmxd1A%izb0 z+lrqlF#Lz~25Q2OdKTW5&^s|`$RG81jls{yV@h83Sz$bw1~g+lxF3rTAJ6hJH(*r2 zCj)zbsi$2X)e3qiC>}#0t~t(Mz8*1uX8_YZD_YOPJ;M+OGn&uC4{6s%8Lw)*QyL^N z{8NV)@0KRyBcQkINUR?K=A#|`t;UaGu)F|F3`PdMsP9e4&Ao$xz20)fV;L3nGCe+c z;vn(Ad*7B3!-o$G+qMiSzi&(50TLdTRX&*>h*D_#luUeb!^(!jt_0j?;QH20J$fdF ztQ`IL@jaJe4~Ij06nFjD*M0|nUx6t-xtmLJ!nxyZrvcf~pyI3C-y?Z&-Q(QNBeSw< z+n}u*E-3oj?JMKBTgm}%V-Js+<75|)O4!)2vbYz-z~wi(ogum&IV90%@tfUdj$8Y7 zk3C=i_Ij9d|BtP!Ca>ZiAeDt3K#IF4$j&UKG3JgBjBziG@hHUj_f;PpV~bl?(+BPF z@WE+eq59x7!M-m0ktR$7mtN<3*7Zm(fxTSDJ@CE9F4;Y1{kd;o-yNp&1He zB)P==Fr(^!F-&6KKQbQ>@w$kk+0#qx7u(By^TDRB{ZwvU(8pVvBv-6h+n>+{OU-5 zUBquH!*7YqH|{6DE7Fho{gHV&{%EAXwG4kMGLQK)k@>R`-x={&9OrnKyeEEEKD;^0 zM>)P5I&vk$_?Vn|Zti(=y0^c4k2sEhDQ_`{ST8Z}8F9Zxj{YAQncF<1xqnDxeptl& zmf^LL`4JHx5b?ng9~N=W-O45Ln_7lXi_CS(7*2@&nCrAg!93>rI9@Pc?%Y2OQgUB@ zygAdm9Ot~VT*=TDk^A!F&FS9$@++PDv>$W7W|8JMMEbYvC%-k)zb)dM%kX<5^DXoDL|mugp(5r(BJ-H* z>xF`T%!ftxbvnPGuhZ!TJ|@zSxlU;o^mQ7sz>jzKIaVj1h`Xh~H)nc%SU%DDNB3er zDKeiLalTiQOVaz4h@V=9&x_1sK0h*FR)&8oGGAVXuZYaol;Iag=9fnNvJc=lBBA_v z?-p?1p8gBCFCQDhefil0?#tgj;66MLfcx-o0r&C$33%~JCVmd$!^^Rkug|{&_vMRY zslhIOuY>#g@=m1xH*oKM71}OeKK=oGj&tu2aG$^Z!2S5X4&0CDjt2MR^P%8OGr5w9 z;o$chMSCzhvfmW(N#K5bcS6LcgBP!4g46Fld~?7LD<~wx_g2Fk=h(zQPn`ok&6#to zF~{-M;C{UDZE&AImxKHM{(InC@RKVU%zXdIZw`I`c00K5pEiMe_xUc|kAEHp_u+Xw z;y(xX>9-@Y|6A~$_*wW~1|IAmS|n^@FdmR^n&wPXzY$@yp=8zMc&3+mB}OdH9+A z*}%U3E&%uCtrPqPQ%CvcH;TS}VcYh+Grs`*I>+hvbBL_ z+?Urk!0&S9My z^t0eq&b?#7S*OhWIB?b><9uh&I%E7x;C?(g4cyn)uY>#g$Zr(c=9qncqqxlRcJRKA z^BcvbjxPtdi}UZ_jrg4r=R0n@sLyZy>>}^k-I&bh9~trEB0eMH-%#EY&K!)L2!aS@t4oj26BI&Tk-ac3G-z{+EF_!Gh0%Tib&ZX1wa{hfRF5heAxUP5B zmCLe@IjqCRLidtY{b5x$gw(_$eX*eH_aT}VzU#p1>wqOR(Sm+maxZr5BLUIZ1>j+k zbm_W&xEtadExXqb5NrXsEYQ|9;?cr!SsZRl@+I7*E3S1({xH$BmHDC>z8=AsAd)h= z2)}gswtb)>QPDNy_9cZxTE9R@OE@*_(vpL^qF$Hq+qVXiO1j)#Jr7AM9|ee239zkZ zmjLU6cl{DU*S72D3HtejE=kX6+KcP@A%iW<*UXX?`MQ){SI_H5AiCT>e3euDl%u#( z9rdEwSFFNHPc9~vm9PBjD11@m*Au`0I@6*>*3T06oTYfZw}r!1cVW`s1d2cq4wclZs!H6uk%Y;v}3HOGpa*yNL)oY>^2QT`dx zCpP(N%GF^Q#3tWKxu_?IP0l{v$PHggtPEKs{=}t~;^7)i&S`nL^eQM2k1RNK!$=6Y?;U_jZ z`~2!BM4$b=r4_O1u%9Qe8 zkNotY0SFRfUWFg89Dc=TXU_k~6|ZR-(I0CqFs{O~mSCT8?2X?bHnVh%vgOHvtW z56mS%Uc6ge$vJlB zxsmjX%_jY=#xGuja{1wj#Pt?+LCf-2aU*NMo@3S z-?0Xz{}B=%mMyM9`3J;?XL9fyjup!tLc(@o(OlQ3dL+KN-yqx2g^@>7j|&FKL3_4OKT|{6iP10_ z4U?`%h9`b>;i?{9M)$gXzXw)*99XF_fXkJweJWRt_yJs6)g!y=<_fOLsoGZe_@J#^ znZpL^rR9kP?J^u2R`&VDR}!BntPdKpvUpZWaQ~(riLRR_6i!mva6#Rw;;No~X$)C? z+v>@ywiZr!X_;DC6?{WTi*65D8SIA8S5{i6ZYbC?8)jm6t{z%@_)$m~SwmD+$yG$A zU0fS8WM$JP^WnIItG0ahg38Le!WlzBAF&@2#opX8-!{0@Y+^Ihv2%Aep{#e^RLRnn z==w@kVt9|luEm$UzU0kIHZ3{0+uGHKedVM}*1k01#DUlSJ~6QREz}8QMd5n>a{}Mt z9l!hW8*p6We|fEogdtgISKf~!itfT(1{j+q{*q`pt-TQ?aj)2H3GXF_!3OpBhqGOZWhz>VI9tQ)PIuf06J?yGl#KM@07XW%&5W z{P>7ZjQELV_{ov^>@s{_WWKBnUmlrXR)$|0ncoue4IeSTEpl&T#P5pu-4TDV4Brx& zKU0Q38=1dWhWoiY*1vZn{XG%yS*X-f{(61H+^;>M)Amef<^8b8znBk*%}Q#AMQruN0Jj_h9-@f#w3Q^aqN z_=6FDJmSwr{Dp|W81YyCALDOC;oTE)zMt~>RTXi*pYrC1M7-}u%=<^~@%@+g-}A%G zDBLR(9E%m7_bU^hEHSSN&*Vk(s>G*ZUL2oRg=c%;K6C8l`vZ=>eEs8jSiU{TgBP!4 zSYzYEdjbr7`I!#x&1Zo7`a37mUj**!#}aT~-uWrs{Vso3g8TA*A-FH^99#MF{#|h2 zzFr6J!*eq@=OpDyCb+g_qvLmgb3Rh8WMVVGcE=w8f8Oy&!QXJ4(}vw$_@4&%Yqhxl z^-yR20=RE){|N5eTaI;nd;1sgbDVv2*$LmD^#J$r=h(#ew}(dh{lWcsi2GN2{UP9f z{F#pQId<^RC!EUk`s1mOFw2!pd@<5L5xjUM6JLw;xsJi-AGZ^*k2FZ?S%JPOCc?8X*ZUy;>PlI*;u~a<10D7 zhzoD^!VBJgy~3rsZW@O-vb0y&xlLaj+Fn@lich!1vNvyhV+VWT#i+dqmbZVpeVM${ zvt7*eJ)^vQEZxP*w(}C(_VQ7zOSnq5h%0@4T>6T*^xZHRgRa}TmA=yj*)oz3!a+cthpU6GumerEMu3%`HN?SJ2|n*Z*+2Ele3MqbRahQMqo<^Vw2ws++Wj& z*yK++IkCxKadKjlvp+TWiA~-eZJxPLY;yLWmj1*huK})R0CDko-tvOjbod;fx zr%;DOL1O9>+JH#f>Q2vI)lN=XkZ|O>u|VgT$AK-6h)w<^u;mf4$)5r?cZf~?EajR<#3p|g*wT~O zfBiv+Y^u@F($R@AnqwFZ z$vzw0#1h+iCK}o?x>(XMqqDPp?##uVtsPRN{;vN4&_Z=DS%*-3?k&C(kJllbav1h| z#~aIDYM*TjlWCB0L_J(n4JfByyi)k}#LtZ1PcID}+Nr^h*U7L@EinAk4gUC&&g*e+ zD$TZ_$MEs@Mf|+KozNqn??CBa2K!{jvM?-cxC)P`HQxOWuOz%J_W;vL1O za6JyaOAnHD4KG1Te;KcMeZeVx@C}%=Xzm>hT{uy=ZvBK`J1zdv5F^{pxeHJ4utf&t z))!=kW=F^ZgYtV^yo$tRcyb{WgRw@VS7PLuRnJY^Uia*v9TT6K{PfhPrayV=wwaI5 z-nwB;#r+izRyt?JWj)rzZHdQ}b?;@*T$ENFIp z<@1R?hvyP?S5@`+?j?QR9-i26VapLc1|2u=g064Y_BnK1;*Pf`BJIP%=jKh{)qvm4hyJkmWm+`;mhx*IcmXXIQ;(@P+^N zyg6RU&YFX-f*+7$ImV~>5_a8hW}TWJp0VR8@pEwya~VC zx+ex+*S*5xQhamYHQ^MvF)6tH?>{|vQss5af4uxjldkH0Lyrf0uYI;RT>E7AmcQ+( z_>PNnS5sx8+jy*!7|(b$CI(jAnOI-(P-0-Wr*Njs3yFaPx+kug^6+1mKY9P--`vzS z;Z|r}vzJdI{V07xOcR4HYFTpt-rRp4@&0b&+@IXAa_0r-{)l|gg>U}V(xK~9O`n{G zvSQrsC__Ph%5gvV>A>qwPY$eG6&8cNv>dAe-q+5<1D;z&*NUYg*|dAg%oDetnE&d= zuhvb!Y2IetZ!Ix)rRwuO+WZC*Dnlu-x~7pA*>bbgSrKOm*9clGw#ny_)E4B^9fpyp^MrX(tPkfl726D#KA)WE(yJ(6735tcOQ88>xtu*n~WvR`|DD3&7r^P zHsQBuF=mLvnq%PplYNNj|+|eYnr77+6K# ztK0e>yw`Rc*pv4m-PYsY?U9Myx_&vYTi2F(-3A`;3i$MH*LMx{OJs#}wKv(PE`uy^|#K7+FCf0X{3pcN+px!Ic+p!P5 z^$5+t9(BjV zqVL%6^f>cx^y}}{E&5VS`_eoq*4~~yO~>wN0}iQMy?s^Bo-3{@mbS(_4j%X0J1{re z+A-&tS+hHjIcjK*a}mZ9|4WOHY>W}Qb@cH6+q_CV*8hF`-?yM6<}v5Ivs_|cXH?_! zKh1|k{xw9rIF^*~aqdd4ee=m?tl^LOiII8CPmRoDJ|{AtAMwtJ^Zk}w65ex+YWS9w z;mafQa(qRkzcS*hBfci$7f1Zkh+h`*%OieW8Gd7AeoMqRMEtgh-(H5_6Pe#1@rNS5 zL;q6b1_@s!R7V)++d}U-F^NS*Lo=xGyb9Kb8 z`CsNYMgGP7w#a;c`9qQYm~V;9`98#_Pt3PR<}rURGJiGVd&=+%%yfGHV}3|v9`pW@ z`4JHx9P!luV|-K;-k6V$%>CKR?B8NOG1A{(J~^_#zkGINKjw2H^LY{H`5?Z$#C&CB zzB=OPNBq(<{OZX3mWcCA5FehH^K1}re*b>*ha&xL`^mRQ`Z0ehGJm=ZeU6KCoh`$l>J!SZNk$LzyKNJY*uPg9&#g~t&{p39({g_ur z<~#$&`&W*qBK?>*MCLIc9hsNolOz495uYCMQ$Hl19ob(J@zrJcn#la(|6zVvUXb**F?N;#QT@w10wUm`^i(0{;_5FsK`9OpL|NBUyh#`>CY^~XGP}o z_LDD-^jDPO7e(fmM*Q**$*+v;$Na9yJmz;t=9~AE-xKMVFOBlDQQ5ShQY zpZw)WfA@#v??(1}VeOr7Pmd_WGm&{Yo{#iB=Nh%*RT;kdsV)dA6IimA@beRggZuf7 z{@{N81zXTkma-3V|$f5~qF{rqem+|Rd80H5jRUnYV3 z`LrqEx8o;QGVCdIiqoGC13&-M4DRQ%W`X7@7@SL$NBdIa9_UpZqv7~ zSkjR2?fc!}zP(|e~eSPP*iGKX~Yw+TgO#BYSmuJ3P z^v~mej?CW$FL|EA1Fe6a>Iv?jhYkYw&o_sG`}F+;xKID1!2R<@J-AQrMsPp=;}&#& zyvKd5egDgE5q#iX$ANF-2!l*AB(|#f5UGNeS5zO+~?P~!F_woZw-C> z`cL4~T=`*LpY8ZRgZt;_JHY+(@qd6{?eu>Pex2h#0r$_x+^70>XZ~w&pP#=2_xbln zaQ{5@XK?@g@>lS_Zv52^ZGnG&;l9*ZfTdS5(Fc6I zPXhb-=)vGio%u1qe*Sq_!Hg~>6Q2e5;U5R?*Qa~|+`rGC3hv*(e>LI^tAD?KI=Jtj z7lQl#b}_i`pO=CA_eot5=lRa;^W{n=E(Q1Nqj;Y4cr!-)m=}{BzXALd$8P~=pDR}~ z!MW^fjl%xFf#2i!J>Y)5z>mQ@QRn4KCboj#?)cBZYmw(>{tS4#`@e$w{=FM?N4fO)7@Trcs1N-sDIp8~; ze=EQzyY#yN{Cvm11HR1h?}GdB&-LJb{PF{EKYsZkINKNtFXxv0`1?L^|NdzU_+aPX z6X5+Fe+qnv2Iv3tbq?Lak+Z+6RXWplf zmW*LC@o{kWfpR4i1Hk?B&8NWq^H2l$7E_1)MsWXp#Iot1uf~G==c|d}{(11r;C{W| z$>5V+c$&fe^VDo`-~TKCzs|MKo#6g?@*Cj(d2%g&$|QsI;a0z z@XK9#@Y%_)C;Ah(@BiNd_x=BWgZuuzJH~GQ`TJwwPdfK&!2R>}$H9+v=`jG@uZR5< zIG-8iN+ue>efeqx_vM3QM<4&O;66MPY2StC%Mm{r+=sUr+?R*h;6D5dzB-1kS=Ft?%@qk0`A8bv%r1-Hb3H>;JnyobFZ2ItDLfG{Qe{2 zKaTjXBK~f~|G`bb(Y^YJkB|7Ah@TtrYa;$baE9IX{&^0Z{okeVi}5+Amy8b&)A)@7 zw~OI9A>wC89DBM94SVbO-E_FqOO}UDWVi=S*hq&P!EjrfaLh(HGb3yp6VB2Io7rTj z!OdgBjx%9boNS=M7UbcGiYy(=g+IC<4#voFOPP^W3rB#2Q%J&D7vY4Aa3V${Rl@NZ z;Y5vaLP%&yVD$JozTMvW9lHzHS zKGTr=x_{76J?A9&PPy*e6MQGvJ&5dB6g~7LZ6~7WUPfu%%*cF8XJyBqv>xA*4#fcO zg^c4}-PHp}(s~+6I;Yzk>2W6Mkp9ruGiB1lbu%PAyQKAWob+%eI`s8Wm-KL^ z5;@~lx{XnM4$KHik`a<3BgEneNskc{+>!LXbo--ell-AQU}7N@9x$<|q1Hg#nKbmT zboZouKEyYl4`nppB)5Dhr(m=IGX^l9502qR|MK||YTP8$l86!?Nf3#Y#tAl%B%0D< z5~|&_NqU%#=Bj3z=7pX&qleIh%7^oOB!Z2S-FDuL_#A2*4iOR`G$-{an~@@v+JL|e z)$(GY(z9~Xp;9ydr1+-wjG(lhdXv_(aMGFyX-)pLZbp^1EwSu~Bi$4$9cm2|K~upF z?6I?bY_~1jU`sc$N^3f$bw{tX9@mrB#7S%Fq&0ccnm%bwptPn?T2D+$YZ|5XP@c3V zPg=`QXgm(p(VCcRqK=R>7$L%u zl6j#mgNv%EV+8 zo2+g#QBa%1EkBY$MrR>6t=pm5fC`;P6&DM33!3?m`1vNe;*qsF{;Ce4~Q^9?7Q+5|u(xKw9 z`%-rb-InTwY=wED8R*ZxnpbrsT-u}{}jV}`ih=3Ld}i47Bt zF%I(U2B>eCRagCWjs3~tdC@svS3Lu#cb9YO@+Ols2Ij$`uFCiDB35L*%)Vs068w6w zW5~;*9{@hs>nV$VFytaG5D7JM>x%A%hOIpIHw zYJ%MFFZhF7j!mK0-wj#zMOnh~+pWYq_=9@|n||zYgQF_pKdkzI`uCllZ83#jUj$j= zq%3jr`=A5^!3~4lkBiH~@jbiHH}0^FCh=FNKZiE{BQ3r=C)mjc$95?>Uz8>Oi>db$ zBT*JT+wsMovgm&TIpG@-_%1Fsl*MKh_1|`ROIh@6%NKjfqTfV)FK16#^xGl#+v(E( z5oLdjpDBCFVxNa7`hDc=S#)Gyl*OhG!#7SB7?4wM4>W=pr%AYxTGh{h-%3}WlWVsJe7X7P`B~K`e z{tepudk$sMzel~l=TH`XfHvg>JFnr`ha@(X#b#f~ax9cZ&-Utm{-Z>;wM$saVlx4< z0$eP(P2m|9A&X#JAM%t)`g=idX5K>G*A}(a_SFt_LN0` zx3Z@!`bQua`o_==wDDmniw(!7Cph6T9Q%zD{^Lvb5hY@{u;4zRoa1En1<7?yS>j=z zn53Dq=sA`^>?w=Bn0j86aFj*QzOqEF+ZX#yBu>g=!~PS|Qx-kP705AC7Cpxoh&^S| zv)`#O&+Uu-01}q6*sw1u5qCE1cS__tc`W4uC$s%7(ZR_VLzd&EEb%l^@AIFs=-HN+ z=;*?-oi5SI$?T&^?Bis%$0a&D`5nj-KV^xBV;tldDT|(C8^oTn=sCtgu2agQFN7@D zBW2Ndhb-44WzlnNgzT5H=m$~Hn=2e;(X)NKpFh8)l)vSUYtQEp^iv4dH`FEjqxQZR zCJgL_wDL+o_JwW`{>zX?aXzJioiFf>@*ube?U-!JWO!T_?amiCN5#cB-BpKk3z=bE zZecvkZtP^fz!U?+T?o5_oEZLdzl^igZ&`<2>h_mT5Lkcw)8#%*h>1i zm1C#(+pw!eBG|OLKO*3M3-Ke%F+dDXI}Uvps(n=Av-A61g}L_5U;yvLuD-6erYc=C z{p-%}mmD-;z}KDM4=;S-@$np^M-%DaFW}5(;jCcKlr-hunHS`5<{EZmGV8cS^ILUU zFS8wWd3I7cZMT=Y72=9V#wYTzH5EA#*_Sj;|AU0ctvEb0&t1vl>CZ=2t(n;XbB7(C zv$;8%cTL+wa>;_?=2Vl!E8Eq4jy+kk?#OX}c1 z?HrX|hAn9xo(a`F>}1S97nP5aru{R=e%sWRg$oP1cKUF?bmyJdH3Ghi7IgTdCwIHGjGQ zNBPOX{G9>MW_T6{cMnE&h%DTZ@thnv?zfL&{!xE_LgPeL*ua20$@iwsno<3|a8|Pm zX4RedJv6#}FInHfZ56dubCUg&Rgx~c3BUiLDb_O2jSsNP91!pKk^BG8-J`@n zYCk=Era6Z(BVKaP*AC(FXn!7G)Q#!liynK9JNr0fe|%m#=lt~?Z;a1!FK;d3EwfF> zITxR0)-kldd+t%=?Afm4T>H%L4z$1JO7a!^}GuUrrY8Z2Y-SgmW&u55oz=gAETetj8oV z|16I+_NQfGJ*J8Aon!1RPd5Hj3{O*xYJ5QEIgs20FEjoN3@LB+JA3ztBK$8gT|lV4e9h)e$@D9mAk)g{lll>O0=_4~vSus&ZE zVEsNZ3asBBehAj-;k$vZPfP^s`rTBpuCMVMX;$2iEmT#;xm<>%h9c_%v7_|8Kzhe!3N`&+i|= z`hLTqCa|J=U}idzr|o(zK;a!@;?B~ zaR8FvM}sd@JOsQzaRvB##r%Fl*B|&zwXQ!*0C!gQ6T$lVKMg!U`OgCD=Q-<=!<7G} zVEz1S0$+xoq@Ukd>-yg^u&&?T0M_*}+Un=~UEs*!n^>^EULOGW${56gUxL}j;an_O z2OcDd3;8LqzQ6LD>j}#LKf$_v>385d<vX z0oM1Qlff**65pv{{ror^te-d4;A5114Ol-<>cPAxNPHKA4^{T_!1{T#2(0gKSAzBR zb}jg6{3O0xAU~>j1!Vor;yqyf{J0;iujgNar>OL>u5*RrjbQ!!$ju$AAknidZlNtm`x7VBNku5`4F^KLyM>h;y;vG;o6;u9qtCg^D>A zXP8RQ46x3R2CyycfFO?4dxrVnuIyW0-ROwZxu>ToUW3`aDpwyJjG^tzya zR?YNuRqf>2Rg7eML-maMs`>^j>s^oNhmJmB_z%Vmz$)GxAYN6~p9AKj)#EvoJskHQ ze*F}FdJ=wj5`IJyei0IW4i$d9;l5zwVEFKpmhc0P@S}wA3l{gG8b2@yzX1rp8VSFn z3BPj+zXWLKqqJ~LJ=UIQs_-q3`!2(ON#j51kq;A`iT_H=f6x$qHh~Y4m?$jg9uCwm za~}xsA1k+0g>QabVDse$4<3H*yPiG%Rw(@30{iA6W8ePMitw8`e6J#32g&y=nXlJe zy4<&O2+eN>{37-IL;=JP;<&+w1=!$|FLwyx=N9<7#VP$KFaFyx^I3~a$}#Skk8vNE z_)o?BM@;^cmv+DP3cnv~`;iyUOqdj(VWI3!6_bxdh5zz3inEf>kX-J{$4D+|a=Km8 zwEv#Qe}EKzEP^AE z)991!KQ8p&IQg%L+I}$C_Uk+US(E=V$$#VJKQubVMXo=l8$ar3mwEn+Cjar0|A;F5 ztY!QtcOqS8xpetdx&sM|J&K$&kiz4OlDimiGW2H{yZH#ieYC+3O)i+;Fs+KCBH9FV z{^2JJyT;bemm3%m#sL>IXHBjSKVNA-*7U5IQ>IUC^ZmqbK1{Lkr5i59s&q5bwHLKX zrZt;Yn??%0(qsklFUf=dBAQxA7ESa5sMP#mc?B;N=ly6lO z$*vja_SM$PKdGwfr(fJQBfrA9O@_B;xBJX+)-1TpsHv)IVm(d@ zKF`53Gn0_Ii5FDO#+OGtiYoPmmgwh9teHN!J&&4d7J=&eaP(2MTM1V;apu%&KC!Vw z6)jJz`V@=LeRo~%a`LCwbL=H!$H!!Is%mFXLJ62wHKTrNChe+>WG=_>a?V(^O%0Mf zwP9Muv%M-tSk^KY%$P6(G8(l@j`*E5Gc4@wT#W8?A+>Ill-yb-PM#cQx5*NJq{z(4 zZH_QgK}t``Bq5`lRqMvS_FzLU9IO2@&Y9zV4)%J=qGz40=*RBmm9prIslUSMDT|)% z5(zd?a*JQlmClB;*s!f4@d^Imj=@j%OId7&LoQ-N92{lQkAYltwbN4;J>S1%zZ^?b zw9MI17MpXaZ*h9cqUXDqguRe9zOj(9*vzNi$4OcA%c$q1ig1)ge>3EwYn`65=V0}Bi~bGjZ*=yQMgJb;e*V0$?IiIj{@^~r zujnRcPg(5oT7Yk4Xn}G9x#(tRLs@J(E1N>va570a%3{NI1^iG#^)_%v0?kQ*j!END=-C$D4wh{YTXMGEZ6b{M1K|k+SI7#xCWAvgr4P zEa#E3=!+mHVs5`|<1Shm$zqd$zF&^hvmIOHK}u%ZUyq$(^22sO3Cniv9^0LsvgpgG z|H$bni+&j7gMB=dML&{y9}i{GkD=bjLs|6WAs5}{(o9+ObEv=D=_!kTKIFn&r@x*y zKaFIuVH%#!(hM z`x6o!oITqjmm2^`M@?(xxOfi4ckilb#nWC6mnu8C$pVc%?q^Q%?6IL z*t|wPJIUZEi=OSoMfW>BWzl~`y^n{o=-DpZ!GQ#aN+$gGmq@5{h^@)n7CN^A%v*Q0KPOM5?QO1$# z^fC={E+7W)^$LO?QR$t;$1x$=?hzcvC1QlF*o7|_^>uT;?l*5o4NkdF-g=$W>0c{G z4U75bEu)SFf6K&6ex|G256ddg^1jH$W6vMG_4uF_-z7y~)bx3IU&QxGi|-1ypFC;oma%20uRi@d_!4GO=If;D-$rstQ|#_|URmCC*w0&YgJ7t# z<5xf1Chhn#`qt>S>XwDg1>3sq{A_rKmgYMPBvkI!^5F8)=)0X*<-B1hci7ZCI`f6k zHIE(Qza@*lB#Wu9e!8r8-)-@$E&2K^xyyHNhde8L>^U^Oxj=n6w*R_dT@*v~CD1P_ zB*gRh4s3n+4H){IaHLXZE>bcwVOLjq!U@Oq>YJ{cRgbwrX4Ui?UD*rY{`5J#u%<`{n;@wZ%T z{Bg_n&h1a`sd7B-dZLN*FZI^D9Ghrzy6U5$@x$5*22@WaGmkD z++h5p=Zf3k#m3)qlkva8@Xdzr$-<8s|Fw#HLniZ_N%5VYk!v4Z^}Cm zhjT7Hmi;RnOq~B`V($5K!~QiaWACf;yXAf5;qBw=wugMEvA5jI_**VE{+8JW=y;I-6MuYYJZwy$M&r`v=Jf8{H z<$oerr8@p8SQwfH#~3)?t#`M&`kTf`gT zmqXUq^Ic$VzY475e*mn@?;~JcKA!;V^2K}4V0Av82bU^-2^_gt@JGPfj3O4i30XhC z-UCN@5DU{fUfF*FnR)D7EMRk6ogj{v*IJ2UzBcllI~NOz!20=d5LiDidV%%x;s~&Q zKCs<$twe|Y9R=nwI2Q|!2kY{30$7(P=C!`xodVY7=`^rDKUH9TeN6%D@-zdi%U=Un zUoRYMtIOAXur8k*Ya6*(z^0Q<8AU8$Q~L3W*)(0Mn9Y>ODQ2_QF^bvL!+W=Lv4G7A zyoQ7y2J7o_9avl;gx?w7Zn#U1SiASB!G<{&RUG51Hyn+tbK(Ep_&;g*PljXarHt_( zXqfBIh@-!ZBkKUUOHdF@@cxH|jF-gScWSj6m4jD2%mNS%yCH{!ku&Ua=Z`}d*wY?P zx9O&b=7@=K*hx5kB^-GYP6!!}acO5Hj2;Ps&U`m2zzvTn3rA02l*m^Nk8z_XWIzmu z2_OJBWo1lCS%n+I;YSYmu>yX`1^h7(A^dND*oOCWfxl|JhD^%qQYwRW{OA#{bdkyY zr*1&Qu0tH0u^TPplG%2YNh;IJCq0*Y+%LPEj@R0{Sr=YZh5ld6&{^dQi5s1TX(xBt zsf&Z1k*1%L{h1h`5O#Wo-LmL|l&(#7jqaw`lU}OVmz|)y%)c29D_{p`I}!dDM;q*B z5Qa-+b&Z_?G)%#i=_&=%8d8-u-LJe{*!>z5<5zSy{@^IHzDd^~zrvbO49c)6`e`JK z4WBEC8BRZ%Hm#8?HoW)so9Xmt)8=Q9EH>v-?;kppMbG!5!dcG#659NGB#X@w+W0j5 zgf^?34P~)eLH*C2p0em4r2bx~r!0Ct@A~;T*FsJ(qu@5-SM-Ze3}vxreIs$c({H8C z>PQwF)nZB_R{C91Av80p# z3vJVEd6tIfuw{BLHbV!!kSrWdknfW>2-~PW7_~=*ZAS1b^>#b(Fe}Xof_=aYpNC&( z{Q7v7$KGZ1R8BAf9rG@m-C)=-40aW|xd1*Z#c{uM%wEc+_|XmO>e_jkK0H-3={o_k zj&B8k=@2LJ4S_<(H%i6F;lT9c@s7fe@eRO_?jC^1Wcu+p4nG{LzmnYCuFNZOw4vix zj+LATn2UqpzIdDBev$RNv>P{l3+p0EX2M_M>jGJ+gUL9KsnCfNyM~EVrOCJ#-GK1l z{W;nF4<0lqR3?u}d6Vqz#$1n_`(fE)yKzV4czp5vx$$}Y?->4nEBx;g{{K(UGZZEZ zDU`g}9m_ScJAa0k^1~zE8yxM^uT}1Lj{m*GELYCC_*k~~CKpL`KE2)dG9PH->-iO| zx>aE1zRT72J)qU;`wm$9_XX?x`JS=oy{Z#_&S7my2-?0JtjouVU~NCf1@!;1;B;eu z4p^se3RoY14Os854y^P4La^T7Wng{&o4`7KOTfDPT?LL@EL;O8x>sSXN$<%x_#ML< zY$-F2@Vf?VxqsnzAv3+g9HztL6Gqj4K=>U()|F%04p|4Wp6*{w+722AvGxu>SBZBo z53UmLD);V1!1=n@0RN&8zKO^yfmE7t-$bPx747=!shp0jI;#HCYx)cfTjk98oSD9@ z7e;|*CUnnKnHh%9_-IrvHB;&^j&gGSwCS~9*|)t*xAr&hrVjgicpu|Aq2oO~x+bD$ z6|WWA$+PBU$lB45?g;$!bANYs3D_~r0Q~4^Co-9S{2hg#ey+|1_rXt`?3df9th#6E zy$Hx>Ij>um(?a}skC0=47=9ZTwb!|QQg5HD?BA`Vhj+5yhU)qT{b0@ZTumK)^s$4( zCv5iTYTkJ+J@Q=bgw!8g$C(=WQr8o@2C2n^H|6KA$?p^lOg|9}er8a> ze%U@RkKQ`wh4EW@7flQXZ%%iNcW+(1s_D2TWlbBFr1Lri>A4-cw{-6mTesl8KFsFgf_$l`T69_Ko^f^<0S3r`dQ!bI;Mu^RLr$Cbk^VF}7}Dy7I$)tKSp5 zHZz$v&Cc|q=2rYUCN`~2)1O^eUEKV|{-P;v-jeCREpDEd=}9eaUfiy{xw%iq{&ppA zQnJL|s&tLx=f%bhn^zgD{6$3+L)$qgBmMT1i<_liyLiH~3GCY*6-4>e<%O+k*2ph@ zb>!Gj*F^onr;J^PSt-{PV9wZZHp-FDjo#ep@gYxk+K?`Y7nUp@9z^rB-mYfdlytYv z$?ElyUgzXR>()&#Zf&X%stnbLyXiGP?G zO|ZN2^-XhxC2ZcX*s%Zj8u_uk6s4@(%@iExJfgeg2TM_oDn(#I?6I)%1q7w6~ zuaQH##7r8wC7c2G$g%IYDK&q6?AY@!31@)K#|*HS`1|3=mqu?L!aHG6b7lI?HAShW zbZ&mpt?`zf@ea5GGqb-&X^eEZCU@~~TmJsZuStKWTlY0`Sl{V*m)o@r>T5C`#JjC( zO8+=sl>1_J@Yl-pCvO$CF8-<7&(%tnylp(9;sEyqiSDqG-}(c0=hrsRr*D)n`kF6U zT(L140o1DIcD8o{eK%}h)^lv%u4X@${kAGye3+gex$Sc#8q1XZ3U8CU`^FDM?k1 zaOBvN)Lhl4j2*Y;EZ%k2t|=%AhCF^ruwcXOPp*7?)7sImj(KJL%M)HYd+U%V)1BhI zRxM61jQ4tYi9e%%eXG|`D@qo3YF@o`@KQ;SY;~TuHl=gohekds&zo=+_KeDyzPk=R zwC$9?Q36c z*P^95{z=Quo%^*HIx5xr3T$1X^B|H-cBfyk6?5^6jTjny_U;*%_FvHP1sN+ecN=E^icX*92aUgF zjyKWa_clLb;{60^o_nYzyCcf7Ve~^VgGXCtJ(&@9DZ~QIudp{k%XBIxx z`1dz_yy4-7#~MDzaE;*$4eNQdm=(*7zvYLF|HFnKF&vFIa@XHx<8S#n9>(4>zd_XT@f*Xh;*{|(HLT}h zV|kMCU{XKO^Ni77&nrykw}Z~P<5^<(R>P~aFuxVl@oh5vjA4E^sO?|P!mk-z^LGF#g|^dz$zLWMR≀le?79MW=EuU=s&(6Z< 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 literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..7024f4a17d8425c71b14425c99b702131c7fcd0f GIT binary patch literal 667916 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�Iq%x79;3G=xZrDW769{Z)Q3nzdNiHE=Gzx)h04xi;vDjYl$ z&#@Hda|oJ*-$44T@aoxE9)ua^=fZq`z^{Z0kX{TQ>&a&}Tr0dD=}p3nzYWu)CkEUh z%$R=_z5|?w4?WcD4Yvu;MEZm<>;FArKL4Ogn00$WnC*R8m~HukFypM5<4)^`NS_zx z@3vneqd$AX@!Rf1*TdhDpClZEbfz%2qXw(u8$dy`r-TWS!Ol(bJKVby|l-&qPYrX@z1soED#v97)Es z@;RP)X&1-yGXtN~$nY$Ohpf}(Z=f~KJneNgms{*bi}{LMJ)5bMQ$Sv;I? zWS!Qa=q=F6IxP>%FlHNcvQ8^X^mfQ(ofdyz&S~-fnsbDC?tU&Aak}9rM=oSQ^r7fI z!m2M3eJ^yf)+d*`#J^oUz3`B=E%%7t2b~<50l=_T^nPL0za#p7=wxlUEI=wz)A =h-ehh2J)*}!Cu{sh(YYRxRc{eJ0G+J*PSN9`leIqm zq9;QqYkdxio(i3;_4&Q%Y0$|U|9#OHKqsrtjVRm2b(E}nwCI`8$y%SYsYBzl!&AkR zk33nIy#>Z|kub0MWQu<|{A68*v&EB#^h#m+c^=4Vtw35J%x8Wx&pH>%IE{0QczB&D zDC|X?8u1syPma78ZN*S0o=1>=RXnBekRvl)&jZw<@fy;%#Z!(vIr0+M^MrVIA$>}i z&pUsHjCxkUPuBel$59VLC#(Lh=vC0kIe>HsNmZ@VaKBc#gtD*7i1wJ`A0#?R`vi?pMj`=d}P%%LkpT>k;oIpdJpLtp1lp z_d_RZ{QaVH|4i06Z;2iQovd*_5S{xqvaSofUcl+jfKJx=?iW1(ogBH?T_$6xqphs_ zEb+v{L)Nm1q9;HnYuOa)DBFXwmkMWruQz-v8TH9TS+dU4P2%A-U_Muaad_?be&H=h z8-#g%_Zwuy$wC~m&eLy-=M;Fhi)Sf3WbLb6qGv-VYo9+SI*(Jx>gV_MoK`+`vd#;B z7f*dTbh7&261@;QS>yBC0sY0$$r|UF=%vuf8s|i`f&OynWSys{iCzJntn+2I=t1aY zoiEAM(VwjQ=fzV64_V7D61^HaS<7BQ9c2%oY>6

        I)2k&Jrs7>%s+v_(9RA^o;+ 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 o~lTxhu5aFyXr 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 *ON{7=;NuRt1U2Ql+>2Tx2ia!EY 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 Zu-&jd+8lB}v|N6lTVF8})_soe{{Yxbt6Bg6 literal 0 HcmV?d00001 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 new file mode 100755 index 0000000000..449c883d61 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/lib/lib_copy.sh @@ -0,0 +1,39 @@ +#! /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/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 4cd77968b6..31ac13c240 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -34,6 +34,16 @@ INPUT = \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_agg_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_brc_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_cm_data_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_df_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_lcd_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_odp_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_prb_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h \ @@ -41,6 +51,7 @@ INPUT = \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_bt_defs.h \ diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-architecture.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-architecture.rst index ec04f47bb9..f096c8a797 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-architecture.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-architecture.rst @@ -390,7 +390,7 @@ When adopting the design of independent module, the two main factors should be c - ESP-BLE-MESH Proxy Server related functionalities * - :component_file:`proxy_client.c ` - ESP-BLE-MESH Proxy Client related functionalities - * - :component_file:`settings.c ` + * - :component_file:`settings.c ` - ESP-BLE-MESH NVS storage functionality * - :component_file:`main.c ` - ESP-BLE-MESH stack initialize, stack enable, node removal related functionalities diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-faq.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-faq.rst index 2f4250da6d..bd5d22cf6a 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-faq.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-faq.rst @@ -568,7 +568,7 @@ Generally, a Provisioner is used to provision unprovisioned devices and form a m The **count** value is provided to the Proxy node which is provisioned by the App so as to determine when to start Proxy advertising in advance. -4.5 When will Configuration Client Model of the node running :example:`fast_prov_server ` example start to work? +4.5 When will Configuration Client Model of the node running :example:`fast_prov_server ` example start to work? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Configuration Client Model will start to work after the Temporary Provisioner functionality is enabled. diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index dcabebffd9..5b93431421 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -7,13 +7,12 @@ Supported Features Mesh Core """"""""" -* Provisioning: Node Role - * PB-ADV and PB-GATT - * OOB Authentication - -* Provisioning: Provisioner Role - * PB-ADV and PB-GATT +* Provisioning: + * PB-ADV, PB-GATT and PB-Remote * OOB Authentication + * Certificate-based Provisioning + * Remote Provisioning + * Enhanced Provisioning Authentication * Networking * Relay @@ -24,6 +23,10 @@ Mesh Core * Low Power * Proxy Server * Proxy Client + * Directed Forwarding + * Private Beacon + * Subnet Bridge + * Minor Enhancements * Multiple Client Models Run Simultaneously * Support multiple client models send packets to different nodes simultaneously @@ -40,6 +43,24 @@ Mesh Models * Configuration Client model * Health Server model * Health Client model + * Remote Provisioning Server model + * Remote Provisioning Client model + * Directed Forwarding Configuration Server model + * Directed Forwarding Configuration Client model + * Bridge Configuration Server model + * Bridge Configuration Client model + * Mesh Private Beacon Server model + * Mesh Private Beacon Client model + * On-Demend Private Proxy Server model + * On-Demend Private Proxy Client model + * SAR Configuration Server model + * SAR Configuration Client model + * Solicitation PDU RPL Configuration Server model + * Solicitation PDU RPL Configuration Client model + * Opcodes Aggregator Server model + * Opcodes Aggregator Client model + * Large Composition Data Server model + * Large Composition Data Client model * Generic client models * Generic OnOff Client @@ -120,9 +141,9 @@ Mesh Applications * :example_file:`Tutorial ` * :example:`Example ` * ESP-BLE-MESH Fast Provisioning - * :example_file:`Fast Provisioning Client Model Tutorial ` - * :example_file:`Fast Provisioning Server Model Tutorial ` - * :example:`Example ` + * :example_file:`Fast Provisioning Client Model Tutorial ` + * :example_file:`Fast Provisioning Server Model Tutorial ` + * :example:`Example ` * `Demo Video `__ * ESP-BLE-MESH and Wi-Fi Coexistence * :example_file:`Tutorial ` diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-index.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-index.rst index 8092c582dd..2c32552961 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-index.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-index.rst @@ -219,10 +219,14 @@ ESP-BLE-MESH Examples * :example_file:`ESP-BLE-MESH Provisioner ` - shows how a device can act as an ESP-BLE-MESH Provisioner to provision devices. The Provisioner has a Configuration Server model, a Configuration Client model and a Generic OnOff Client model, see :example:`example code `. -* ESP-BLE-MESH Fast Provisioning - :example_file:`Client ` and :example_file:`Server ` - this example is used for showing how fast provisioning can be used in order to create a mesh network. It takes no more than 60 seconds to provision 100 devices, see :example:`example client code ` and :example:`example server code `. +* ESP-BLE-MESH Fast Provisioning - :example_file:`Client ` and :example_file:`Server ` - this example is used for showing how fast provisioning can be used in order to create a mesh network. It takes no more than 60 seconds to provision 100 devices, see :example:`example client code ` and :example:`example server code `. * :example_file:`ESP-BLE-MESH and Wi-Fi Coexistence ` - an example that demonstrates the Wi-Fi and Bluetooth (BLE/BR/EDR) coexistence feature of {IDF_TARGET_NAME}. Simply put, users can use the Wi-Fi while operating Bluetooth, see :example:`example code `. +* ESP-BLE-MESH Remote Provisioning(v1.1) - :example_file:`Client, Server and device ` - this example is used to demonstrate the new remote provisioning feature introduced in the Mesh Protocol v1.1, see :example:`example client code `, :example:`example server code ` and :example:`example device code `. + +* ESP-BLE-MESH Directed Forwarding(v1.1) - :example_file:`Client and Server ` - this example is used to demonstrate the new directed forwarding feature introduced in the Mesh Protocol v1.1. Only nodes along the path will forward the directed messages, while other nodes will not actively participate in forwarding, see :example:`example client code ` and :example:`example server code `. + .. _esp-ble-mesh-demo-videos: @@ -262,7 +266,9 @@ Bluetooth SIG Documentation --------------------------- - `BLE Mesh Core Specification `_ +- `BLE Mesh Protocol v1.1 Specification(draft) `_ - `BLE Mesh Model Specification `_ +- `BLE Mesh Model v1.1 Specification(draft) `_ - `An Intro to Bluetooth Mesh Part 1 `_ / `Part 2 `__ - `The Fundamental Concepts of Bluetooth Mesh Networking, Part 1 `_ / `Part 2 `__ - `Bluetooth Mesh Networking: Friendship `_ diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-terminology.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-terminology.rst index 8ca7aea51b..1c8dcaccce 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-terminology.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-terminology.rst @@ -95,7 +95,10 @@ ESP-BLE-MESH Terminology - PB-ADV transfers packets generated during the provisioning process over the advertising channels. This way can only be used for provisioning when provisioner and unprovisioned device both support PB-ADV. * - PB-GATT - PB-GATT is a provisioning bearer used to provision a device using Proxy PDUs to encapsulate Provisioning PDUs within the Mesh Provisioning Service. - - PB-GATT uses connection channels to transfer packets generated during the provisioning process. If an unprovisioned device wants to be provisioned through this method, it needs to implement the related Mesh Provisioning Service. Unprovisioned devices which do not implement such service cannot be provisioned into mesh network through PB-GATT bearer. + - PB-GATT uses connection channels to transfer packets generated during the provisioning process. If an unprovisioned device wants to be provisioned through this method, it needs to implement the related Mesh Provisioning Service. Unprovisioned devices which don't implement such service cannot be provisioned into mesh network through PB-GATT bearer. + * - PB-Remote + - The PB-Remote provisioning bearer uses the existing mesh network to provision an unprovisioned device that is not within immediate radio range of the Provisioner. + - PB-Remote uses the PB-ADV bearer or the PB-GATT bearer for the last hop to the unprovisioned device. * - Provisioning - Provisioning is a process of adding an unprovisioned device to a mesh network, managed by a Provisioner. - The process of provisioning turns the "unprovisioned device" into a "node", making it a member of the ESP-BLE-MESH network. @@ -114,6 +117,9 @@ ESP-BLE-MESH Terminology * - No OOB - No Out-of-Band - Authentication method of No OOB: Set the value of the Static OOB field to 0. Using this way is like not authenticating the unprovisioned devices. + * - Certificate-based Provisioning + - Certificate-based Out-of-Band + - The certificate-based provisioning feature makes use of Public Key Infrastructure to authenticate unprovisioned device's public key and UUID information. .. _ble-mesh-terminology-address: @@ -154,10 +160,12 @@ ESP-BLE-MESH Terminology * - Application Key (AppKey) - Application keys are used to secure communications at the upper transport layer. - Application key is used for decryption of application data before delivering application data to application layer and encryption of them during the delivery of application layer. Some nodes in the network have a specific purpose and can restrict access to potentially sensitive data based on the needs of the application. With specific application keys, these nodes are associated with specific applications. Generally speaking, the fields using different application keys include security (access control of buildings, machine rooms and CEO offices), lighting (plant, exterior building and sidewalks) and HVAC systems. Application keys are bound to Network keys. This means application keys are only used in a context of a Network key they are bound to. An application key shall only be bound to a single Network key. - * - Master Security Material - - The master security material is derived from the network key (NetKey) and can be used by other nodes in the same network. Messages encrypted with master security material can be decoded by any node in the same network. - - The corresponding friendship messages encrypted with the friendship security material: 1. Friend Poll, 2. Friend Update, 3. Friend Subscription List, add/delete/confirm, 4. The Stored Messages" sent by friend nodes to Low Power node. The corresponding friendship messages encrypted with the master security material: 1. Friend Clear, 2. Friend Clear Confirm. Based on the setup of the applications, the messages sent from the Low Power node to the friend nodes will be encrypted with the friendship security material or master security material, with the former being used by the messages transmitted between Low Power node and friend nodes and the latter being used by other network messages. - + * - Flooding Security Material + - The flooding security material is derived from the network key (NetKey) and can be used by other nodes in the same network. Messages encrypted with flooding security material can be decoded by any node in the same network. + - The corresponding friendship messages encrypted with the friendship security material: 1. Friend Poll, 2. Friend Update, 3. Friend Subscription List, add/delete/confirm, 4. The Stored Messages" sent by friend nodes to Low Power node. The corresponding friendship messages encrypted with the flooding security material: 1. Friend Clear, 2. Friend Clear Confirm. Based on the setup of the applications, the messages sent from the Low Power node to the friend nodes will be encrypted with the friendship security material or flooding security material, with the former being used by the messages transmitted between Low Power node and friend nodes and the latter being used by other network messages. + * - Directed Security Material + - The directed security material is derived from the network key (NetKey) and can be used by other nodes in the directed forwarding path. + - The messages that need to be forwarded through the directed forwarding path need to be encrypted with the directed security material. Messages encrypted with directed security material can be decoded by any node in the same directed forwarding path. .. _ble-mesh-terminology-message: @@ -197,6 +205,60 @@ ESP-BLE-MESH Terminology * - Health Client Model - The model is used to represent an element that can control and monitor the health of a node. - The Health Client Model uses messages to control the state maintained by the Health Server Model. The model can get the self-test information of other nodes through the message "Health Fault Get". + * - Remote Provisioning Server model + - The model is used to support the functionality of provisioning a remote device over the mesh network and to perform the Node Provisioning Protocol Interface procedures. + - The Remote Provisioning Server model is a root model and a main model that does not extend any other models. + * - Remote Provisioning Client model + - The model is used to support the functionality of provisioning devices into a mesh network by interacting with a mesh node that supports the Remote Provisioning Server model. + - The Remote Provisioning Client is a root model and a main model that does not extend any other models. The Remote Provisioning Client may operate on states defined by the Remote Provisioning Server model using Remote Provisioning messages. + * - Directed Forwarding Configuration Server model + - The model is used to support the configuration of the directed forwarding functionality of a node. + - The Directed Forwarding Configuration Server model is a main model that extends the Configuration Server model. + * - Directed Forwarding Configuration Client model + - The model is used to support the functionality of a node that can configure the directed forwarding functionality of another node. + - The Directed Forwarding Configuration Client model is a root model and a main model that does not extend any other models. The Directed Forwarding Configuration Client model may operate on states defined by the Directed Forwarding Configuration Server model using Directed Forwarding Configuration messages. + * - Bridge Configuration Server model + - The model is used to support the configuration of the subnet bridge functionality of a node. + - The Bridge Configuration Server model is a main model that extends the Configuration Server model. + * - Bridge Configuration Client model + - The model is used to support the functionality of a node that can configure the subnet bridge functionality of another node. + - The Bridge Configuration Client model is a root model and a main model that does not extend any other models. The Bridge Configuration Client model may operate on states defined by the Bridge Configuration Server model using Bridge messages. + * - Mesh Private Beacon Server model + - The model is used to support the configuration of the Mesh Private beacons functionality of a node. + - The Mesh Private Beacon Server model is a main model that extends the Configuration Server model. + * - Mesh Private Beacon Client model + - The model is used to support the functionality of a node that can configure the Mesh Private beacons functionality of another node. + - The Mesh Private Beacon Client model is a root model and a main model that does not extend any other models. The Mesh Private Beacon Client model may operate on states defined by the Mesh Private Beacon Server model using Mesh Private Beacon messages. + * - On-Demend Private Proxy Server model + - The model is used to support the configuration of the advertising with Private Network Identity type functionality of a node. + - The On-Demand Private Proxy Server model is a main model that extends the Mesh Private Beacon Server model and corresponds with the Solicitation PDU RPL Configuration Server model. + * - On-Demend Private Proxy Client model + - The model is used to support the functionality of a node that can configure the advertising with Private Network Identity type functionality of another node. + - The On-Demand Private Proxy Client model is a root model and a main model that does not extend any other models. The On-Demand Private Proxy Client model may operate on states defined by the On-Demand Private Proxy Server model using On-Demand Private Proxy messages. + * - SAR Configuration Server model + - The model is used to support the configuration of the segmentation and reassembly behavior of a node. + - The SAR Configuration Server model is a root model and a main model that does not extend any other models. + * - SAR Configuration Client model + - The SAR Configuration Client model is used to support the functionality of configuring the behavior of the lower transport layer of a node that supports the SAR Configuration Server model. + - The SAR Configuration Client model is a root model and a main model that does not extend any other models. The SAR Configuration Client model may operate on states defined by the SAR Configuration Server model using SAR Configuration messages. + * - Solicitation PDU RPL Configuration Server model + - The Solicitation PDU RPL Configuration Server model is used to support the functionality of removing items from the solicitation replay protection list of a node. + - The Solicitation PDU RPL Configuration Server model corresponds with the On-Demand Private Proxy Server model. + * - Solicitation PDU RPL Configuration Client model + - The model is used to support the functionality of removing addresses from the solicitation replay protection list of a node that supports the Solicitation PDU RPL Configuration Server model. + - The Solicitation PDU RPL Configuration Client model is a root model and a main model that does not extend any other models. The Solicitation PDU RPL Configuration Client model may be used to remove items from a solicitation replay protection list of a peer node by using Solicitation PDU RPL Configuration messages. + * - Opcodes Aggregator Server model + - The model is used to support the functionality of processing a sequence of access layer messages. + - The Opcodes Aggregator Server model is a root model that does not extend any other models. + * - Opcodes Aggregator Client model + - The model is used to support the functionality of dispatching a sequence of access layer messages to nodes supporting the Opcodes Aggregator Server model. + - The Opcodes Aggregator Client model is a root model and a main model that does not extend any other models. + * - Large Composition Data Server model + - The model is used to support the functionality of exposing pages of Composition Data that do not fit in a Config Composition Data Status message and to expose metadata of the model instances. + - The Large Composition Data Server is a main model that extends the Configuration Server model. + * - Large Composition Data Client model + - The model is used to support the functionality of reading pages of Composition Data that do not fit in a Config Composition Data Status message and reading the metadata of the model instances. + - The Large Composition Data Client model is a root model that does not extend any other models. The Large Composition Data Client model may operate on states defined by the Large Composition Data Server model using Large Composition Data messages. .. _ble-mesh-terminology-network-management: diff --git a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst index d7d22eb27b..9968a382bd 100644 --- a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst +++ b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst @@ -1,6 +1,10 @@ ESP-BLE-MESH ============ +.. note:: + + The current ESP-BLE-MESH v1.1 related code is a preview version, so the Mesh Protocol v1.1 related Structures, MACROs, and APIs involved in the code may be changed. + With various features of ESP-BLE-MESH, users can create a managed flooding mesh network for several scenarios, such as lighting, sensor and etc. For an ESP32 to join and work on a ESP-BLE-MESH network, it must be provisioned firstly. By provisioning, the ESP32, as an unprovisioned device, will join the ESP-BLE-MESH network and become a ESP-BLE-MESH node, communicating with other nodes within or beyond the radio range. diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-architecture.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-architecture.rst index 90281f0e67..8e59771ef3 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-architecture.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-architecture.rst @@ -390,7 +390,7 @@ Mesh Bearers 在实现时充分考虑了可移植性。当 ESP-BLE-MESH 协议 - ESP-BLE-MESH 代理服务器相关功能 * - :component_file:`proxy_client.c ` - ESP-BLE-MESH 代理客户端相关功能 - * - :component_file:`settings.c ` + * - :component_file:`settings.c ` - ESP-BLE-MESH NVS 存储器功能 * - :component_file:`main.c ` - ESP-BLE-MESH 协议栈初始化,协议栈使能,节点移除相关功能 diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-faq.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-faq.rst index 323735c7c7..5d17296b0b 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-faq.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-faq.rst @@ -568,7 +568,7 @@ ESP-BLE-MESH 常见问题手册 此 **count** 值提供给 App 配置的代理节点,以决定何时提前开始 Proxy 广播信息。 -4.5 运行以下示例 :example:`fast_prov_server ` 的节点的 Configuration Client Model 何时开始工作? +4.5 运行以下示例 :example:`fast_prov_server ` 的节点的 Configuration Client Model 何时开始工作? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 使能了 Temporary Provisioner 功能后,Configuration Client Model 会开始工作。 diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-index.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-index.rst index 30e0fd9b1f..762f5a1720 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-index.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-index.rst @@ -219,10 +219,14 @@ ESP-BLE-MESH 示例 * :example_file:`ESP-BLE-MESH Provisioner ` - 展示了设备如何充当 ESP-BLE-MESH Provisioner 以配网设备。Provisioner 拥有 Configuration Server model、Configuration Client model 和 Generic OnOff Client model,示例请见 :example:`example code `。 -* ESP-BLE-MESH 快速配网 - :example_file:`Client ` 和 :example_file:`Server ` - 该示例用于演示快速配网。配网 100 个设备费时不超过 60 秒,示例请见::example:`example client code ` 和 :example:`example server code `。 +* ESP-BLE-MESH 快速配网 - :example_file:`Client ` 和 :example_file:`Server ` - 该示例用于演示快速配网。配网 100 个设备费时不超过 60 秒,示例请见::example:`example client code ` 和 :example:`example server code `。 * :example_file:`Wi-Fi 和 ESP-BLE-MESH 共存 ` - 该示例用于演示 Wi-Fi 和 ESP-BLE-MESH 共存的功能。简而言之,用户可在运行 ESP-BLE-MESH 时使用 Wi-Fi,示例请见 :example:`example code `。 +* ESP-BLE-MESH 远程配网(v1.1 新增) - :example_file:`Client, Server and device ` - 该示例用于演示 mesh 协议 v1.1 中新增的远程配网功能, 示例请见: :example:`example client code `, :example:`example server code ` and :example:`example device code `. + +* ESP-BLE-MESH 定向转发(v1.1 新增) - :example_file:`Client and Server ` - 该示例用于演示 mesh 协议 v1.1 中新增的定向转发功能。只有路径上的节点才会对定向消息进行转发,而其他节点不参与转发, 示例请见 :example:`example client code ` and :example:`example server code `. + .. _esp-ble-mesh-demo-videos: @@ -262,7 +266,9 @@ ESP-BLE-MESH 常见问题手册 ------------- - `BLE Mesh Core Specification `_ +- `BLE Mesh Protocol v1.1 Specification(draft) `_ - `BLE Mesh Model Specification `_ +- `BLE Mesh Model v1.1 Specification(draft) `_ - `An Intro to Bluetooth Mesh Part 1 `_ / `Part 2 `__ - `The Fundamental Concepts of Bluetooth Mesh Networking, Part 1 `_ / `Part 2 `__ - `Bluetooth Mesh Networking: Friendship `_ diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-terminology.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-terminology.rst index ce89b36dc0..2bba149143 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-terminology.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-terminology.rst @@ -96,6 +96,9 @@ ESP-BLE-MESH Terminology * - PB-GATT - "PB-GATT is a provisioning bearer used to provision a device using Proxy PDUs to encapsulate Provisioning PDUs within the Mesh Provisioning Service." - PB-GATT 通过连接通道传输配网过程中产生的数据包。如果未配网设备想使用此方式进行配网,其需要实现相关的 Mesh Provisioning Service。未实现此服务的未配网设备不能通过 PB-GATT 承载层配网接入 mesh 网络。 + * - PB-Remote + - "The PB-Remote provisioning bearer uses the existing mesh network to provision an unprovisioned device that is not within immediate radio range of the Provisioner." + - PB-Remote 是一种使用现有的网状网络来为无法与配网器直接通信的未配网设备进行配网的配网承载方式。 * - 配置入网 - "Provisioning is a process of adding an unprovisioned device to a mesh network, managed by a Provisioner." - 经过配网,“未配网设备”的身份转变为“节点”,成为 ESP-BLE-MESH 网络中的一员。 @@ -114,7 +117,9 @@ ESP-BLE-MESH Terminology * - 无带外 (No OOB) - No Out-of-Band - 无 OOB 的认证方法:将“静态 OOB”字段赋值为 0。采用这种方式相当于不认证未配网的设备。 - + * - 基于证书的配网 (Certificate-based Provisioning) + - Certificate-based Out-of-Band + - 基于证书的配网功能利用公钥基础设施来验证未配网设备的公钥和UUID信息。 .. _ble-mesh-terminology-address: @@ -154,10 +159,12 @@ ESP-BLE-MESH Terminology * - 应用密钥 (AppKey) - "Application keys are used to secure communications at the upper transport layer." - 应用密钥用于应用数据传递至应用层过程中对应用数据的解密,和应用层下发过程中对数据的加密。网络中的一些节点有特定的用途,并且可以根据应用程序的需求对一些潜在敏感数据的访问进行限制。通过特定的应用密钥,这些节点与特定应用程序相关联。通常而言,使用不同应用密钥的领域有安全(楼宇门禁、机房门禁和 CEO 办公室门禁)、照明(工厂、外部楼宇和人行道)和 HVAC 系统。应用密钥绑定在网络密钥上,这意味着应用密钥仅在绑定网络密钥的情况下使用。每一个应用密钥仅可绑定到一个网络密钥。 - * - 主安全资料 + * - 泛洪安全资料 - "The master security material is derived from the network key (NetKey) and can be used by other nodes in the same network. Messages encrypted with master security material can be decoded by any node in the same network. " - - 使用好友安全材料加密的相应友谊消息有:1. 好友轮询 (Friend Poll),2. 好友更新 (Friend Update),3. 好友订阅列表 (Friend Subscription List),添加/删除/确认,4. 好友节点发送到低功耗节点的“已存储消息”,使用主安全材料加密的相应友谊消息有:1. 好友清除 (Friend Clear),2. 好友清除确认 (Friend Clear Confirm)。根据应用程序的设置,从低功耗节点发送到好友节点的消息会使用友谊安全材料或主安全材料进行加密,前者用于低功耗节点与好友节点之间的消息传输,而后者用于其他网络消息。 - + - 使用好友安全材料加密的相应友谊消息有:1. 好友轮询 (Friend Poll),2. 好友更新 (Friend Update),3. 好友订阅列表 (Friend Subscription List),添加/删除/确认,4. 好友节点发送到低功耗节点的“已存储消息”,使用泛洪安全材料加密的相应友谊消息有:1. 好友清除 (Friend Clear),2. 好友清除确认 (Friend Clear Confirm)。根据应用程序的设置,从低功耗节点发送到好友节点的消息会使用友谊安全材料或泛洪安全材料进行加密,前者用于低功耗节点与好友节点之间的消息传输,而后者用于其他网络消息。 + * - 定向安全资料 + - "The directed security material is derived from the network key (NetKey) and can be used by other nodes in the directed forwarding path." + - 定向安全资料是从网络密钥(NetKey)派生的,可以被定向转发路径中的其他节点使用。使用定向安全资料加密的消息可以被同一定向转发路径中的任何节点解码。 .. _ble-mesh-terminology-message: @@ -196,6 +203,60 @@ ESP-BLE-MESH Terminology * - Health Client Model - "The model is used to represent an element that can control and monitor the health of a node." - Health Client Model 通过消息控制 Health Server Model 维护的状态。该模型可通过消息 “Health Fault Get” 获取其他节点的自检信息。 + * - Remote Provisioning Server model + - "The model is used to support the functionality of provisioning a remote device over the mesh network and to perform the Node Provisioning Protocol Interface procedures." + - 该模型用于支持通过网状网络对远程设备进行供应,并执行节点供应协议接口程序。 + * - Remote Provisioning Client model + - "The model is used to support the functionality of provisioning devices into a mesh network by interacting with a mesh node that supports the Remote Provisioning Server model." + - 该模型用于与支持远程供应服务器模型的网状节点进行交互,以支持将设备供应到网状网络的功能。 + * - Directed Forwarding Configuration Server model + - "The model is used to support the configuration of the directed forwarding functionality of a node." + - 该模型用于支持节点的定向转发功能的配置。 + * - Directed Forwarding Configuration Client model + - "The model is used to support the functionality of a node that can configure the directed forwarding functionality of another node." + - 该模型用于支持一个节点配置另一个节点的定向转发功能的功能。 + * - Bridge Configuration Server model + - "The model is used to support the configuration of the subnet bridge functionality of a node." + - 该模型用于支持节点的子网桥接功能的配置。 + * - Bridge Configuration Client model + - "The model is used to support the functionality of a node that can configure the subnet bridge functionality of another node." + - 该模型用于支持一个节点配置另一个节点的子网桥接功能的功能。 + * - Mesh Private Beacon Server model + - "The model is used to support the configuration of the Mesh Private beacons functionality of a node." + - 该模型用于支持节点的 Mesh 私有信标功能的配置。 + * - Mesh Private Beacon Client model + - "The model is used to support the functionality of a node that can configure the Mesh Private beacons functionality of another node." + - 该模型用于支持一个节点配置另一个节点的 Mesh 私有信标功能的功能。 + * - On-Demend Private Proxy Server model + - "The model is used to support the configuration of the advertising with Private Network Identity type functionality of a node." + - 该模型用于支持节点的私有网络身份类型广告配置功能。 + * - On-Demend Private Proxy Client model + - "The model is used to support the functionality of a node that can configure the advertising with Private Network Identity type functionality of another node." + - 该模型用于支持一个节点配置另一个节点的私有网络身份类型广告功能的功能。 + * - SAR Configuration Server model + - "The model is used to support the configuration of the segmentation and reassembly behavior of a node." + - 该模型用于支持节点的分段和重组行为的配置。 + * - SAR Configuration Client model + - "The SAR Configuration Client model is used to support the functionality of configuring the behavior of the lower transport layer of a node that supports the SAR Configuration Server model." + - SAR配置客户端模型用于支持配置支持 SAR 配置服务器模型的节点的较低传输层行为的功能。 + * - Solicitation PDU RPL Configuration Server model + - "The Solicitation PDU RPL Configuration Server model is used to support the functionality of removing items from the solicitation replay protection list of a node." + - Solicitation PDU RPL 配置服务器模型用于支持从节点的请求重放保护列表中移除项目的功能。 + * - Solicitation PDU RPL Configuration Client model + - "The model is used to support the functionality of removing addresses from the solicitation replay protection list of a node that supports the Solicitation PDU RPL Configuration Server model." + - 该模型用于支持支持 Solicitation PDU RPL 配置服务器模型的节点从其请求重放保护列表中移除地址的功能。 + * - Opcodes Aggregator Server model + - "The model is used to support the functionality of processing a sequence of access layer messages." + - 该模型用于支持处理一系列访问层消息的功能。 + * - Opcodes Aggregator Client model + - "The model is used to support the functionality of dispatching a sequence of access layer messages to nodes supporting the Opcodes Aggregator Server model." + - 该模型用于支持将一系列访问层消息分派给支持 Opcodes Aggregator Server 模型的节点的功能。 + * - Large Composition Data Server model + - "The model is used to support the functionality of exposing pages of Composition Data that do not fit in a Config Composition Data Status message and to expose metadata of the model instances." + - 该模型用于支持暴露不适应于 Config Composition Data Status 消息中的组成数据页的功能,并暴露模型实例的元数据。 + * - Large Composition Data Client model + - "The model is used to support the functionality of reading pages of Composition Data that do not fit in a Config Composition Data Status message and reading the metadata of the model instances." + - 该模型用于支持读取不适应于 Config Composition Data Status 消息中的组成数据页的功能,并读取模型实例的元数据。 .. _ble-mesh-terminology-network-management: diff --git a/examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/genie_model_srv.c b/examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/genie_model_srv.c index d8885faa9d..132c1d502a 100644 --- a/examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/genie_model_srv.c +++ b/examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/genie_model_srv.c @@ -387,7 +387,6 @@ esp_err_t genie_model_msg_send(genie_model_msg_t *p_model_msg) ctx.net_idx = bt_mesh_model_get_netkey_id(p_model_msg->p_elem); ctx.addr = GENIE_RECV_ADDR; ctx.send_ttl = BLE_MESH_TTL_DEFAULT; - ctx.send_rel = 0; ESP_LOGI(TAG, "vendor message send: tid: 0x%02x, retry: %02d, len: %02d, opcode: 0x%02x, data: 0x%s", p_model_msg->tid, p_model_msg->retry, p_model_msg->len, p_model_msg->opid, util_hex2str(p_model_msg->data, p_model_msg->len)); ESP_LOGD(TAG, "vendor message send: element: %p, app_idx: %d, net_idx: %d, tid: 0x%02x, retry: %02d, len: %02d, opcode: 0x%02x, data: 0x%s", diff --git a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c index bcaf06709d..a4b2427ecd 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c +++ b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c @@ -129,7 +129,6 @@ void example_send_self_prov_node_addr(struct k_work *work) .app_idx = fast_prov_srv->app_idx, .dst = fast_prov_srv->prim_prov_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); if (err != ESP_OK) { @@ -179,7 +178,6 @@ static void example_get_all_node_addr(struct k_work *work) .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 10000, - .role = ROLE_PROVISIONER, }; err = example_send_fast_prov_all_node_addr_get(model, &info); if (err != ESP_OK) { @@ -234,12 +232,10 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo set.ctx_flags = BIT(6); set.group_addr = fast_prov_srv->group_addr; } - info.role = ROLE_FAST_PROV; #else set.ctx_flags = 0x037F; memcpy(&set.node_addr_cnt, &node->node_addr_cnt, sizeof(example_node_info_t) - offsetof(example_node_info_t, node_addr_cnt)); - info.role = ROLE_PROVISIONER; #endif err = example_send_fast_prov_info_set(model, &info, &set); if (err != ESP_OK) { @@ -258,7 +254,6 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo .app_idx = fast_prov_srv->app_idx, .dst = fast_prov_srv->prim_prov_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); if (err != ESP_OK) { @@ -286,7 +281,6 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 10000, - .role = ROLE_PROVISIONER, }; err = example_send_fast_prov_all_node_addr_get(model, &info); if (err != ESP_OK) { @@ -384,7 +378,6 @@ esp_err_t example_fast_prov_client_recv_status(esp_ble_mesh_model_t *model, .app_idx = node->app_idx, .dst = node->group_addr, .timeout = 0, - .role = ROLE_PROVISIONER, }; err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false); if (err != ESP_OK) { diff --git a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c index 0c83accb60..c2e9251618 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c +++ b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c @@ -349,10 +349,8 @@ esp_err_t example_send_config_appkey_add(esp_ble_mesh_model_t *model, common.ctx.net_idx = info->net_idx; common.ctx.app_idx = 0x0000; /* not used for config messages */ common.ctx.addr = info->dst; - common.ctx.send_rel = false; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; - common.msg_role = info->role; return esp_ble_mesh_config_client_set_state(&common, &set); } @@ -372,10 +370,8 @@ esp_err_t example_send_generic_onoff_get(esp_ble_mesh_model_t *model, common.ctx.net_idx = info->net_idx; common.ctx.app_idx = info->app_idx; common.ctx.addr = info->dst; - common.ctx.send_rel = false; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; - common.msg_role = info->role; return esp_ble_mesh_generic_client_get_state(&common, &get); } @@ -405,10 +401,8 @@ esp_err_t example_send_generic_onoff_set(esp_ble_mesh_model_t *model, common.ctx.net_idx = info->net_idx; common.ctx.app_idx = info->app_idx; common.ctx.addr = info->dst; - common.ctx.send_rel = false; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; - common.msg_role = info->role; return esp_ble_mesh_generic_client_set_state(&common, &set); } @@ -472,7 +466,6 @@ esp_err_t example_send_fast_prov_info_set(esp_ble_mesh_model_t *model, .net_idx = info->net_idx, .app_idx = info->app_idx, .addr = info->dst, - .send_rel = false, .send_ttl = 0, }; err = esp_ble_mesh_client_model_send_msg(model, &ctx, @@ -495,7 +488,6 @@ esp_err_t example_send_fast_prov_net_key_add(esp_ble_mesh_model_t *model, .net_idx = info->net_idx, .app_idx = info->app_idx, .addr = info->dst, - .send_rel = false, .send_ttl = 0, }; @@ -518,7 +510,6 @@ esp_err_t example_send_fast_prov_self_prov_node_addr(esp_ble_mesh_model_t *model .net_idx = info->net_idx, .app_idx = info->app_idx, .addr = info->dst, - .send_rel = false, .send_ttl = 0, }; @@ -538,7 +529,6 @@ esp_err_t example_send_fast_prov_all_node_addr_get(esp_ble_mesh_model_t *model, .net_idx = info->net_idx, .app_idx = info->app_idx, .addr = info->dst, - .send_rel = false, .send_ttl = 0, }; @@ -561,7 +551,6 @@ esp_err_t example_send_fast_prov_status_msg(esp_ble_mesh_model_t *model, case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK: case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: ctx->send_ttl = 0; - ctx->send_rel = false; break; default: ESP_LOGW(TAG, "%s: Invalid fast prov status opcode 0x%04" PRIx32, __func__, opcode); diff --git a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/CMakeLists.txt index 12b940ee56..6dc16c7094 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/CMakeLists.txt @@ -1,6 +1,8 @@ -set(COMPONENT_SRCS "light_driver.c" - "iot_led.c") +set(COMPONENT_SRCS + "light_driver.c" + "iot_led.c" + "led_strip_encoder.c") set(COMPONENT_ADD_INCLUDEDIRS ". include") diff --git a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/include/led_strip_encoder.h b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/include/led_strip_encoder.h new file mode 100644 index 0000000000..b397b2dfc4 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/include/led_strip_encoder.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "driver/rmt_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of led strip encoder configuration + */ +typedef struct { + uint32_t resolution; /*!< Encoder resolution, in Hz */ +} led_strip_encoder_config_t; + +/** + * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols + * + * @param[in] config Encoder configuration + * @param[out] ret_encoder Returned encoder handle + * @return + * - ESP_ERR_INVALID_ARG for any invalid arguments + * - ESP_ERR_NO_MEM out of memory when creating led strip encoder + * - ESP_OK if creating encoder successfully + */ +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder); + + + +void rmt_encoder_init(void); +void rmt_led_set(uint8_t red, uint8_t green, uint8_t blue); + +#ifdef __cplusplus +} +#endif diff --git a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/iot_led.c b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/iot_led.c index 428996ea3c..777868524a 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/iot_led.c +++ b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/iot_led.c @@ -29,6 +29,8 @@ #define GPTIMER_RESOLUTION_HZ 1000000 // 1MHz, 1 tick=1us +#if (CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3) + typedef struct { int cur; int final; @@ -475,3 +477,5 @@ esp_err_t iot_led_set_gamma_table(const uint16_t gamma_table[GAMMA_TABLE_SIZE]) memcpy(g_gamma_table, gamma_table, GAMMA_TABLE_SIZE * sizeof(uint16_t)); return ESP_OK; } + +#endif /* (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3) */ diff --git a/examples/bluetooth/esp_ble_mesh/common_components/light_driver/led_strip_encoder.c b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/led_strip_encoder.c new file mode 100644 index 0000000000..03ba98447e --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/common_components/light_driver/led_strip_encoder.c @@ -0,0 +1,178 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "led_strip_encoder.h" +#include "driver/rmt_tx.h" +#include "portmacro.h" + +static const char *TAG = "led_encoder"; + +typedef struct { + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; +} rmt_led_strip_encoder_t; + +static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = RMT_ENCODING_RESET; + rmt_encode_state_t state = RMT_ENCODING_RESET; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; +} + +static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; +} + +static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = RMT_ENCODING_RESET; + return ESP_OK; +} + +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) +{ + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + // different led strip might have its own timing requirements, following parameter is for WS2812 + rmt_bytes_encoder_config_t bytes_encoder_config = { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); + rmt_copy_encoder_config_t copy_encoder_config = {}; + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); + + uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us + led_encoder->reset_code = (rmt_symbol_word_t) { + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + *ret_encoder = &led_encoder->base; + return ESP_OK; +err: + if (led_encoder) { + if (led_encoder->bytes_encoder) { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) { + rmt_del_encoder(led_encoder->copy_encoder); + } + free(led_encoder); + } + return ret; +} + + +#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) + +#ifndef BLE_MESH_LED_STRIP_IO +#define RMT_LED_STRIP_GPIO_NUM 8 +#else +#define RMT_LED_STRIP_GPIO_NUM BLE_MESH_LED_STRIP_IO +#endif + +#define EXAMPLE_LED_NUMBERS 1 +#define EXAMPLE_CHASE_SPEED_MS 10 + +static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3]; +rmt_channel_handle_t led_chan = NULL; +rmt_encoder_handle_t led_encoder = NULL; +rmt_transmit_config_t tx_config; + +void rmt_encoder_init() +{ + led_chan = NULL; + rmt_tx_channel_config_t tx_chan_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock + .gpio_num = RMT_LED_STRIP_GPIO_NUM, + .mem_block_symbols = 64, // increase the block size can make the LED less flickering + .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, + .trans_queue_depth = 4, // set the number of transactions that can be pending in the background + }; + ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan)); + + ESP_LOGI(TAG, "Install led strip encoder"); + led_encoder = NULL; + led_strip_encoder_config_t encoder_config = { + .resolution = RMT_LED_STRIP_RESOLUTION_HZ, + }; + ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder)); + + ESP_LOGI(TAG, "Enable RMT TX channel"); + ESP_ERROR_CHECK(rmt_enable(led_chan)); + + tx_config.loop_count = 0; // no transfer loop +} + +void rmt_led_set(uint8_t red, uint8_t green, uint8_t blue) +{ + led_strip_pixels[0] = green; + led_strip_pixels[1] = red; + led_strip_pixels[2] = blue; + + ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config)); + ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY)); +} diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/README.md b/examples/bluetooth/esp_ble_mesh/directed_forwarding/README.md new file mode 100644 index 0000000000..be11715aa9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/README.md @@ -0,0 +1,56 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | + +# Directed Forwarding + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example is primarily intended to demonstrate the newly added directed forwarding feature in Mesh Protocol v1.1. + +## How to use example + +Please refer to this [tutorial](examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md) for detailed instructions on how to run it. + + +### Hardware Required +You need prepare at least two ESP series development boards. We recommend using the [ESP32-C3-DevKitM-1](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html) or [ESP32-C6-DevKitC-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/user_guide.html#). Alternatively, you can use other development boards, but ensure that each board has at least one LED and one button for operation. +### Configure the project + +``` +idf.py menuconfig +``` + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output +After all devices have joined the network, you need to press the button on the provisioner(the device which runs df_client) to complete the final setup. Once the setup is complete, provisioner will provide the following output: + +``` +You could click to send message by directed forwarding +After the message handled, you could click again to send message by flooding +``` +After seeing the above output, you can press the button again to send a network message. When the message is sent in directed forwarding, the following output will be displayed: +``` +Will send a message to node(`node unicast`) with DF +``` +When the message is sent in a flooding, the following output will be displayed: +``` +Will send a message to node(`node unicast`) with Flooding +``` +## Troubleshooting + +See common troubleshooting for Directed Forwarding examples from [ESP-BLE-MESH FAQ](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/esp-ble-mesh/ble-mesh-index.html#esp-ble-mesh-faq). + +(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt new file mode 100644 index 0000000000..b3ad88ab5a --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt @@ -0,0 +1,11 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(onoff_client) diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/CMakeLists.txt new file mode 100644 index 0000000000..b1a0bcb761 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/CMakeLists.txt @@ -0,0 +1,7 @@ +set(srcs "main.c" + "board.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/Kconfig.projbuild new file mode 100644 index 0000000000..cbab996ec2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 if IDF_TARGET_ESP32 + default BLE_MESH_ESP32C3_DEV if IDF_TARGET_ESP32C3 + default BLE_MESH_ESP32S3_DEV if IDF_TARGET_ESP32S3 + default BLE_MESH_ESP32C6_DEV if IDF_TARGET_ESP32C6 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP32C3_DEV + bool "ESP32C3-DevKitC" + depends on IDF_TARGET_ESP32C3 + + config BLE_MESH_ESP32S3_DEV + bool "ESP32S3-DevKitC" + depends on IDF_TARGET_ESP32S3 + + config BLE_MESH_ESP32C6_DEV + bool "ESP32C6-DevKitC" + depends on IDF_TARGET_ESP32C6 + + config BLE_MESH_ESP32H2_DEV + bool "ESP32H2-DevKitC" + depends on IDF_TARGET_ESP32H2 + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.c b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.c new file mode 100644 index 0000000000..266ef381bc --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.c @@ -0,0 +1,88 @@ +/* board.c - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "driver/gpio.h" +#include "esp_log.h" + +#include "iot_button.h" +#include "board.h" +#include "esp_timer.h" +#include "led_strip_encoder.h" + +#define TAG "BOARD" + +#define BUTTON_ACTIVE_LEVEL 0 + +extern void example_ble_mesh_start_example_configuration(void); +extern void example_ble_mesh_send_gen_onoff_set(bool by_df); +extern uint8_t in_configuration_phase; +esp_timer_handle_t led_timer_hdl; + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b) +{ + rmt_led_set(r,g,b); +} + +static void led_timer_callback(void* arg) +{ + board_led_operation(0,0,0); +} + +static void esp_led_timer_init(void) +{ + const esp_timer_create_args_t led_timer_args = { + .callback = &led_timer_callback, + .arg = NULL, + .name = "led timer", + }; + + ESP_ERROR_CHECK(esp_timer_create(&led_timer_args, &led_timer_hdl)); +} + +void board_led_operation_auto_close(uint8_t r, uint8_t g, uint8_t b, uint32_t ms) +{ + esp_timer_stop(led_timer_hdl); + board_led_operation(r,g,b); + esp_timer_start_once(led_timer_hdl, ms * 1000); +} + + +static void board_led_init(void) +{ + rmt_encoder_init(); + esp_led_timer_init(); +} + +static void button_tap_cb(void* arg) +{ + ESP_LOGI(TAG, "tap cb (%s)", (char *)arg); + static bool use_df = true; + if (in_configuration_phase) { + example_ble_mesh_start_example_configuration(); + } else { + example_ble_mesh_send_gen_onoff_set(use_df); + use_df = !use_df; + } +} + +static void board_button_init(void) +{ + button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL); + if (btn_handle) { + iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE"); + } +} + +void board_init(void) +{ + board_led_init(); + board_button_init(); +} diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.h b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.h new file mode 100644 index 0000000000..9ebec462e4 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/board.h @@ -0,0 +1,56 @@ +/* board.h - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "esp_ble_mesh_defs.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#elif defined(CONFIG_BLE_MESH_ESP32C3_DEV) +#define LED_R GPIO_NUM_8 +#define LED_G GPIO_NUM_8 +#define LED_B GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32S3_DEV) +#define LED_R GPIO_NUM_47 +#define LED_G GPIO_NUM_47 +#define LED_B GPIO_NUM_47 +#elif defined(CONFIG_BLE_MESH_ESP32C6_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32H2_DEV) +#define LED_R GPIO_NUM_8 +#define LED_G GPIO_NUM_8 +#define LED_B GPIO_NUM_8 +#endif + +#define LED_ON 1 +#define LED_OFF 0 + +#define BUTTON_IO_NUM GPIO_NUM_9 + +struct _led_state { + uint8_t current; + uint8_t previous; + uint8_t pin; + char *name; +}; + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/main.c b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/main.c new file mode 100644 index 0000000000..ba81abd71a --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/main.c @@ -0,0 +1,916 @@ +/* main.c - Application main entry point */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "esp_random.h" +#include "nvs_flash.h" +#include "esp_bt.h" +#include "esp_mac.h" +#include "foundation.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" +#include "esp_ble_mesh_df_model_api.h" + +#include "ble_mesh_example_init.h" +#include "board.h" + +#define TAG "EXAMPLE" + +#define CID_ESP 0x02E5 + +#define PROV_OWN_ADDR 0x0001 + +#define MSG_SEND_TTL 3 +#define MSG_TIMEOUT 0 +#define MSG_ROLE ROLE_PROVISIONER + +#define COMP_DATA_PAGE_0 0x00 + +#define APP_KEY_IDX 0x0000 +#define APP_KEY_OCTET 0x12 + +#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT 0x0000 +#define ESP_BLE_MESH_VND_MODEL_ID_SERVER 0x0001 + +#define ESP_BLE_MESH_VND_MODEL_OP_SET ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) + +static uint8_t dev_uuid[16]; + +typedef struct { + uint8_t uuid[16]; + uint16_t unicast; + uint8_t elem_num; + uint8_t onoff; + uint8_t tid; +} esp_ble_mesh_node_info_t; + +static esp_ble_mesh_node_info_t nodes[CONFIG_BLE_MESH_MAX_PROV_NODES] = { + [0 ... (CONFIG_BLE_MESH_MAX_PROV_NODES - 1)] = { + .unicast = ESP_BLE_MESH_ADDR_UNASSIGNED, + .elem_num = 0, + .onoff = LED_OFF, + } +}; + +static uint16_t last_node_idx; +static uint16_t curr_node_idx; +uint8_t in_configuration_phase = 1; + +static struct esp_ble_mesh_key { + uint16_t net_idx; + uint16_t app_idx; + uint8_t app_key[16]; +} prov_key; + +static esp_ble_mesh_client_t config_client; +static esp_ble_mesh_client_t onoff_client; +#if CONFIG_BLE_MESH_DF_CLI +static esp_ble_mesh_client_t directed_forwarding_client; +#endif + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +#if CONFIG_BLE_MESH_DF_SRV +static esp_ble_mesh_df_srv_t directed_forwarding_server = { + .directed_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), + .default_rssi_threshold = (-80), + .rssi_margin = 20, + .directed_node_paths = 20, + .directed_relay_paths = 20, +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .directed_proxy_paths = 20, +#else + .directed_proxy_paths = 0, +#endif +#if defined(CONFIG_BLE_MESH_FRIEND) + .directed_friend_paths = 20, +#else + .directed_friend_paths = 0, +#endif + .path_monitor_interval = 120, + .path_disc_retry_interval = 300, + .path_disc_interval = ESP_BLE_MESH_PATH_DISC_INTERVAL_30_SEC, + .lane_disc_guard_interval = ESP_BLE_MESH_LANE_DISC_GUARD_INTERVAL_10_SEC, + .directed_ctl_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_ctl_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), +}; +#endif + +static const esp_ble_mesh_client_op_pair_t vnd_op_pair[] = { + { ESP_BLE_MESH_VND_MODEL_OP_SET, ESP_BLE_MESH_VND_MODEL_OP_STATUS }, +}; + +static esp_ble_mesh_client_t vendor_client = { + .op_pair_size = ARRAY_SIZE(vnd_op_pair), + .op_pair = vnd_op_pair, +}; + +static esp_ble_mesh_model_op_t vnd_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_STATUS, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_CLIENT, + vnd_op, NULL, &vendor_client), +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), +#if CONFIG_BLE_MESH_DF_CLI + ESP_BLE_MESH_MODEL_DF_CLI(&directed_forwarding_client), +#endif +#if CONFIG_BLE_MESH_DF_SRV + ESP_BLE_MESH_MODEL_DF_SRV(&directed_forwarding_server), +#endif + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +static esp_ble_mesh_prov_t provision = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = PROV_OWN_ADDR, + .prov_start_address = 0x0002, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +static esp_err_t example_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast, + uint8_t elem_num, uint8_t onoff_state) +{ + int i; + + if (!uuid || !ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return ESP_ERR_INVALID_ARG; + } + + if (last_node_idx >= ARRAY_SIZE(nodes)) { + ESP_LOGW(TAG, "Maximum node limit exceeded, Max nodes number is %d", CONFIG_BLE_MESH_MAX_PROV_NODES); + return ESP_ERR_NO_MEM; + } + + /* Judge if the device has been provisioned before */ + for (i = 0; i < last_node_idx; i++) { + if (!memcmp(nodes[i].uuid, uuid, 16)) { + ESP_LOGW(TAG, "%s: reprovisioned device 0x%04x", __func__, unicast); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + if (nodes[last_node_idx].unicast == ESP_BLE_MESH_ADDR_UNASSIGNED) { + nodes[last_node_idx].unicast = unicast; + nodes[last_node_idx].elem_num = elem_num; + nodes[last_node_idx].onoff = onoff_state; + memcpy(nodes[i].uuid, uuid, 16); + last_node_idx++; + return ESP_OK; + } + + for (i = ARRAY_SIZE(nodes) - 1; i >= 0; i--) { + if (nodes[i].unicast != ESP_BLE_MESH_ADDR_UNASSIGNED) { + nodes[i + 1].unicast = unicast; + nodes[i + 1].elem_num = elem_num; + nodes[i + 1].onoff = onoff_state; + last_node_idx = i + 2; + return ESP_OK; + } + } + + return ESP_FAIL; +} + +static esp_ble_mesh_node_info_t *example_ble_mesh_get_node_info(uint16_t unicast) +{ + int i; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return NULL; + } + + for (i = 0; i < last_node_idx; i++) { + if (nodes[i].unicast <= unicast && + nodes[i].unicast + nodes[i].elem_num > unicast) { + return &nodes[i]; + } + } + + return NULL; +} + +static esp_err_t example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common, + esp_ble_mesh_node_info_t *node, + esp_ble_mesh_model_t *model, uint32_t opcode) +{ + if (!common || !node || !model) { + return ESP_ERR_INVALID_ARG; + } + + common->opcode = opcode; + common->model = model; + common->ctx.net_idx = prov_key.net_idx; + common->ctx.app_idx = prov_key.app_idx; + common->ctx.addr = node->unicast; + common->ctx.send_ttl = MSG_SEND_TTL; + common->msg_timeout = MSG_TIMEOUT; + + return ESP_OK; +} + +void example_ble_mesh_send_directed_forwarding_srv_control_set(esp_ble_mesh_node_info_t *node) +{ + esp_ble_mesh_df_client_set_t set = {0}; + esp_ble_mesh_client_common_param_t param = {0}; + esp_ble_mesh_elem_t *element = NULL; + esp_ble_mesh_model_t *model = NULL; + esp_err_t err = ESP_OK; + + element = esp_ble_mesh_find_element(esp_ble_mesh_get_primary_element_address()); + if (!element) { + ESP_LOGE(TAG, "Element 0x%04x not exists", esp_ble_mesh_get_primary_element_address()); + return; + } + + model = esp_ble_mesh_find_sig_model(element, ESP_BLE_MESH_MODEL_ID_DF_CLI); + if (!model) { + ESP_LOGE(TAG, "Directed Forwarding Client not exists"); + return; + } + + example_ble_mesh_set_msg_common(¶m, node, model, ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET); + + set.directed_control_set.net_idx = prov_key.net_idx; + set.directed_control_set.directed_forwarding = ESP_BLE_MESH_DIRECTED_FORWARDING_ENABLED; + set.directed_control_set.directed_relay = ESP_BLE_MESH_DIRECTED_RELAY_ENABLED; + set.directed_control_set.directed_proxy = ESP_BLE_MESH_DIRECTED_PROXY_IGNORE; + set.directed_control_set.directed_proxy_use_default = ESP_BLE_MESH_DIRECTED_PROXY_USE_DEFAULT_IGNORE; + set.directed_control_set.directed_friend = ESP_BLE_MESH_DIRECTED_FRIEND_IGNORE; + + + err = esp_ble_mesh_df_client_set_state(¶m, &set); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Directed Forwarding Control Set"); + } + + return; +} + +void example_ble_mesh_send_gen_onoff_set(bool by_df) +{ + esp_ble_mesh_generic_client_set_state_t set = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + + if (!last_node_idx) { + ESP_LOGE(TAG, "No node provisioned"); + return; + } + + curr_node_idx = last_node_idx - 1; + + esp_ble_mesh_node_info_t *node = &nodes[curr_node_idx]; + + example_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + + if (by_df) { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_USE_DIRECTED|ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } else { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } + + ESP_LOGI(TAG, "Will send a message to node(0x%04x) with %s", node->unicast, by_df ? "DF" : "Flooding"); + + set.onoff_set.op_en = false; + set.onoff_set.onoff = node->onoff; + set.onoff_set.tid = node->tid; + node->tid++; + + err = esp_ble_mesh_generic_client_set_state(&common, &set); + if (err) { + ESP_LOGE(TAG, "Send Generic OnOff Set Unack failed"); + return; + } + + node->onoff = !node->onoff; + board_led_operation(0, 100, 0); +} + +void example_ble_mesh_start_example_configuration(void) +{ + esp_ble_mesh_msg_ctx_t ctx = {0}; + uint32_t opcode; + esp_err_t err; + uint8_t address[12]; + + if (last_node_idx < 4) { + ESP_LOGE(TAG, "The network has too few nodes to run this example."); + return; + } + + memcpy(address, nodes[last_node_idx - 3].uuid + 2, 6); + memcpy(address + 6, nodes[last_node_idx - 2].uuid + 2, 6); + + ctx.net_idx = prov_key.net_idx; + ctx.app_idx = prov_key.app_idx; + ctx.addr = nodes[last_node_idx - 1].unicast; + ctx.send_ttl = MSG_SEND_TTL; + opcode = ESP_BLE_MESH_VND_MODEL_OP_SET; + + err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx, opcode, + sizeof(address), (uint8_t *)address, MSG_TIMEOUT, true, MSG_ROLE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send vendor message 0x%06" PRIx32 "err: 0x%04x", opcode, err); + return; + } + +} + +static esp_err_t prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid, + uint16_t unicast, uint8_t elem_num, uint16_t net_idx) +{ + char name[11] = {0}; + int err; + + ESP_LOGI(TAG, "node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_idx, unicast, elem_num, net_idx); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_idx); + err = esp_ble_mesh_provisioner_set_node_name(node_idx, name); + if (err) { + ESP_LOGE(TAG, "%s: Set node name failed", __func__); + return ESP_FAIL; + } + + err = example_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF); + if (err) { + ESP_LOGE(TAG, "%s: Store node info failed", __func__); + return ESP_FAIL; + } + + example_ble_mesh_send_directed_forwarding_srv_control_set(&nodes[last_node_idx - 1]); + return ESP_OK; +} + +static void prov_link_open(esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGI(TAG, "%s link open", bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); +} + +static void prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason) +{ + ESP_LOGI(TAG, "%s link close, reason 0x%02x", + bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason); +} + +static void recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[BD_ADDR_LEN], + esp_ble_mesh_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + int err; + + /* Due to the API esp_ble_mesh_provisioner_set_dev_uuid_match, Provisioner will only + * use this callback to report the devices, whose device UUID starts with 0xdd & 0xdd, + * to the application layer. + */ + + ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, BD_ADDR_LEN), addr_type, adv_type); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(dev_uuid, 16)); + ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT"); + + memcpy(add_dev.addr, addr, BD_ADDR_LEN); + add_dev.addr_type = (uint8_t)addr_type; + memcpy(add_dev.uuid, dev_uuid, 16); + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + /* Note: If unprovisioned device adv packets have not been received, we should not add + device with ADD_DEV_START_PROV_NOW_FLAG set. */ + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, + ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG); + if (err) { + ESP_LOGE(TAG, "%s: Add unprovisioned device into queue failed", __func__); + } + + board_led_operation(100, 100, 100); + return; +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, err_code %d", param->provisioner_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, err_code %d", param->provisioner_prov_disable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT"); + recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + prov_link_open(param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + prov_link_close(param->provisioner_prov_link_close.bearer, param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + prov_complete(param->provisioner_prov_complete.node_idx, param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + board_led_operation(0, 0, 0); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code %d", param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code %d", param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code %d", param->provisioner_set_node_name_comp.err_code); + if (param->provisioner_set_node_name_comp.err_code == ESP_OK) { + const char *name = NULL; + name = esp_ble_mesh_provisioner_get_node_name(param->provisioner_set_node_name_comp.node_index); + if (!name) { + ESP_LOGE(TAG, "Get node name failed"); + return; + } + ESP_LOGI(TAG, "Node %d name is: %s", param->provisioner_set_node_name_comp.node_index, name); + } + break; + } + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code); + if (param->provisioner_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err = 0; + prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx; + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed"); + return; + } + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx, + ESP_BLE_MESH_VND_MODEL_ID_CLIENT, CID_ESP); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed"); + return; + } + } + break; + } + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code); + break; + default: + break; + } + + return; +} + +static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04" PRIx32, + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send config client message failed, opcode 0x%04" PRIx32, opcode); + return; + } + + node = example_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + ESP_LOGI(TAG, "composition data %s", bt_hex(param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len)); + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: + ESP_LOG_BUFFER_HEX("composition data %s", param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_STATUS: + break; + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Composition Data Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} + +static void example_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04" PRIx32, + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send generic client message failed, opcode 0x%04" PRIx32, opcode); + return; + } + + node = example_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + } + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET onoff: 0x%02x", node->onoff); + node->onoff = !node->onoff; + board_led_operation(0,0,0); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + /* If failed to receive the responses, these messages will be resend */ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + example_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET TIMEOUT, node addr(0x%04x)", node->unicast); + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a generic client status message event"); + break; + } +} + +static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_STATUS) { + ESP_LOGI(TAG, "Recv 0x06%" PRIx32 "", param->model_operation.opcode); + in_configuration_phase = 0; + ESP_LOGI(TAG, "You could click to send message by directed forwarding"); + ESP_LOGI(TAG, "After the message handled, you could click again to send message by flooding"); + } + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + if (param->model_send_comp.err_code) { + ESP_LOGE(TAG, "Failed to send message 0x%06" PRIx32 "err: %04x", param->model_send_comp.opcode, param->model_send_comp.err_code); + break; + } + ESP_LOGI(TAG, "Send 0x%06" PRIx32, param->model_send_comp.opcode); + break; + case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: + ESP_LOGI(TAG, "Receive publish message 0x%06" PRIx32, param->client_recv_publish_msg.opcode); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGW(TAG, "Client message 0x%06" PRIx32 " timeout", param->client_send_timeout.opcode); + example_ble_mesh_start_example_configuration(); + break; + default: + break; + } +} + +static void example_ble_mesh_directed_forwarding_client_cb(esp_ble_mesh_df_client_cb_event_t event, + esp_ble_mesh_df_client_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT: + ESP_LOGW(TAG, "Directed Forwarding Set, opcode 0x%04x, from 0x%04x", param->params->opcode, param->params->ctx.addr); + switch (param->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET: + if (param->recv.directed_control_status.status == STATUS_SUCCESS) { + ESP_LOGI(TAG, "Enable Directed Forwarding state success"); + } else { + ESP_LOGW(TAG, "Enable Directed Forwarding state fail"); + } + break; + } + break; + case ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT: + ESP_LOGW(TAG, "Directed Forwarding Timeout, opcode 0x%04x, to 0x%04x", param->params->opcode, param->params->ctx.addr); + esp_ble_mesh_node_info_t node = {.unicast = param->params->ctx.addr}; + example_ble_mesh_send_directed_forwarding_srv_control_set(&node); + break; + default: + break; + } +} + +static void example_ble_mesh_directed_forwarding_server_cb(esp_ble_mesh_df_server_cb_event_t event, + esp_ble_mesh_df_server_cb_param_t *param) +{ + esp_ble_mesh_df_server_table_change_t change = {0}; + esp_ble_mesh_uar_t path_origin; + esp_ble_mesh_uar_t path_target; + + if (event == ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT) { + memcpy(&change, ¶m->value.table_change, sizeof(esp_ble_mesh_df_server_table_change_t)); + + switch (change.action) { + case ESP_BLE_MESH_DF_TABLE_ADD: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Established a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + } + break; + case ESP_BLE_MESH_DF_TABLE_REMOVE: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Remove a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + } + break; + default: + ESP_LOGW(TAG, "Unknown action %d", change.action); + } + } + + return; +} + +static esp_err_t ble_mesh_init(void) +{ + uint8_t match[2] = {0xaa, 0x55}; + esp_err_t err = ESP_OK; + + prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY; + prov_key.app_idx = APP_KEY_IDX; + memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key)); + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb); + esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb); + esp_ble_mesh_register_df_client_callback(example_ble_mesh_directed_forwarding_client_cb); + esp_ble_mesh_register_df_server_callback(example_ble_mesh_directed_forwarding_server_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err); + return err; + } + + err = esp_ble_mesh_client_model_init(&vnd_models[0]); + if (err) { + ESP_LOGE(TAG, "Failed to initialize vendor client"); + return err; + } + + err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set matching device uuid (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh provisioner (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to add local AppKey (err %d)", err); + return err; + } + + err = esp_ble_mesh_enable_directed_forwarding(ESP_BLE_MESH_KEY_PRIMARY, ESP_BLE_MESH_DIRECTED_FORWARDING_ENABLED, ESP_BLE_MESH_DIRECTED_RELAY_ENABLED); /* Enable Directed Forwarding on self */ + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable directed forwarding(err %d)", err); + return err; + } + + example_ble_mesh_store_node_info(dev_uuid, 0x01, 1, 0); + + ESP_LOGI(TAG, "BLE Mesh Provisioner initialized"); + board_led_operation(0,0,0); + return err; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + /* Device uuis will be filled with bd address at dev_uuid + 2 */ + ble_mesh_get_dev_uuid(dev_uuid); + + ESP_LOG_BUFFER_HEX(TAG":Provisioner bd address: ", dev_uuid + 2, BD_ADDR_LEN); + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults new file mode 100644 index 0000000000..c3310f37bf --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults @@ -0,0 +1,23 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_CTRL_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BLE_MESH_DF_CLI=y +CONFIG_BLE_MESH_DF_SRV=y diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c3 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..b64e6068ee --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c3 @@ -0,0 +1,17 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c6 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..58ccc4d7a9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32c6 @@ -0,0 +1,19 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32h2 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..eeb1aec96e --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32h2 @@ -0,0 +1,29 @@ +# ESP32H2-specific +##Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=3 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=3 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_SELF_TEST=y +CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK=y +CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=80 +CONFIG_BLE_MESH_MAX_PROV_NODES=80 + +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# end of ESP32H2-specific diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32s3 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..b64e6068ee --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/sdkconfig.defaults.esp32s3 @@ -0,0 +1,17 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt new file mode 100644 index 0000000000..884a4ed7df --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/CMakeLists.txt new file mode 100644 index 0000000000..13a56c69f2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "main.c" + "board.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/Kconfig.projbuild new file mode 100644 index 0000000000..cbab996ec2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 if IDF_TARGET_ESP32 + default BLE_MESH_ESP32C3_DEV if IDF_TARGET_ESP32C3 + default BLE_MESH_ESP32S3_DEV if IDF_TARGET_ESP32S3 + default BLE_MESH_ESP32C6_DEV if IDF_TARGET_ESP32C6 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP32C3_DEV + bool "ESP32C3-DevKitC" + depends on IDF_TARGET_ESP32C3 + + config BLE_MESH_ESP32S3_DEV + bool "ESP32S3-DevKitC" + depends on IDF_TARGET_ESP32S3 + + config BLE_MESH_ESP32C6_DEV + bool "ESP32C6-DevKitC" + depends on IDF_TARGET_ESP32C6 + + config BLE_MESH_ESP32H2_DEV + bool "ESP32H2-DevKitC" + depends on IDF_TARGET_ESP32H2 + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.c b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.c new file mode 100644 index 0000000000..e895db0347 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.c @@ -0,0 +1,78 @@ +/* board.c - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "driver/gpio.h" +#include "esp_log.h" +#include "board.h" +#include "esp_timer.h" +#include "led_strip_encoder.h" +#include "iot_button.h" + +#include "mesh/adapter.h" + +#define TAG "BOARD" +#define BUTTON_ACTIVE_LEVEL 0 + +esp_timer_handle_t led_timer_hdl; + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b) +{ + rmt_led_set(r,g,b); +} + +static void led_timer_callback(void* arg) +{ + board_led_operation(0,0,0); +} + +static void esp_led_timer_init(void) +{ + const esp_timer_create_args_t led_timer_args = { + .callback = &led_timer_callback, + .arg = NULL, + .name = "led timer", + }; + + ESP_ERROR_CHECK(esp_timer_create(&led_timer_args, &led_timer_hdl)); +} + +void board_led_operation_auto_close(uint8_t r, uint8_t g, uint8_t b, uint32_t ms) +{ + esp_timer_stop(led_timer_hdl); + board_led_operation(r,g,b); + esp_timer_start_once(led_timer_hdl, ms * 1000); +} + +static void board_led_init(void) +{ + rmt_encoder_init(); + esp_led_timer_init(); +} + +static void button_tap_cb(void* arg) +{ + ESP_LOGI(TAG, "tap cb (%s)", (char *)arg); +} + +static void board_button_init(void) +{ + button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL); + if (btn_handle) { + iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE"); + } +} + +void board_init(void) +{ + board_led_init(); + board_button_init(); +} diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.h b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.h new file mode 100644 index 0000000000..d468ce0029 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/board.h @@ -0,0 +1,47 @@ +/* board.h - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#elif defined(CONFIG_BLE_MESH_ESP32C3_DEV) +#define LED_R GPIO_NUM_8 +#define LED_G GPIO_NUM_8 +#define LED_B GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32S3_DEV) +#define LED_R GPIO_NUM_47 +#define LED_G GPIO_NUM_47 +#define LED_B GPIO_NUM_47 +#elif defined(CONFIG_BLE_MESH_ESP32C6_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32H2_DEV) +#define LED_R GPIO_NUM_8 +#define LED_G GPIO_NUM_8 +#define LED_B GPIO_NUM_8 +#endif + +#define LED_ON 1 +#define LED_OFF 0 +#define BUTTON_IO_NUM GPIO_NUM_9 + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b); +void board_led_operation_auto_close(uint8_t r, uint8_t g, uint8_t b, uint32_t ms); +void board_init(void); + +#endif diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/main.c b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/main.c new file mode 100644 index 0000000000..63c329e649 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/main.c @@ -0,0 +1,501 @@ +/* main.c - Application main entry point */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_bt.h" + +#include "mesh/adapter.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" +#include "esp_ble_mesh_df_model_api.h" + +#include "board.h" +#include "ble_mesh_example_init.h" + +#define TAG "EXAMPLE" + +#define CID_ESP 0x02E5 +#define APP_KEY_IDX 0x0000 +#define APP_KEY_OCTET 0x12 + +#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT 0x0000 +#define ESP_BLE_MESH_VND_MODEL_ID_SERVER 0x0001 + +#define ESP_BLE_MESH_VND_MODEL_OP_SET ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP) +#define ESP_BLE_MESH_VND_MODEL_OP_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP) + +extern int bt_mesh_test_update_white_list(struct bt_mesh_white_list *wl); +extern int bt_mesh_test_stop_scanning(void); +extern int bt_mesh_test_start_scanning(bool wl_en); + +static uint8_t dev_uuid[16] = { 0xaa, 0x55 }; +static uint8_t app_key[16] = {0}; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_ENABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +#if CONFIG_BLE_MESH_DF_SRV +static esp_ble_mesh_df_srv_t directed_forwarding_server = { + .directed_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), + .default_rssi_threshold = (-80), + .rssi_margin = 20, + .directed_node_paths = 20, + .directed_relay_paths = 20, +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .directed_proxy_paths = 20, +#else + .directed_proxy_paths = 0, +#endif +#if defined(CONFIG_BLE_MESH_FRIEND) + .directed_friend_paths = 20, +#else + .directed_friend_paths = 0, +#endif + .path_monitor_interval = 120, + .path_disc_retry_interval = 300, + .path_disc_interval = ESP_BLE_MESH_PATH_DISC_INTERVAL_30_SEC, + .lane_disc_guard_interval = ESP_BLE_MESH_LANE_DISC_GUARD_INTERVAL_10_SEC, + .directed_ctl_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_ctl_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), +}; +#endif + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_0 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), +#if CONFIG_BLE_MESH_DF_SRV + ESP_BLE_MESH_MODEL_DF_SRV(&directed_forwarding_server), +#endif + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0), +}; + +static esp_ble_mesh_model_op_t vnd_op[] = { + ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_SET, 2), + ESP_BLE_MESH_MODEL_OP_END, +}; + +static esp_ble_mesh_model_t vnd_models[] = { + ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_SERVER, + vnd_op, NULL, NULL), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +/* Disable OOB security for SILabs Android app */ +static esp_ble_mesh_prov_t provision = { + .uuid = dev_uuid, +#if 0 + .output_size = 4, + .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER, + .input_actions = ESP_BLE_MESH_PUSH, + .input_size = 4, +#else + .output_size = 0, + .output_actions = 0, +#endif +}; + +static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08" PRIx32, flags, iv_index); + esp_ble_mesh_node_add_local_app_key(app_key, net_idx, APP_KEY_IDX); + board_led_operation(0, 0,0); +} + +static void example_change_led_state(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff) +{ + uint16_t primary_addr = esp_ble_mesh_get_primary_element_address(); + uint8_t elem_count = esp_ble_mesh_get_element_count(); + uint8_t i; + + if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + for (i = 0; i < elem_count; i++) { + if (ctx->recv_dst == (primary_addr + i)) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + // Receive a message send by directed forwarding. + board_led_operation_auto_close(0,0,100,2000); + } else { + // Receive a message send by flooding. + board_led_operation_auto_close(100,0,0,2000); + } + } + } + } + } else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) { + if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + /* Receive a message send by directed forwarding. */ + board_led_operation_auto_close(0,0,100,2000); + } else { + /* Receive a message send by flooding. */ + board_led_operation_auto_close(100,0,0,2000); + } + } + } + } else if (ctx->recv_dst == 0xFFFF) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + /* Receive a message send by directed forwarding. */ + board_led_operation_auto_close(0,0,100,2000); + } else { + /* Receive a message send by flooding. */ + board_led_operation_auto_close(100,0,0,2000); + } + } + } +} + +static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + esp_ble_mesh_server_recv_gen_onoff_set_t *set) +{ + esp_ble_mesh_gen_onoff_srv_t *srv = model->user_data; + + switch (ctx->recv_op) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + if (set->op_en == false) { + srv->state.onoff = set->onoff; + } else { + /* TODO: Delay and state transition */ + srv->state.onoff = set->onoff; + } + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + } + esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE); + example_change_led_state(model, ctx, srv->state.onoff); + break; + default: + break; + } +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"); + prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code); + break; + case ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT:{ + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->node_add_app_key_comp.err_code); + if (param->node_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err = 0; + uint8_t app_idx = param->node_add_app_key_comp.app_idx; + if (app_idx == APP_KEY_IDX) { + err = esp_ble_mesh_node_bind_app_key_to_local_model(esp_ble_mesh_get_primary_element_address(), ESP_BLE_MESH_CID_NVAL, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, APP_KEY_IDX); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed %d", err); + return; + } + err = esp_ble_mesh_node_bind_app_key_to_local_model(esp_ble_mesh_get_primary_element_address(), CID_ESP, + ESP_BLE_MESH_VND_MODEL_ID_SERVER, APP_KEY_IDX); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed %d", err); + return; + } + } + } + board_led_operation_auto_close(50,50,50, 1000); + break; + } + + default: + break; + } +} + +static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event, + esp_ble_mesh_generic_server_cb_param_t *param) +{ + esp_ble_mesh_gen_onoff_srv_t *srv; + ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04" PRIx32 ", src 0x%04x, dst 0x%04x", + event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst); + + switch (event) { + case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff); + example_change_led_state(param->model, ¶m->ctx, param->value.state_change.onoff_set.onoff); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + srv = param->model->user_data; + ESP_LOGI(TAG, "onoff 0x%02x", srv->state.onoff); + example_handle_gen_onoff_msg(param->model, ¶m->ctx, NULL); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x, tid 0x%02x", param->value.set.onoff.onoff, param->value.set.onoff.tid); + if (param->value.set.onoff.op_en) { + ESP_LOGI(TAG, "trans_time 0x%02x, delay 0x%02x", + param->value.set.onoff.trans_time, param->value.set.onoff.delay); + } + example_handle_gen_onoff_msg(param->model, ¶m->ctx, ¶m->value.set.onoff); + } + break; + default: + ESP_LOGE(TAG, "Unknown Generic Server event 0x%02x", event); + break; + } +} + +static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param) +{ + if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) { + switch (param->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD"); + ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x", + param->value.state_change.appkey_add.net_idx, + param->value.state_change.appkey_add.app_idx); + ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND"); + ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_app_bind.element_addr, + param->value.state_change.mod_app_bind.app_idx, + param->value.state_change.mod_app_bind.company_id, + param->value.state_change.mod_app_bind.model_id); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD"); + ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_sub_add.element_addr, + param->value.state_change.mod_sub_add.sub_addr, + param->value.state_change.mod_sub_add.company_id, + param->value.state_change.mod_sub_add.model_id); + break; + default: + break; + } + } +} + +static void example_ble_mesh_directed_forwarding_server_cb(esp_ble_mesh_df_server_cb_event_t event, + esp_ble_mesh_df_server_cb_param_t *param) +{ + esp_ble_mesh_df_server_table_change_t change = {0}; + esp_ble_mesh_uar_t path_origin; + esp_ble_mesh_uar_t path_target; + + if (event == ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT) { + memcpy(&change, ¶m->value.table_change, sizeof(esp_ble_mesh_df_server_table_change_t)); + + switch (change.action) { + case ESP_BLE_MESH_DF_TABLE_ADD: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Established a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + // board_led_operation(0, 0, 100); + + } + break; + case ESP_BLE_MESH_DF_TABLE_REMOVE: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Remove a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + board_led_operation(0, 0, 0); + } + break; + default: + ESP_LOGW(TAG, "Unknown action %d", change.action); + } + } + + return; +} + +static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event, + esp_ble_mesh_model_cb_param_t *param) +{ + int i; + struct bt_mesh_white_list wl; + // ESP_LOGI(TAG, "event: %04x opcode %06x", event, param->model_operation.opcode); + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_SET) { + uint8_t *msg = (uint8_t *)param->model_operation.msg; + uint16_t len = param->model_operation.length; + ESP_LOGI(TAG, "recv len %d", len); + esp_err_t err = esp_ble_mesh_server_model_send_msg(&vnd_models[0], + param->model_operation.ctx, ESP_BLE_MESH_VND_MODEL_OP_STATUS, + sizeof(uint16_t), (uint8_t *)&len); + if (err) { + ESP_LOGE(TAG, "Failed to send message 0x%06x", ESP_BLE_MESH_VND_MODEL_OP_STATUS); + } + + wl.add_remove = BLE_MESH_WHITELIST_ADD; + wl.addr_type = BLE_MESH_ADDR_PUBLIC; + wl.update_wl_comp_cb = NULL; + bt_mesh_test_stop_scanning(); + for (i = 0; i < len; i+=6) { + memcpy(wl.remote_bda, msg + i , 6); + bt_mesh_test_update_white_list(&wl); + } + bt_mesh_test_start_scanning(true); + } + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + if (param->model_send_comp.err_code) { + ESP_LOGE(TAG, "Failed to send message 0x%06" PRIx32, param->model_send_comp.opcode); + break; + } + ESP_LOGI(TAG, "Send 0x%06" PRIx32, param->model_send_comp.opcode); + break; + default: + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + + memset(app_key, APP_KEY_OCTET, sizeof(app_key)); + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb); + esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb); + esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb); + esp_ble_mesh_register_df_server_callback(example_ble_mesh_directed_forwarding_server_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err); + return err; + } + + err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV|ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh node (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(0, 0, 0); + + return err; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + ble_mesh_get_dev_uuid(dev_uuid); + + ESP_LOG_BUFFER_HEX(TAG":Provisioner bd address: ", dev_uuid + 2, BD_ADDR_LEN); + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults new file mode 100644 index 0000000000..b8552a6969 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults @@ -0,0 +1,22 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_CTRL_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_SELF_TEST=y +CONFIG_BLE_MESH_TEST_USE_WHITE_LIST=y +CONFIG_BLE_MESH_DF_SRV=y diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c3 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c6 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32c6 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32h2 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32h2 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32s3 b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/sdkconfig.defaults.esp32s3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md new file mode 100644 index 0000000000..56d16805a8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md @@ -0,0 +1,318 @@ +# 1. Introduction +## 1.1 Basic Knowledge +### 1.1.1 Data propagation in Bluetooth LE-Mesh v1.0 +In Bluetooth LE-Mesh v1.0, messages in the network are propagated through bounded flooding, where bounded refers to the limited propagation range determined by the TTL (Time to Live) value, and flooding means that every receiving node participating in the message forwarding within the valid TTL range. + +### 1.1.2 Data propagation in Bluetooth LE-Mesh v1.1 +In Bluetooth LE-Mesh v1.1, messages in the network can be propagated through routing. This example demonstrates the Directed Forwarding method. Messages propagated using Directed Forwarding involve only those nodes on the path for forwarding, while other nodes do not participate in the forwarding. + +### 1.1.3 Creating a path +Creating a path in the Espressif IDF Bluetooth LE-Mesh v1.1 protocol stack is straightforward. By marking the `send_tag` as `ESP_BLE_MESH_TAG_USE_DIRECTED` when sending a message, the protocol stack will actively check whether there is an existing path to reach the destination node. If not, the message will be sent using flooding first and then a path to the destination node will be requested. Once the path is successfully created, subsequent messages will be sent using routing. + +### 1.1.4 Learning more about Directed Forwarding +For more information about Directed Forwarding, please refer to the detailed [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/esp-ble-mesh/ble-mesh-index.html) in the Espressif IDF document. + +## 1.2 Example Description +### 1.2.1 Directory Structure and Explanation +``` +directed_forwarding +├── df_client +│ ├── CMakeLists.txt +│ └── main +│ ├── board.c +│ ├── board.h +│ ├── CMakeLists.txt +│ ├── Kconfig.projbuild +│ └── main.c +├── df_server +│ ├── CMakeLists.txt +│ └── main +│ ├── board.c +│ ├── board.h +│ ├── CMakeLists.txt +│ ├── Kconfig.projbuild +│ └── main.c +├── tutorial +│ ├── images +│ └── BLE_Mesh_Directed_Forwarding_Example_Walkthrough.md +└── README.md +``` +Under the directed_forwarding project, there are two main directories: df Client and df Server. In this example, the df Client assumes the roles of Provisioner, Path Origin, and Generic OnOff Client. The df Server assumes the roles of Generic OnOff Server and Path Target. + +### 1.2.2 Prerequisites +- One device running the `df_client` project. +- One or more devices running the `df_server` project. + +### 1.2.3 Running Phenomenon +The devices running the `df_client` project are referred to as the Provisioner node or Path Origin node in the following description. + +The devices running the `df_server` project are referred to as Nodes. + +When the Provisioner's LED is white, it indicates that it is provisioning a specific Node. When the provisioning process is complete, the LED of the provisioned Node will turn to white, and this process continues until all nodes join the network and the LEDs are white. + +The last node to join the network serves as the Path Target. Once all nodes have joined the network, the button on the Provisioner should be pressed for the first time. The Provisioner will send VendorModel messages to the Path Target node in order to add the bd_address of the second-to-last and third-to-last nodes to the Path Target's receive whitelist. This allows the Path Target to only receive messages from these two nodes, thus avoiding receiving messages from the Path Origin (Provisioner) within the one hop range. + +Once the configuration is complete, the button on the Provisioner should be pressed again for the second time. This will trigger the sending of a Generic Onoff Set message, which is expected to be sent using routing. However, since there is no existing path, it will also trigger a path establishment. After the path is successfully established, the LED on the nodes along the path will change from white to blue. However, the light on the Path Target will be green because there is no established path at the time of message sending. Therefore, the sending method will be changed from routing to flooding by the Mesh stack. Upon pressing the button for the third time, a Generic Onoff Set message will be sent using flooding, and the light on the Path Target will be green. On the fourth button press, a Generic Onoff Set message will be sent using routing, and the light on the Path Target will be blue. + +### 1.2.4 Message Sequence +![Packet interaction](images/directed_forwarding_sequence.png) + +### 1.2.5 Code Explanation +#### 1.2.5.1 Onoff Client +First, declare and register `Directed Forwarding Client` and `Directed Forwarding Server` as shown below: +```c +#if CONFIG_BLE_MESH_DF_CLI +static esp_ble_mesh_client_t directed_forwarding_client; +#endif + +#if CONFIG_BLE_MESH_DF_SRV +static esp_ble_mesh_df_srv_t directed_forwarding_server = { + .directed_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), + .default_rssi_threshold = (-80), + .rssi_margin = 20, + .directed_node_paths = 20, + .directed_relay_paths = 20, +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .directed_proxy_paths = 20, +#else + .directed_proxy_paths = 0, +#endif +#if defined(CONFIG_BLE_MESH_FRIEND) + .directed_friend_paths = 20, +#else + .directed_friend_paths = 0, +#endif + .path_monitor_interval = 120, + .path_disc_retry_interval = 300, + .path_disc_interval = ESP_BLE_MESH_PATH_DISC_INTERVAL_30_SEC, + .lane_disc_guard_interval = ESP_BLE_MESH_LANE_DISC_GUARD_INTERVAL_10_SEC, + .directed_ctl_net_transmit = ESP_BLE_MESH_TRANSMIT(1, 100), + .directed_ctl_relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 100), +}; +#endif + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), +#if CONFIG_BLE_MESH_DF_CLI + ESP_BLE_MESH_MODEL_DF_CLI(&directed_forwarding_client), +#endif +#if CONFIG_BLE_MESH_DF_SRV + ESP_BLE_MESH_MODEL_DF_SRV(&directed_forwarding_server), +#endif + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; + +``` +The Directed Forwarding Client is used for configuring parameters of the Directed Forwarding Server. Every routing node must have a Directed Forwarding Server, but it is not necessary to have a Directed Forwarding Client. + +The parameters in the Directed Forwarding Server are as follows: +- The `directed_net_transmit` parameter controls the broadcasting parameters for sending non-control messages using Directed Forwarding technology. In this example, `ESP_BLE_MESH_TRANSMIT(1, 100)` indicates 1 retransmission and an interval of 100 milliseconds for broadcasting. This value is the default and generally should not be changed. +- The `directed_relay_retransmit` parameter controls the broadcasting parameters for forwarding non-control messages using Directed Forwarding technology. In this example, `ESP_BLE_MESH_TRANSMIT(2, 100)` indicates 2 retransmissions and an interval of 100 milliseconds for broadcasting. This value is the default and generally should not be changed. +- The `default_rssi_threshold` and `rssi_margin` are used to control the received RSSI strength of path requests during path establishment. The RSSI strength of the path requests that nodes can accept should be greater than the sum of `default_rssi_threshold` and `rssi_margin`. +- The `directed_node_paths` specifies the minimum number of paths when the node is either the starting or destination node in the path. Its value should be no less than 20. +- The `directed_relay_paths` specifies the minimum number of paths when the node is an intermediate node in the path. Its value should be no less than 20. +- The `directed_proxy_paths` specifies the minimum number of paths when the node acts as a proxy server to assist proxy clients. When proxy servers are not supported, the value should be 0; otherwise, it should be no less than 20. +- The `directed_friend_paths` specifies the minimum number of paths when the node acts as a friend node to assist low-power nodes. When friend nodes are not supported, the value should be 0; otherwise, it should be no less than 20. +- The `path_monitor_interval` specifies the timeout for path monitoring in seconds. +- The `path_disc_retry_interval` specifies the timeout for retrying path discovery when it fails in seconds. +- The `path_disc_interval` specifies the timeout for paths. +- The `lane_disc_guard_interval` specifies the minimum time interval between two path requests. +- The `directed_ctl_net_transmit` parameter controls the broadcasting parameters for sending control messages using Directed Forwarding technology. In this example, `ESP_BLE_MESH_TRANSMIT(1, 100)` indicates 1 retransmission and an interval of 100 milliseconds for broadcasting. This value is the default and generally should not be changed. +- The `directed_ctl_relay_retransmit` parameter controls the broadcasting parameters for forwarding control messages using Directed Forwarding technology. In this example, `ESP_BLE_MESH_TRANSMIT(2, 100)` indicates 2 retransmissions and an interval of 100 milliseconds for broadcasting. This value is the default and generally should not be changed. + +After registering the Directed Forwarding Client and Directed Forwarding Server, their callback functions also need to be registered. Here is an example code: +```c +static esp_err_t ble_mesh_init(void) +{ + // ... + esp_ble_mesh_register_df_client_callback(example_ble_mesh_directed_forwarding_client_cb); + esp_ble_mesh_register_df_server_callback(example_ble_mesh_directed_forwarding_server_cb); + // ... +} +``` +The implementation of the callback function `example_ble_mesh_directed_forwarding_client_cb` is as follows: +```c +static void example_ble_mesh_directed_forwarding_client_cb(esp_ble_mesh_df_client_cb_event_t event, + esp_ble_mesh_df_client_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT: + ESP_LOGW(TAG, "Directed Forwarding Set, opcode 0x%04x, from 0x%04x", param->params->opcode, param->params->ctx.addr); + switch (param->params->opcode) { + case ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET: + if (param->recv.directed_control_status.status == STATUS_SUCCESS) { + ESP_LOGI(TAG, "Enable Directed Forwarding state success"); + } else { + ESP_LOGW(TAG, "Enable Directed Forwarding state fail"); + } + break; + } + break; + case ESP_BLE_MESH_DF_CLIENT_SEND_TIMEOUT_EVT: + ESP_LOGW(TAG, "Directed Forwarding Timeout, opcode 0x%04x, to 0x%04x", param->params->opcode, param->params->ctx.addr); + esp_ble_mesh_node_info_t node = {.unicast = param->params->ctx.addr}; + example_ble_mesh_send_directed_forwarding_srv_control_set(&node); + break; + default: + break; + } +} +``` +The event `ESP_BLE_MESH_DF_CLIENT_RECV_SET_RSP_EVT` triggers the opcode `ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_SET` within the callback function. This event occurs when the Directed Forwarding Client sends a Directed Forwarding Control Set message to the Directed Forwarding Server and receives a response. The Directed Forwarding functionality is disabled by default on routing nodes, so the Directed Forwarding Client needs to enable this functionality on each routing node, sequentially. + +The implementation of the callback function `example_ble_mesh_directed_forwarding_server_cb` is as follows: +```c +static void example_ble_mesh_directed_forwarding_server_cb(esp_ble_mesh_df_server_cb_event_t event, + esp_ble_mesh_df_server_cb_param_t *param) +{ + esp_ble_mesh_df_server_table_change_t change = {0}; + esp_ble_mesh_uar_t path_origin; + esp_ble_mesh_uar_t path_target; + + if (event == ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT) { + memcpy(&change, ¶m->value.table_change, sizeof(esp_ble_mesh_df_server_table_change_t)); + + switch (change.action) { + case ESP_BLE_MESH_DF_TABLE_ADD: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Established a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + } + break; + case ESP_BLE_MESH_DF_TABLE_REMOVE: { + memcpy(&path_origin, &change.df_table_info.df_table_entry_add_remove.path_origin, sizeof(path_origin)); + memcpy(&path_target, &change.df_table_info.df_table_entry_add_remove.path_target, sizeof(path_target)); + ESP_LOGI(TAG, "Remove a path from 0x%04x to 0x%04x", path_origin.range_start, path_target.range_start); + } + break; + default: + ESP_LOGW(TAG, "Unknown action %d", change.action); + } + } + + return; +} +``` +Currently, only the `ESP_BLE_MESH_DF_SERVER_TABLE_CHANGE_EVT` event is available, which contains two actions: `ESP_BLE_MESH_DF_TABLE_ADD` and `ESP_BLE_MESH_DF_TABLE_REMOVE`. When a table entry is added to the routing table (DIRECTED_FORWARDING_TABLE), the `ESP_BLE_MESH_DF_TABLE_ADD` action is triggered, indicating the establishment of a new path. When a table entry is removed from the routing table (DIRECTED_FORWARDING_TABLE), the `ESP_BLE_MESH_DF_TABLE_REMOVE` action is triggered, indicating the termination of a path. + +The `example_ble_mesh_send_gen_onoff_set` function demonstrates how to use Directed Forwarding to send a message. +```c +void example_ble_mesh_send_gen_onoff_set(bool by_df) +{ + esp_ble_mesh_generic_client_set_state_t set = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + + if (!last_node_idx) { + ESP_LOGE(TAG, "No node provisioned"); + return; + } + + curr_node_idx = last_node_idx - 1; + + esp_ble_mesh_node_info_t *node = &nodes[curr_node_idx]; + + example_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + + if (by_df) { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_USE_DIRECTED|ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } else { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } + + ESP_LOGI(TAG, "Will send a message to node(0x%04x) with %s", node->unicast, by_df ? "DF" : "Flooding"); + + set.onoff_set.op_en = false; + set.onoff_set.onoff = node->onoff; + set.onoff_set.tid = node->tid; + node->tid++; + + err = esp_ble_mesh_generic_client_set_state(&common, &set); + if (err) { + ESP_LOGE(TAG, "Send Generic OnOff Set Unack failed"); + return; + } + + node->onoff = !node->onoff; + board_led_operation(0, 100, 0); +} + +``` +You can choose whether to use Directed Forwarding to send the Generic Onoff Set message before its transmission. Here is the code snippet: +```c + if (by_df) { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_USE_DIRECTED|ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } else { + common.ctx.send_tag |= ESP_BLE_MESH_TAG_IMMUTABLE_CRED; + } +``` +Only setting `ESP_BLE_MESH_TAG_USE_DIRECTED` in `send_tag` is necessary. Additionally, it is not recommended to set `ESP_BLE_MESH_TAG_IMMUTABLE_CRED` in practical applications, as doing so will prevent the protocol stack from actively selecting the optimal way to transmit the message. In this example, setting this bit is solely for demonstrating the difference between flooding propagation mode and routing propagation mode. + +With this, the message can be broadcasted using routing. + +This message can be broadcasted via the routing method. +#### 1.2.5.2 Onoff Server +At Onoff Server, it is important to know how to determine if a message is sent by Directed Forwarding. The code in the example is as follows: +```c +static void example_change_led_state(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff) +{ + uint16_t primary_addr = esp_ble_mesh_get_primary_element_address(); + uint8_t elem_count = esp_ble_mesh_get_element_count(); + uint8_t i; + + if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + for (i = 0; i < elem_count; i++) { + if (ctx->recv_dst == (primary_addr + i)) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + // Receive a message send by directed forwarding. + board_led_operation_auto_close(0,0,100,2000); + } else { + // Receive a message send by flooding. + board_led_operation_auto_close(100,0,0,2000); + } + } + } + } + } else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) { + if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + /* Receive a message send by directed forwarding. */ + board_led_operation_auto_close(0,0,100,2000); + } else { + /* Receive a message send by flooding. */ + board_led_operation_auto_close(100,0,0,2000); + } + } + } + } else if (ctx->recv_dst == 0xFFFF) { + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + /* Receive a message send by directed forwarding. */ + board_led_operation_auto_close(0,0,100,2000); + } else { + /* Receive a message send by flooding. */ + board_led_operation_auto_close(100,0,0,2000); + } + } + } +} +``` +The propagation source of the message can be determined during use by `ctx->recv_cred`. +```c + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + if (ctx->recv_cred == ESP_BLE_MESH_DIRECTED_CRED) { + /* Receive a message send by directed forwarding. */ + board_led_operation_auto_close(0,0,100,2000); + } else { + /* Receive a message send by flooding. */ + board_led_operation_auto_close(100,0,0,2000); + } + } +``` + +Similarly, upon receiving `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` and replying with `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS`, there is no restriction on the sending format, so once the path is established, messages are sent using Directed Forwarding. diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/images/directed_forwarding_sequence.png b/examples/bluetooth/esp_ble_mesh/directed_forwarding/tutorial/images/directed_forwarding_sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..e1f65c6e861d4ee7dbe6431214867156da440cdb GIT binary patch literal 74836 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 literal 0 HcmV?d00001 diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c index 55951da892..9ac4601074 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c @@ -168,7 +168,6 @@ static void provisioner_prov_complete(int node_index, const uint8_t uuid[16], ui .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_PROVISIONER, }; esp_ble_mesh_cfg_app_key_add_t add_key = { .net_idx = prov_info.net_idx, @@ -425,7 +424,6 @@ static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t ev .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_PROVISIONER, }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -448,7 +446,6 @@ static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t ev .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_PROVISIONER, }; esp_ble_mesh_cfg_app_key_add_t add_key = { .net_idx = prov_info.net_idx, diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/sdkconfig.defaults index ebb238db04..87249841a3 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/sdkconfig.defaults @@ -19,3 +19,5 @@ CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 CONFIG_BLE_MESH_CFG_CLI=y CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y + +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md index d1debcf72d..d64046d3b7 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md @@ -151,10 +151,8 @@ common.model = model; common.ctx.net_idx = info->net_idx; common.ctx.app_idx = 0x0000; /* not used for config messages */ common.ctx.addr = info->dst; -common.ctx.send_rel = false; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; -common.msg_role = info->role; return esp_ble_mesh_config_client_set_state(&common, &set); ``` @@ -208,7 +206,6 @@ example_msg_common_info_t info = { .app_idx = node->app_idx, .dst = node->group_addr, .timeout = 0, - .role = ROLE_PROVISIONER, }; err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false); if (err != ESP_OK) { diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c index ce2135e8cb..6fd267b9bf 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c @@ -282,7 +282,6 @@ static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { @@ -606,7 +605,6 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -629,7 +627,6 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/sdkconfig.defaults index c548289c7a..bd458f2c8f 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/sdkconfig.defaults @@ -26,3 +26,5 @@ CONFIG_BLE_MESH_CFG_CLI=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/tutorial/BLE_Mesh_Fast_Prov_Server_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/tutorial/BLE_Mesh_Fast_Prov_Server_Example_Walkthrough.md index 6474e8da89..8dc103fb38 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/tutorial/BLE_Mesh_Fast_Prov_Server_Example_Walkthrough.md +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/tutorial/BLE_Mesh_Fast_Prov_Server_Example_Walkthrough.md @@ -371,20 +371,17 @@ The Vendor Client Model calls the `esp_ble_mesh_client_model_send_msg` API to se | `ctx.app_idx` | The AppKey Index for the message encryption | | `ctx.addr` | The address of the destination nodes | | `ctx.send_ttl`| The TTL State, which determines how many times a message can be relayed| -| `ctx.send_rel`| This parameter determines whether the Model will wait for an acknowledgment after sending a message | | `opcode` | The message opcode | | `msg->len` | The length of the `msg->data`| | `msg->data` | The pointer to sent data| | `msg_timeout` | The maximum duration (4000 ms by default) that the Model waits for an acknowledgment. | |`true` | True: an acknowledgement is required; False: no acknowledgement is required | -| `msg_role` | The role of a message (node/provisioner) | ```c esp_ble_mesh_msg_ctx_t ctx = { .net_idx = info->net_idx, .app_idx = info->app_idx, .addr = info->dst, - .send_rel = false, .send_ttl = 0, }; err = esp_ble_mesh_client_model_send_msg(model, &ctx, diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c index 398b699fce..1cc61e1156 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c @@ -181,9 +181,7 @@ void example_ble_mesh_send_gen_onoff_set(void) common.ctx.app_idx = store.app_idx; common.ctx.addr = 0xFFFF; /* to all nodes */ common.ctx.send_ttl = 3; - common.ctx.send_rel = false; common.msg_timeout = 0; /* 0 indicates that timeout value from menuconfig will be used */ - common.msg_role = ROLE_NODE; set.onoff_set.op_en = false; set.onoff_set.onoff = store.onoff; diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/sdkconfig.defaults index 43dadfee98..e4e550f41e 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/sdkconfig.defaults @@ -17,3 +17,5 @@ CONFIG_BLE_MESH_PB_GATT=y CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y + +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/tutorial/BLE_Mesh_Node_OnOff_Client_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/tutorial/BLE_Mesh_Node_OnOff_Client_Example_Walkthrough.md index 74eb4d5c06..b8bb331838 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/tutorial/BLE_Mesh_Node_OnOff_Client_Example_Walkthrough.md +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/tutorial/BLE_Mesh_Node_OnOff_Client_Example_Walkthrough.md @@ -130,9 +130,7 @@ The `esp_ble_mesh_set_msg_common` function is used to set the message controllin | `ctx.app_idx` | The AppKey Index for message encryption | | `ctx.addr` | The address of the destination nodes | | `ctx.send_ttl`| The TTL State, which determines how many times a message will be relayed | -| `ctx.send_rel`| This parameter determines if the Model will wait for an acknowledgement after sending a message | | `msg_timeout` | The maximum time the Model will wait for an acknowledgement | -| `msg_role` | The role of message (node/provisioner) | > Note: > diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/sdkconfig.defaults index f285ddba62..43e38d4b06 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/sdkconfig.defaults @@ -16,3 +16,5 @@ CONFIG_BLE_MESH_NODE=y CONFIG_BLE_MESH_PB_GATT=y CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 + +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c b/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c index e7581a2a40..9eb27a655f 100644 --- a/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c @@ -33,7 +33,6 @@ #define PROV_OWN_ADDR 0x0001 #define MSG_SEND_TTL 3 -#define MSG_SEND_REL false #define MSG_TIMEOUT 0 #define MSG_ROLE ROLE_PROVISIONER @@ -181,9 +180,7 @@ static esp_err_t example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_para common->ctx.app_idx = prov_key.app_idx; common->ctx.addr = node->unicast; common->ctx.send_ttl = MSG_SEND_TTL; - common->ctx.send_rel = MSG_SEND_REL; common->msg_timeout = MSG_TIMEOUT; - common->msg_role = MSG_ROLE; return ESP_OK; } diff --git a/examples/bluetooth/esp_ble_mesh/provisioner/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/provisioner/sdkconfig.defaults index e788845430..70e2c3a107 100644 --- a/examples/bluetooth/esp_ble_mesh/provisioner/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/provisioner/sdkconfig.defaults @@ -8,6 +8,7 @@ CONFIG_CTRL_BTDM_MODEM_SLEEP=n CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y # Override some defaults of ESP BLE Mesh CONFIG_BLE_MESH=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/README.md b/examples/bluetooth/esp_ble_mesh/remote_provisioning/README.md new file mode 100644 index 0000000000..07ceb2afab --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/README.md @@ -0,0 +1,58 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | +# Remote Provisioning + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +The example is primarily used to demonstrate the new Remote Provisioning feature added in Mesh Protocol v1.1. +## How to use example + +Please refer to this [tutorial](examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md) for detailed instructions on how to run it. + +### Hardware Required +You need prepare at least three ESP series development boards. We recommend using the [ESP32-C3-DevKitM-1](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html) or [ESP32-C6-DevKitC-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/user_guide.html#). Alternatively, you can use other development boards, but ensure that each board has at least one LED and one button for operation. +### Configure the project + +``` +idf.py menuconfig +``` + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output +When a device that runs the `rpr_server` joins the network, the device that runs the `rpr_client` will have the following log output: + +``` +The Remote Provisioning Server have been provisioned, You could click button to start remote provisioning +``` +After seeing this output log, you can press the button on the device running `rpr_client` to initiate the Remote Provisioning process. + +After successfully joining the network through Remote Provisioning, the device running `rpr_client` will have the following log output: +``` +Remote Prov Client Prov Complete +Net Idx: `net index` +Node addr: `node address` +Node element num: `element num` +Node UUID: `UUID` +``` +(The content wrapped with ` ` will vary depending on the device you are actually using.) + +Afterwards, you can press the button on the device running `rpr_client` to toggle the LED settings of other devices in the network. + +## Troubleshooting + +See common troubleshooting for Directed Forwarding examples from [ESP-BLE-MESH FAQ](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/esp-ble-mesh/ble-mesh-index.html#esp-ble-mesh-faq). + +(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt new file mode 100644 index 0000000000..0f89672c6d --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt @@ -0,0 +1,11 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/CMakeLists.txt new file mode 100644 index 0000000000..5e9d189521 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(srcs "main.c" + "board.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/Kconfig.projbuild new file mode 100644 index 0000000000..cbab996ec2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 if IDF_TARGET_ESP32 + default BLE_MESH_ESP32C3_DEV if IDF_TARGET_ESP32C3 + default BLE_MESH_ESP32S3_DEV if IDF_TARGET_ESP32S3 + default BLE_MESH_ESP32C6_DEV if IDF_TARGET_ESP32C6 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP32C3_DEV + bool "ESP32C3-DevKitC" + depends on IDF_TARGET_ESP32C3 + + config BLE_MESH_ESP32S3_DEV + bool "ESP32S3-DevKitC" + depends on IDF_TARGET_ESP32S3 + + config BLE_MESH_ESP32C6_DEV + bool "ESP32C6-DevKitC" + depends on IDF_TARGET_ESP32C6 + + config BLE_MESH_ESP32H2_DEV + bool "ESP32H2-DevKitC" + depends on IDF_TARGET_ESP32H2 + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.c new file mode 100644 index 0000000000..35d76a885e --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.c @@ -0,0 +1,73 @@ +/* board.c - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "iot_button.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "board.h" + +#define TAG "BOARD" + +#define BUTTON_ACTIVE_LEVEL 0 + +extern uint8_t click_to_send_onoff_set; +extern void example_ble_mesh_send_gen_onoff_set(uint8_t onoff); +extern void example_ble_mesh_send_remote_provisioning_scan_start(void); + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_led_set(r, g, b); +#else + gpio_set_level(LED_R, r); + gpio_set_level(LED_G, g); + gpio_set_level(LED_B, b); +#endif +} + +static void board_led_init(void) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_encoder_init(); + rmt_led_set(LED_OFF,LED_OFF,LED_OFF); +#else + gpio_set_level(LED_R, LED_OFF); + gpio_set_level(LED_G, LED_OFF); + gpio_set_level(LED_B, LED_OFF); +#endif +} + +static void button_tap_cb(void* arg) +{ + static uint8_t onoff = 1; + ESP_LOGI(TAG, "tap cb (%s)", (char *)arg); + if (click_to_send_onoff_set) { + example_ble_mesh_send_gen_onoff_set(onoff); + onoff = !onoff; + } else { + example_ble_mesh_send_remote_provisioning_scan_start(); + } +} + + +static void board_button_init(void) +{ + button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL); + if (btn_handle) { + iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE"); + } +} + +void board_init(void) +{ + board_led_init(); + board_button_init(); +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.h b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.h new file mode 100644 index 0000000000..e754f6d95c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/board.h @@ -0,0 +1,51 @@ +/* board.h - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "led_strip_encoder.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#elif defined(CONFIG_BLE_MESH_ESP32C3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32S3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_47 +#elif defined(CONFIG_BLE_MESH_ESP32C6_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32H2_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#endif + +#define BUTTON_IO_NUM GPIO_NUM_9 + +#ifndef BLE_MESH_LED_STRIP_IO +#define LED_ON 1 +#else +#define LED_R 0 +#define LED_G 1 +#define LED_B 2 +#define LED_ON 100 +#endif + +#define LED_OFF 0 + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c new file mode 100644 index 0000000000..978f403a2d --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c @@ -0,0 +1,1144 @@ +/* main.c - Application main entry point */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_rpr_model_api.h" + +#include "mesh/adapter.h" +#include "ble_mesh_example_init.h" + +#include "board.h" +#define TAG "EXAMPLE" + +#define CID_ESP 0x02E5 +#define CID_NVAL 0xFFFF + +#define PROV_OWN_ADDR 0x0001 + +#define MSG_SEND_TTL 3 +#define MSG_TIMEOUT 0 +#define MSG_ROLE ROLE_PROVISIONER + +#define COMP_DATA_PAGE_0 0x00 + +#define APP_KEY_IDX 0x0000 +#define APP_KEY_OCTET 0x12 + +#define COMP_DATA_1_OCTET(msg, offset) (msg[offset]) +#define COMP_DATA_2_OCTET(msg, offset) (msg[offset + 1] << 8 | msg[offset]) + +static uint8_t dev_uuid[16]; + +/* That uuid mask used to specify the unprovision device which should be provisioning by remote provisioning */ +/* That uuid mask should be same as the dev_uuid in the ../node/main/main.c#L34 */ +static uint8_t remote_dev_uuid_match[2] = {0x55, 0x55}; +static uint16_t cur_rpr_cli_opcode; +uint8_t click_to_send_onoff_set = 0; +uint8_t message_tid = 0; +static uint16_t remote_rpr_srv_addr = 0; +typedef struct { + uint8_t uuid[16]; + uint16_t unicast; + uint8_t elem_num; + uint8_t onoff; + uint8_t *sig_model_num; + uint8_t *vnd_model_num; + uint16_t **sig_models; + uint32_t **vnd_models; +} esp_ble_mesh_node_info_t; + +static esp_ble_mesh_node_info_t nodes[CONFIG_BLE_MESH_MAX_PROV_NODES] = { + [0 ... (CONFIG_BLE_MESH_MAX_PROV_NODES - 1)] = { + .unicast = ESP_BLE_MESH_ADDR_UNASSIGNED, + .elem_num = 0, + .onoff = LED_OFF, + } +}; + +static struct esp_ble_mesh_key { + uint16_t net_idx; + uint16_t app_idx; + uint8_t app_key[16]; +} prov_key; + +#if CONFIG_BLE_MESH_RPR_CLI +static esp_ble_mesh_client_t remote_prov_client; +#endif +static esp_ble_mesh_client_t config_client; +static esp_ble_mesh_client_t onoff_client; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), +#if CONFIG_BLE_MESH_RPR_CLI + ESP_BLE_MESH_MODEL_RPR_CLI(&remote_prov_client), +#endif + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +static esp_ble_mesh_prov_t provision = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = PROV_OWN_ADDR, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +static esp_err_t example_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast, + uint8_t elem_num, uint8_t onoff_state) +{ + int i; + + if (!uuid || !ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return ESP_ERR_INVALID_ARG; + } + + /* Judge if the device has been provisioned before */ + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (!memcmp(nodes[i].uuid, uuid, 16)) { + ESP_LOGW(TAG, "%s: reprovisioned device 0x%04x", __func__, unicast); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (nodes[i].unicast == ESP_BLE_MESH_ADDR_UNASSIGNED) { + memcpy(nodes[i].uuid, uuid, 16); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + return ESP_FAIL; +} + +static esp_ble_mesh_node_info_t *example_ble_mesh_get_node_info(uint16_t unicast) +{ + int i; + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + if (nodes[i].unicast <= unicast && + nodes[i].unicast + nodes[i].elem_num > unicast) { + return &nodes[i]; + } + } + + return NULL; +} + +static esp_err_t example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common, + uint16_t unicast, + esp_ble_mesh_model_t *model, uint32_t opcode) +{ + if (!common || !unicast || !model) { + return ESP_ERR_INVALID_ARG; + } + + common->opcode = opcode; + common->model = model; + common->ctx.net_idx = prov_key.net_idx; + common->ctx.app_idx = prov_key.app_idx; + common->ctx.addr = unicast; + common->ctx.send_ttl = MSG_SEND_TTL; + common->msg_timeout = MSG_TIMEOUT; + + return ESP_OK; +} + +static esp_err_t prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid, + uint16_t unicast, uint8_t elem_num, uint16_t net_idx) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + esp_ble_mesh_node_info_t *node = NULL; + char name[11] = {0}; + int err; + + ESP_LOGI(TAG, "node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_idx, unicast, elem_num, net_idx); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_idx); + err = esp_ble_mesh_provisioner_set_node_name(node_idx, name); + if (err) { + ESP_LOGE(TAG, "%s: Set node name failed", __func__); + return ESP_FAIL; + } + + err = example_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF); + if (err) { + ESP_LOGE(TAG, "%s: Store node info failed", __func__); + return ESP_FAIL; + } + + node = example_ble_mesh_get_node_info(unicast); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Provisioning node by common methold"); + ESP_LOGI(TAG, "That node will be act as remote provisioning server to help Provisioner to provisioning another node"); + + example_ble_mesh_set_msg_common(&common, unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Send config comp data get failed", __func__); + return ESP_FAIL; + } + + return ESP_OK; +} + +static void prov_link_open(esp_ble_mesh_prov_bearer_t bearer) +{ + ESP_LOGI(TAG, "%s link open", bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + board_led_operation(LED_OFF, LED_ON, LED_OFF); +} + +static void prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason) +{ + ESP_LOGI(TAG, "%s link close, reason 0x%02x", + bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason); +} + +static void recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[BD_ADDR_LEN], + esp_ble_mesh_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + int err; + + /* Due to the API esp_ble_mesh_provisioner_set_dev_uuid_match, Provisioner will only + * use this callback to report the devices, whose device UUID starts with 0xdd & 0xdd, + * to the application layer. + */ + + ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, BD_ADDR_LEN), addr_type, adv_type); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(dev_uuid, 16)); + ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT"); + + memcpy(add_dev.addr, addr, BD_ADDR_LEN); + add_dev.addr_type = (uint8_t)addr_type; + memcpy(add_dev.uuid, dev_uuid, 16); + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + /* Note: If unprovisioned device adv packets have not been received, we should not add + device with ADD_DEV_START_PROV_NOW_FLAG set. */ + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, + ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG); + if (err) { + ESP_LOGE(TAG, "%s: Add unprovisioned device into queue failed", __func__); + } + + return; +} + +void example_ble_mesh_send_gen_onoff_set(uint8_t onoff) +{ + esp_ble_mesh_generic_client_set_state_t set = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + + example_ble_mesh_set_msg_common(&common, 0xffff, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK); + + set.onoff_set.op_en = false; + set.onoff_set.onoff = onoff; + set.onoff_set.tid = message_tid++; + + err = esp_ble_mesh_generic_client_set_state(&common, &set); + if (err) { + ESP_LOGE(TAG, "Send Generic OnOff Set Unack failed"); + return; + } +} + +void example_ble_mesh_send_remote_provisioning_scan_start(void) +{ + + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + + if (!remote_rpr_srv_addr) { + ESP_LOGE(TAG, "No valid remote provisioning server address"); + return; + } + + /* Send a ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET to get the scan status of remote provisioning server */ + example_ble_mesh_set_msg_common(&common, remote_rpr_srv_addr, remote_prov_client.model, ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET); + err = esp_ble_mesh_rpr_client_send(&common, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg: Scan Get"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET; +} + + +static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node, const uint8_t *data, uint16_t length) +{ + uint16_t cid, pid, vid, crpl, feat; + uint16_t loc, model_id, company_id; + uint8_t nums, numv; + uint16_t offset; + uint8_t seq = 0; + int i; + + if (!node || !data) { + ESP_LOGE(TAG, "Invalid Argument"); + return; + } + + cid = COMP_DATA_2_OCTET(data, 0); + pid = COMP_DATA_2_OCTET(data, 2); + vid = COMP_DATA_2_OCTET(data, 4); + crpl = COMP_DATA_2_OCTET(data, 6); + feat = COMP_DATA_2_OCTET(data, 8); + offset = 10; + + node->sig_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); + if (!node->sig_model_num) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + + node->vnd_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); + if (!node->vnd_model_num) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + + node->sig_models = (uint16_t **)calloc(node->elem_num, sizeof(uint16_t*)); + if (!node->sig_models) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + + node->vnd_models = (uint32_t **)calloc(node->elem_num, sizeof(uint32_t*)); + if (!node->sig_models) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + + ESP_LOGI(TAG, "********************** Composition Data Start **********************"); + ESP_LOGI(TAG, "* CID 0x%04x, PID 0x%04x, VID 0x%04x, CRPL 0x%04x, Features 0x%04x *", cid, pid, vid, crpl, feat); + for (; offset < length; ) { + loc = COMP_DATA_2_OCTET(data, offset); + nums = COMP_DATA_1_OCTET(data, offset + 2); + numv = COMP_DATA_1_OCTET(data, offset + 3); + node->sig_model_num[seq] = nums; + node->vnd_model_num[seq] = numv; + + if (nums) { + node->sig_models[seq] = (uint16_t *)calloc(nums, sizeof(uint16_t)); + if (!(node->sig_models[seq])) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + } else { + node->sig_models[seq] = NULL; + } + + if (numv) { + node->vnd_models[seq] = (uint32_t *)calloc(numv, sizeof(uint32_t)); + if (!(node->vnd_models[seq])) { + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; + } + } else { + node->vnd_models[seq] = NULL; + } + + offset += 4; + ESP_LOGI(TAG, "* Loc 0x%04x, NumS 0x%02x, NumV 0x%02x *", loc, nums, numv); + for (i = 0; i < nums; i++) { + model_id = COMP_DATA_2_OCTET(data, offset); + node->sig_models[seq][i] = model_id; + ESP_LOGI(TAG, "* SIG Model ID 0x%04x *", model_id); + offset += 2; + } + for (i = 0; i < numv; i++) { + company_id = COMP_DATA_2_OCTET(data, offset); + model_id = COMP_DATA_2_OCTET(data, offset + 2); + node->vnd_models[seq][i] = company_id << 16 | model_id; + ESP_LOGI(TAG, "* Vendor Model ID 0x%04x, Company ID 0x%04x *", model_id, company_id); + offset += 4; + } + seq++; + } + ESP_LOGI(TAG, "*********************** Composition Data End ***********************"); +} + +static bool example_ble_mesh_query_element_have_model(uint16_t elem_addr, uint16_t model_id, uint16_t company_id) +{ + esp_ble_mesh_node_info_t *node = NULL; + uint8_t elem_idx = 0; + uint8_t model_num = 0; + int i = 0; + + node = example_ble_mesh_get_node_info(elem_addr); + + elem_idx = elem_addr - node->unicast; + + if (company_id == CID_NVAL) { + model_num = node->sig_model_num[elem_idx]; + for (i = 0; i < model_num; i++) { + if (node->sig_models[elem_idx][i] == model_id) { + return true; + } + } + } else { + model_num = node->vnd_model_num[elem_idx]; + for (i = 0; i < model_num; i++) { + if (node->vnd_models[elem_idx][i] == (company_id << 16 | model_id)) { + return true; + } + } + } + + return false; +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, err_code %d", param->provisioner_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, err_code %d", param->provisioner_prov_disable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT"); + recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + prov_link_open(param->provisioner_prov_link_open.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + prov_link_close(param->provisioner_prov_link_close.bearer, param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + prov_complete(param->provisioner_prov_complete.node_idx, param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code %d", param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code %d", param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code %d", param->provisioner_set_node_name_comp.err_code); + if (param->provisioner_set_node_name_comp.err_code == ESP_OK) { + const char *name = NULL; + name = esp_ble_mesh_provisioner_get_node_name(param->provisioner_set_node_name_comp.node_index); + if (!name) { + ESP_LOGE(TAG, "Get node name failed"); + return; + } + ESP_LOGI(TAG, "Node %d name is: %s", param->provisioner_set_node_name_comp.node_index, name); + } + break; + } + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code); + if (param->provisioner_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err = 0; + prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx; + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed"); + return; + } + } + break; + } + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code); + break; + default: + break; + } + + return; +} + +static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04" PRIx32, + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send config client message failed, opcode 0x%04" PRIx32, opcode); + return; + } + + node = example_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + ESP_LOGI(TAG, "composition data %s", bt_hex(param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len)); + example_ble_mesh_parse_node_comp_data(node, param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len); + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, addr, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + + if (!example_ble_mesh_query_element_have_model(addr, ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, CID_NVAL)) { + ESP_LOGE(TAG, "Element (addr: 0x%04x) does not support onoff srv model"); + return; + } + + example_ble_mesh_set_msg_common(&common, addr, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + + if (!example_ble_mesh_query_element_have_model(addr, ESP_BLE_MESH_MODEL_ID_RPR_SRV, CID_NVAL)) { + if (remote_rpr_srv_addr) { + ESP_LOGI(TAG, "The last node have been provisioned, You could click button to send Generic Onoff Set"); + click_to_send_onoff_set = 1; + } else { + ESP_LOGE(TAG, "Element (addr: 0x%04x) does not support remote provisioning srv model"); + } + } else { + click_to_send_onoff_set = 0; + ESP_LOGI(TAG, "The Remote Provisioning Server have been provisioned, You could click button to start remote provisioning"); + remote_rpr_srv_addr = addr; + } + board_led_operation(LED_OFF, LED_OFF, LED_OFF); + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: + ESP_LOG_BUFFER_HEX("composition data %s", param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_STATUS: + break; + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + example_ble_mesh_set_msg_common(&common, addr, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Composition Data Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, addr, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + example_ble_mesh_set_msg_common(&common, addr, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = addr; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} + +static void example_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_node_info_t *node = NULL; + uint32_t opcode; + uint16_t addr; + int err; + + opcode = param->params->opcode; + addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04" PRIx32, + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send generic client message failed, opcode 0x%04" PRIx32, opcode); + return; + } + + node = example_ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + /* After Generic OnOff Status for Generic OnOff Get is received, Generic OnOff Set will be sent */ + example_ble_mesh_set_msg_common(&common, addr, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET onoff: 0x%02x", node->onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + /* If failed to receive the responses, these messages will be resend */ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + example_ble_mesh_set_msg_common(&common, addr, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + example_ble_mesh_set_msg_common(&common, addr, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a generic client status message event"); + break; + } +} + +static void example_ble_mesh_remote_prov_client_callback(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param) +{ + static uint8_t remote_dev_uuid[16] = {0}; + esp_ble_mesh_rpr_client_msg_t msg = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + uint16_t addr = 0; + + switch (event) { + case ESP_BLE_MESH_RPR_CLIENT_SEND_COMP_EVT: + ESP_LOGW(TAG, "Remote Prov Client Send Comp, err_code %d", param->send.err_code); + break; + case ESP_BLE_MESH_RPR_CLIENT_SEND_TIMEOUT_EVT: + ESP_LOGW(TAG, "Remote Prov Client Send Timeout, opcode 0x%04x, to 0x%04x", + param->send.params->opcode, param->send.params->ctx.addr); + break; + case ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT: + case ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT: + ESP_LOGW(TAG, "Remote Prov Client Recv RSP, opcode 0x%04x, from 0x%04x", + param->recv.params->ctx.recv_op, param->recv.params->ctx.addr); + switch (param->recv.params->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_STATUS: + break; + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "scan_status, status 0x%02x", param->recv.val.scan_status.status); + ESP_LOGI(TAG, "scan_status, rpr_scanning 0x%02x", param->recv.val.scan_status.rpr_scanning); + ESP_LOGI(TAG, "scan_status, scan_items_limit 0x%02x", param->recv.val.scan_status.scan_items_limit); + ESP_LOGI(TAG, "scan_status, timeout 0x%02x", param->recv.val.scan_status.timeout); + switch (cur_rpr_cli_opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET: { + if (param->recv.val.scan_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.scan_status.rpr_scanning) { + /** + * If the remote provisioning server's scan state is idle, + * that state indicates that remote provisioning server could + * start scan process. + */ + case ESP_BLE_MESH_RPR_SCAN_IDLE: { + err = example_ble_mesh_set_msg_common(&common, addr, remote_prov_client.model, + ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return ; + } + + msg.scan_start.scan_items_limit = 0; /* 0 indicates there is no limit for scan items' count */ + msg.scan_start.timeout = 0x0A; /* 0x0A is the default timeout */ + msg.scan_start.uuid_en = 0; /* If uuid enabled, a specify device which have the same uuid will be report */ + /* If uuid disable, any unprovision device all will be report */ + + err = esp_ble_mesh_rpr_client_send(&common, &msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg: Scan start"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START; + break; + } + default: + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Busy", addr); + break; + } + } else { + ESP_LOGE(TAG, "Remote Provisioning Client Scan Get Fail"); + } + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START: { + if (param->recv.val.scan_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + ESP_LOGI(TAG, "Start Remote Provisioning Server(addr: 0x%04x) Scan Success", addr); + } else { + ESP_LOGE(TAG, "Remote Provisioning Client Scan Start Fail"); + } + break; + } + default: + ESP_LOGW(TAG, "Unknown Process opcode 0x%04x:%d", cur_rpr_cli_opcode,__LINE__); + break; + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "scan_report, rssi %ddBm", param->recv.val.scan_report.rssi); + ESP_LOG_BUFFER_HEX(TAG": scan_report, uuid", param->recv.val.scan_report.uuid, 16); + ESP_LOGI(TAG, "scan_report, oob_info 0x%04x", param->recv.val.scan_report.oob_info); + ESP_LOGI(TAG, "scan_report, uri_hash 0x%08x", param->recv.val.scan_report.uri_hash); + + if (param->recv.val.scan_report.uuid[0] != remote_dev_uuid_match[0] || + param->recv.val.scan_report.uuid[1] != remote_dev_uuid_match[1]) { + ESP_LOGI(TAG, "This device is not expect device"); + return; + } + + memcpy(remote_dev_uuid, param->recv.val.scan_report.uuid, 16); + + /* Send ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET to remote provisioning server get link status */ + err = example_ble_mesh_set_msg_common(&common, addr,remote_prov_client.model + , ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return; + } + + err = esp_ble_mesh_rpr_client_send(&common, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg:Link Get"); + } + + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET; + break; + case ESP_BLE_MESH_MODEL_OP_RPR_EXT_SCAN_REPORT: + break; + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_STATUS: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "link_status, status 0x%02x", param->recv.val.link_status.status); + ESP_LOGI(TAG, "link_status, rpr_state 0x%02x", param->recv.val.link_status.rpr_state); + switch (cur_rpr_cli_opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET: { + if (param->recv.val.link_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.link_status.rpr_state) { + case ESP_BLE_MESH_RPR_LINK_IDLE: + /** + * Link status is idle, send ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN + * to remote provisioning server to open prov link + */ + err = example_ble_mesh_set_msg_common(&common, addr, remote_prov_client.model + , ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return; + } + + msg.link_open.uuid_en = 1; + memcpy(msg.link_open.uuid, remote_dev_uuid, 16); + msg.link_open.timeout_en = 0; + + err = esp_ble_mesh_rpr_client_send(&common, &msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg:Link open"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN; + break; + default: + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Busy", addr); + break; + } + } + break; + } + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: { + if (param->recv.val.link_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Recv Link Open Success", addr); + } else { + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Recv Link Open Fail", addr); + } + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE: { + if (param->recv.val.link_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Recv Link Close Success", addr); + } else { + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Recv Link Close Fail", addr); + } + } + break; + default: + ESP_LOGW(TAG, "Unknown Process opcode 0x%04x:%d", cur_rpr_cli_opcode,__LINE__); + break; + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "link_report, status 0x%02x", param->recv.val.link_report.status); + ESP_LOGI(TAG, "link_report, rpr_state 0x%02x", param->recv.val.link_report.rpr_state); + if (param->recv.val.link_report.reason_en) { + ESP_LOGI(TAG, "link_report, reason 0x%02x", param->recv.val.link_report.reason); + } + switch (cur_rpr_cli_opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: + if (param->recv.val.link_report.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.link_report.rpr_state) + { + case ESP_BLE_MESH_RPR_LINK_ACTIVE: + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Link Open Success", addr); + esp_ble_mesh_rpr_client_act_param_t param = {0}; + param.start_rpr.model = remote_prov_client.model; + param.start_rpr.rpr_srv_addr = addr; + + /* Let remote provisioning server start provisioning */ + err = esp_ble_mesh_rpr_client_action(ESP_BLE_MESH_RPR_CLIENT_ACT_START_RPR, + ¶m); + if (err) { + ESP_LOGE(TAG, "Failed to perform Remote Provisioning Client action: Start Prov"); + } + board_led_operation(LED_OFF, LED_ON, LED_OFF); + break; + default: + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Status error", addr); + break; + } + } else { + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Link open fail"); + } + break; + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE: + switch (param->recv.val.link_report.status) + { + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_CLIENT: + ESP_LOGI(TAG, "Link closed by client"); + break; + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_DEVICE: + ESP_LOGI(TAG, "Link closed by device"); + break; + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_BY_SERVER: + ESP_LOGI(TAG, "Link closed by server"); + break; + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_RECEIVE_PDU: + ESP_LOGI(TAG, "Link closed as cannot receive pdu"); + break; + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_SEND_PDU: + ESP_LOGI(TAG, "Link closed as cannot send pdu"); + break; + case ESP_BLE_MESH_RPR_STATUS_LINK_CLOSED_AS_CANNOT_DELIVER_PDU_REPORT: + ESP_LOGI(TAG, "Link closed as cannot send pdu report"); + break; + default: + ESP_LOGW(TAG, "Unknown link close status, %d", param->recv.val.link_report.status); + break; + } + break; + default: + ESP_LOGW(TAG, "Unknown Process opcode 0x%04x:%d", cur_rpr_cli_opcode,__LINE__); + break; + } + break; + case ESP_BLE_MESH_RPR_CLIENT_ACT_COMP_EVT: + ESP_LOGW(TAG, "Remote Prov Client Act Comp, sub_evt 0x%02x", param->act.sub_evt); + switch (param->act.sub_evt) { + case ESP_BLE_MESH_START_RPR_COMP_SUB_EVT: + ESP_LOGI(TAG, "Start Remote Prov Comp, err_code %d, rpr_srv_addr 0x%04x", + param->act.start_rpr_comp.err_code, + param->act.start_rpr_comp.rpr_srv_addr); + break; + default: + ESP_LOGE(TAG, "Unknown Remote Provisioning Client sub event"); + break; + } + break; + case ESP_BLE_MESH_RPR_CLIENT_LINK_OPEN_EVT: + ESP_LOGW(TAG, "Remote Prov Client Link Open"); + break; + case ESP_BLE_MESH_RPR_CLIENT_LINK_CLOSE_EVT: + ESP_LOGW(TAG, "Remote Prov Client Link Close"); + break; + case ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT: + ESP_LOGW(TAG, "Remote Prov Client Prov Complete"); + ESP_LOGI(TAG, "Net Idx: 0x%04x", param->prov.net_idx); + ESP_LOGI(TAG, "Node addr: 0x%04x", param->prov.unicast_addr); + ESP_LOGI(TAG, "Node element num: 0x%04x", param->prov.element_num); + ESP_LOG_BUFFER_HEX(TAG": Node UUID: ", param->prov.uuid, 16); + err = example_ble_mesh_set_msg_common(&common, param->prov.rpr_srv_addr, remote_prov_client.model, + ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return; + } + msg.link_close.reason = ESP_BLE_MESH_RPR_REASON_SUCCESS; + + err = esp_ble_mesh_rpr_client_send(&common, &msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg:Link open"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE; + + prov_complete(param->prov.net_idx, param->prov.uuid, + param->prov.unicast_addr, param->prov.element_num, param->prov.net_idx); + break; + default: + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + uint8_t match[2] = {0x55, 0xaa}; + + esp_err_t err = ESP_OK; + + prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY; + prov_key.app_idx = APP_KEY_IDX; + memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key)); + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb); + esp_ble_mesh_register_rpr_client_callback(example_ble_mesh_remote_prov_client_callback); + + err = esp_ble_mesh_init(&provision, &composition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set matching device uuid (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh provisioner (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to add local AppKey (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Provisioner initialized"); + + return err; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + ble_mesh_get_dev_uuid(dev_uuid); + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults new file mode 100644 index 0000000000..499c5f4052 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults @@ -0,0 +1,21 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_CTRL_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BLE_MESH_RPR_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..5897d737c0 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c3 @@ -0,0 +1,17 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c6 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..58ccc4d7a9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32c6 @@ -0,0 +1,19 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32h2 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..58ccc4d7a9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32h2 @@ -0,0 +1,19 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32s3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..5897d737c0 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/sdkconfig.defaults.esp32s3 @@ -0,0 +1,17 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt new file mode 100644 index 0000000000..47d782116b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/CMakeLists.txt new file mode 100644 index 0000000000..13a56c69f2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "main.c" + "board.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/Kconfig.projbuild new file mode 100644 index 0000000000..cbab996ec2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 if IDF_TARGET_ESP32 + default BLE_MESH_ESP32C3_DEV if IDF_TARGET_ESP32C3 + default BLE_MESH_ESP32S3_DEV if IDF_TARGET_ESP32S3 + default BLE_MESH_ESP32C6_DEV if IDF_TARGET_ESP32C6 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP32C3_DEV + bool "ESP32C3-DevKitC" + depends on IDF_TARGET_ESP32C3 + + config BLE_MESH_ESP32S3_DEV + bool "ESP32S3-DevKitC" + depends on IDF_TARGET_ESP32S3 + + config BLE_MESH_ESP32C6_DEV + bool "ESP32C6-DevKitC" + depends on IDF_TARGET_ESP32C6 + + config BLE_MESH_ESP32H2_DEV + bool "ESP32H2-DevKitC" + depends on IDF_TARGET_ESP32H2 + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.c new file mode 100644 index 0000000000..c729b6113b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.c @@ -0,0 +1,44 @@ +/* board.c - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "driver/gpio.h" +#include "esp_log.h" +#include "board.h" + +#define TAG "BOARD" + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_led_set(r, g, b); +#else + gpio_set_level(LED_R, r); + gpio_set_level(LED_G, g); + gpio_set_level(LED_B, b); +#endif +} + +static void board_led_init(void) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_encoder_init(); + rmt_led_set(LED_OFF,LED_OFF,LED_OFF); +#else + gpio_set_level(LED_R, LED_OFF); + gpio_set_level(LED_G, LED_OFF); + gpio_set_level(LED_B, LED_OFF); +#endif +} + +void board_init(void) +{ + board_led_init(); +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.h b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.h new file mode 100644 index 0000000000..e754f6d95c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/board.h @@ -0,0 +1,51 @@ +/* board.h - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "led_strip_encoder.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#elif defined(CONFIG_BLE_MESH_ESP32C3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32S3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_47 +#elif defined(CONFIG_BLE_MESH_ESP32C6_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32H2_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#endif + +#define BUTTON_IO_NUM GPIO_NUM_9 + +#ifndef BLE_MESH_LED_STRIP_IO +#define LED_ON 1 +#else +#define LED_R 0 +#define LED_G 1 +#define LED_B 2 +#define LED_ON 100 +#endif + +#define LED_OFF 0 + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/main.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/main.c new file mode 100644 index 0000000000..58beb29796 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/main.c @@ -0,0 +1,469 @@ +/* main.c - Application main entry point */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" +#if CONFIG_BLE_MESH_RPR_SRV +#include "esp_ble_mesh_rpr_model_api.h" +#endif + +#include "board.h" +#include "ble_mesh_example_init.h" + +#define TAG "EXAMPLE" + +#define CID_ESP 0x02E5 + +static uint8_t dev_uuid[16] = { 0x55, 0xaa }; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_0 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_1, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_1 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_2, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_2 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, +}; + +static esp_ble_mesh_model_t root_models[] = { +#if CONFIG_BLE_MESH_RPR_SRV + ESP_BLE_MESH_MODEL_RPR_SRV(NULL), +#endif + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0), +}; + +static esp_ble_mesh_model_t extend_model_0[] = { + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_1, &onoff_server_1), +}; + +static esp_ble_mesh_model_t extend_model_1[] = { + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_2, &onoff_server_2), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +/* Disable OOB security for SILabs Android app */ +static esp_ble_mesh_prov_t provision = { + .uuid = dev_uuid, +#if 0 + .output_size = 4, + .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER, + .input_actions = ESP_BLE_MESH_PUSH, + .input_size = 4, +#else + .output_size = 0, + .output_actions = 0, +#endif +}; + +static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08" PRIx32, flags, iv_index); +} + +static void example_change_led_state(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff) +{ + uint16_t primary_addr = esp_ble_mesh_get_primary_element_address(); + uint8_t elem_count = esp_ble_mesh_get_element_count(); + uint8_t rgb[3] = {0}; + uint8_t i; + + if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + for (i = 0; i < elem_count; i++) { + if (ctx->recv_dst == (primary_addr + i)) { + rgb[i] = onoff ? LED_ON : LED_OFF; + } + } + } else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) { + if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) { + rgb[model->element->element_addr - primary_addr] = onoff ? LED_ON : LED_OFF; + } + } else if (ctx->recv_dst == 0xFFFF) { + rgb[0] = onoff ? LED_ON : LED_OFF; + rgb[1] = onoff ? LED_ON : LED_OFF; + rgb[2] = onoff ? LED_ON : LED_OFF; + } + + board_led_operation(rgb[0], rgb[1], rgb[2]); +} + +static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + esp_ble_mesh_server_recv_gen_onoff_set_t *set) +{ + esp_ble_mesh_gen_onoff_srv_t *srv = model->user_data; + + switch (ctx->recv_op) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + if (set->op_en == false) { + srv->state.onoff = set->onoff; + } else { + /* TODO: Delay and state transition */ + srv->state.onoff = set->onoff; + } + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + } + esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE); + example_change_led_state(model, ctx, srv->state.onoff); + break; + default: + break; + } +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + board_led_operation(LED_OFF, LED_ON, LED_OFF); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"); + prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code); + break; + default: + break; + } +} + +static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event, + esp_ble_mesh_generic_server_cb_param_t *param) +{ + esp_ble_mesh_gen_onoff_srv_t *srv; + ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04" PRIx32 ", src 0x%04x, dst 0x%04x", + event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst); + + switch (event) { + case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff); + example_change_led_state(param->model, ¶m->ctx, param->value.state_change.onoff_set.onoff); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + srv = param->model->user_data; + ESP_LOGI(TAG, "onoff 0x%02x", srv->state.onoff); + example_handle_gen_onoff_msg(param->model, ¶m->ctx, NULL); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x, tid 0x%02x", param->value.set.onoff.onoff, param->value.set.onoff.tid); + if (param->value.set.onoff.op_en) { + ESP_LOGI(TAG, "trans_time 0x%02x, delay 0x%02x", + param->value.set.onoff.trans_time, param->value.set.onoff.delay); + } + example_handle_gen_onoff_msg(param->model, ¶m->ctx, ¶m->value.set.onoff); + } + break; + default: + ESP_LOGE(TAG, "Unknown Generic Server event 0x%02x", event); + break; + } +} + +static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param) +{ + if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) { + switch (param->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD"); + ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x", + param->value.state_change.appkey_add.net_idx, + param->value.state_change.appkey_add.app_idx); + ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND"); + ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_app_bind.element_addr, + param->value.state_change.mod_app_bind.app_idx, + param->value.state_change.mod_app_bind.company_id, + param->value.state_change.mod_app_bind.model_id); + board_led_operation(LED_OFF, LED_OFF, LED_OFF); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD"); + ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_sub_add.element_addr, + param->value.state_change.mod_sub_add.sub_addr, + param->value.state_change.mod_sub_add.company_id, + param->value.state_change.mod_sub_add.model_id); + break; + default: + break; + } + } +} + +static void print_scan_start_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "scan_start, element_idx 0x%02x", param->scan_start.model->element_idx); + ESP_LOGI(TAG, "scan_start, model_idx 0x%02x", param->scan_start.model->model_idx); + ESP_LOGI(TAG, "scan_start, scan_items_limit 0x%02x", param->scan_start.scan_items_limit); + ESP_LOGI(TAG, "scan_start, timeout 0x%02x", param->scan_start.timeout); + ESP_LOGI(TAG, "scan_start, net_idx 0x%04x", param->scan_start.net_idx); + ESP_LOGI(TAG, "scan_start, rpr_cli_addr 0x%04x", param->scan_start.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: scan_start, uuid", param->scan_start.uuid, 16); +} + +static void print_scan_stop_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "scan_stop, element_idx 0x%02x", param->scan_stop.model->element_idx); + ESP_LOGI(TAG, "scan_stop, model_idx 0x%02x", param->scan_stop.model->model_idx); + ESP_LOGI(TAG, "scan_stop, net_idx 0x%04x", param->scan_stop.net_idx); + ESP_LOGI(TAG, "scan_stop, rpr_cli_addr 0x%04x", param->scan_stop.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: scan_stop, uuid", param->scan_stop.uuid, 16); +} + +static void print_ext_scan_start_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "ext_scan_start, element_idx 0x%02x", param->ext_scan_start.model->element_idx); + ESP_LOGI(TAG, "ext_scan_start, model_idx 0x%02x", param->ext_scan_start.model->model_idx); + if (param->ext_scan_start.ad_type_filter_count && param->ext_scan_start.ad_type_filter) { + ESP_LOG_BUFFER_HEX("CMD_RP: ext_scan_start, ad_type_filter", + param->ext_scan_start.ad_type_filter, + param->ext_scan_start.ad_type_filter_count); + } + ESP_LOGI(TAG, "ext_scan_start, timeout 0x%02x", param->ext_scan_start.timeout); + ESP_LOGI(TAG, "ext_scan_start, index 0x%02x", param->ext_scan_start.index); + ESP_LOGI(TAG, "ext_scan_start, net_idx 0x%04x", param->ext_scan_start.net_idx); + ESP_LOGI(TAG, "ext_scan_start, rpr_cli_addr 0x%04x", param->ext_scan_start.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: ext_scan_start, uuid", param->ext_scan_start.uuid, 16); +} + +static void print_ext_scan_stop_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "ext_scan_stop, element_idx 0x%02x", param->ext_scan_stop.model->element_idx); + ESP_LOGI(TAG, "ext_scan_stop, model_idx 0x%02x", param->ext_scan_stop.model->model_idx); + ESP_LOGI(TAG, "ext_scan_stop, timeout 0x%02x", param->ext_scan_stop.timeout); + ESP_LOGI(TAG, "ext_scan_stop, index 0x%02x", param->ext_scan_stop.index); + ESP_LOGI(TAG, "ext_scan_stop, net_idx 0x%04x", param->ext_scan_stop.net_idx); + ESP_LOGI(TAG, "ext_scan_stop, rpr_cli_addr 0x%04x", param->ext_scan_stop.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: ext_scan_stop, uuid", param->ext_scan_stop.uuid, 16); +} + +static void print_link_open_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "link_open, element_idx 0x%02x", param->link_open.model->element_idx); + ESP_LOGI(TAG, "link_open, model_idx 0x%02x", param->link_open.model->model_idx); + ESP_LOGI(TAG, "link_open, status 0x%02x", param->link_open.status); + ESP_LOGI(TAG, "link_open, timeout 0x%02x", param->link_open.timeout); + ESP_LOGI(TAG, "link_open, nppi 0x%02x", param->link_open.nppi); + ESP_LOGI(TAG, "link_open, net_idx 0x%04x", param->link_open.net_idx); + ESP_LOGI(TAG, "link_open, rpr_cli_addr 0x%04x", param->link_open.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: link_open, uuid", param->link_open.uuid, 16); +} + +static void print_link_close_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "link_close, element_idx 0x%02x", param->link_close.model->element_idx); + ESP_LOGI(TAG, "link_close, model_idx 0x%02x", param->link_close.model->model_idx); + ESP_LOGI(TAG, "link_close, nppi 0x%02x", param->link_close.nppi); + ESP_LOGI(TAG, "link_close, close_by_device %d", param->link_close.close_by_device); + ESP_LOGI(TAG, "link_close, reason 0x%02x", param->link_close.reason); + ESP_LOGI(TAG, "link_close, net_idx 0x%04x", param->link_close.net_idx); + ESP_LOGI(TAG, "link_close, rpr_cli_addr 0x%04x", param->link_close.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: link_close, uuid", param->link_close.uuid, 16); +} + +static void print_prov_comp_evt(esp_ble_mesh_rpr_server_cb_param_t *param) +{ + ESP_LOGI(TAG, "prov_comp, element_idx 0x%02x", param->prov_comp.model->element_idx); + ESP_LOGI(TAG, "prov_comp, model_idx 0x%02x", param->prov_comp.model->model_idx); + ESP_LOGI(TAG, "prov_comp, nppi 0x%02x", param->prov_comp.nppi); + ESP_LOGI(TAG, "prov_comp, net_idx 0x%04x", param->prov_comp.net_idx); + ESP_LOGI(TAG, "prov_comp, rpr_cli_addr 0x%04x", param->prov_comp.rpr_cli_addr); + ESP_LOG_BUFFER_HEX("CMD_RP: prov_comp, uuid", param->prov_comp.uuid, 16); +} + +static void example_remote_prov_server_callback(esp_ble_mesh_rpr_server_cb_event_t event, + esp_ble_mesh_rpr_server_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT"); + print_scan_start_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT"); + print_scan_stop_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT"); + print_ext_scan_start_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT"); + print_ext_scan_stop_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT"); + print_link_open_evt(param); + board_led_operation(LED_OFF, LED_OFF, LED_ON); + break; + case ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT"); + board_led_operation(LED_OFF, LED_OFF, LED_OFF); + print_link_close_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT"); + print_prov_comp_evt(param); + break; + default: + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb); + esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb); + esp_ble_mesh_register_rpr_server_callback(example_remote_prov_server_callback); + + err = esp_ble_mesh_init(&provision, &composition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err); + return err; + } + + err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh node (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(LED_ON, LED_OFF, LED_OFF); + return err; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + ble_mesh_get_dev_uuid(dev_uuid); + ESP_LOG_BUFFER_HEX(TAG":uuid", dev_uuid, 16); + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults new file mode 100644 index 0000000000..92b956ae45 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults @@ -0,0 +1,20 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_CTRL_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RPR_SRV=y diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c6 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32c6 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32h2 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32h2 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32s3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/sdkconfig.defaults.esp32s3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md b/examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md new file mode 100644 index 0000000000..385ec47a88 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md @@ -0,0 +1,504 @@ +# 1. Introduction +This example demonstrates how to use the Remote Provisioning feature in the Espressif IDF's Bluetooth LE Mesh v1.1 protocol stack. + +The Remote Provisioning feature allows for the inclusion of nodes that are not within the coverage range of the Provisioner. In Remote Provisioning, there are two roles: the Remote Provisioning Client and the Remote Provisioning Server. The Remote Provisioning Client is typically played by the Provisioner, while the Remote Provisioning Server can be played by any node within the network. As an intermediate node, the Remote Provisioning Server primarily performs three functions: +1. Reports information of unprovisioned devices to the Remote Provisioning Client. +2. Reports its own provisioning status to the Remote Provisioning Client. +3. Distributes provisioning data from the Remote Provisioning Client to unprovisioned devices. + +By coordinating with each other, the Remote Provisioning Client and Remote Provisioning Server work together to include unprovisioned devices into the network. +## 1.1 Example Description +### 1.1.1 Directory Structure and Explanation +``` +. +├── unprov_dev +│ ├── CMakeLists.txt +│ └── main +│ ├── board.c +│ ├── board.h +│ ├── CMakeLists.txt +│ ├── Kconfig.projbuild +│ └── main.c +├── rpr_client +│ ├── CMakeLists.txt +│ └── main +│ ├── board.c +│ ├── board.h +│ ├── CMakeLists.txt +│ ├── Kconfig.projbuild +│ └── main.c +├── rpr_server +│ ├── CMakeLists.txt +│ └── main +│ ├── board.c +│ ├── board.h +│ ├── CMakeLists.txt +│ ├── Kconfig.projbuild +│ └── main.c +├── tutorial +│ ├── images +│ └── BLE_Mesh_Remote_Provisioning_Example_Walkthrough.md +└── README.md +``` +In this example, there are three roles: unprovisioned device, remote provisioning client, and remote provisioning server. + +1. The node is used to simulate an unprovisioned device that is outside the signal coverage of the provisioner. In practice, it is not necessary to place it outside the signal coverage of the provisioner, as we can restrict the provisioner from provisioning it through software limitations. This is done to simulate the node being outside the provisioner's signal coverage. +2. The remote_provisioning_client refers to the Remote Provisioning Client mentioned earlier. +3. The remote_provisioning_server refers to the Remote Provisioning Server mentioned earlier. + +Based on this, you will need at least three devices to run this example: + +1 x Device running `unprov_dev`. + +1 x Device running `rpr_client`. + +1 x Device running `rpr_server`. + +### 1.1.2 Running Phenomenon +First, power on the devices running `rpr_client` and node. The LED on the node will be red, indicating that the node is in an unprovisioned state. + +The node will maintain a solid red LED, indicating that remote_provisioning_client is unable to provision the node device. + +Next, power on the remote_provisioning_server node. The LED on the remote_provisioning_server will change from red to green. The remote_provisioning_client will also have a green LED, indicating that it is preparing to provision the remote_provisioning_server and perform post-provisioning tasks (such as adding AppKey and binding AppKey). + +Once all the tasks are completed, the LEDs on both remote_provisioning_server and remote_provisioning_client will turn off. Pressing the button on the remote_provisioning_client will command the remote_provisioning_server to start searching for unprovisioned devices. + +When the remote_provisioning_server finds a device, its LED will turn blue, and the LEDs on both the remote_provisioning_client and the node will turn green. This indicates that the node is going through the provisioning process via the remote_provisioning_server. + +Once all LEDs on the remote_provisioning_client, remote_provisioning_server, and node are turned off, it means that all the preliminary work is completed. + +At this point, pressing the button on the remote_provisioning_client allows you to control the LED on/off state of both the remote_provisioning_server and the node. + +### 1.1.3 Message Sequence +![Message Sequence](./images/message_sequence.png) +### 1.1.4 Code Explanation +#### Remote Provisioning Client +---- +Declaration and registration of a remote provisioning client. +```c +#if CONFIG_BLE_MESH_RPR_CLI +static esp_ble_mesh_client_t remote_prov_client; +#endif +// ... +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), +#if CONFIG_BLE_MESH_RPR_CLI + ESP_BLE_MESH_MODEL_RPR_CLI(&remote_prov_client), +#endif + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; +``` +In the `ble_mesh_init` function, register callback functions for relevant events and set the prefix for the commissionable device. The prefix for node devices is 0x55,0x55, while the prefix set for the remote provisioning client is 0x55,0xaa. Therefore, the remote provisioning client does not directly commission node devices. + +```c +static esp_err_t ble_mesh_init(void) +{ + // ... + uint8_t match[2] = {0x55, 0xaa}; + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb); + /* Register the callback function of remote provisioning client */ + esp_ble_mesh_register_rpr_client_callback(example_ble_mesh_remote_prov_client_callback); + + /* Set the accepted unprovisioned device uuid prefix */ + err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set matching device uuid (err %d)", err); + return err; + } + + // ... +} +``` +In the `example_ble_mesh_config_client_cb` function, under the event `ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT` and opcode `ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND`, use the function `example_ble_mesh_query_element_have_model` to check if the currently ended AppKeyBind node supports the remote provisioning server. If it does, record the node address and trigger the sending of a Remote Provisioning Server Scan Get command when a button is pressed to start remote provisioning. +```c +static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + // ... + + switch (event) { + // ... + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + // ... + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + + if (!example_ble_mesh_query_element_have_model(addr, ESP_BLE_MESH_MODEL_ID_RPR_SRV, CID_NVAL)) { + if (remote_rpr_srv_addr) { + ESP_LOGI(TAG, "The last node have been provisioned, You could click button to send Generic Onoff Set"); + click_to_send_onoff_set = 1; + } else { + ESP_LOGE(TAG, "Element (addr: 0x%04x) does not support remote provisioning srv model"); + } + return; + } else { + click_to_send_onoff_set = 0; + ESP_LOGI(TAG, "The Remote Provisioning Server have been provisioned, You could click button to start remote provisioning"); + remote_rpr_srv_addr = addr; + } + board_led_operation(LED_G, LED_OFF); + break; + } + default: + break; + } + break; + // ... + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} +``` +The button callback function in board.c is as follows: +```c +static void button_tap_cb(void* arg) +{ + static uint8_t onoff = 1; + ESP_LOGI(TAG, "tap cb (%s)", (char *)arg); + if (click_to_send_onoff_set) { + example_ble_mesh_send_gen_onoff_set(onoff); + onoff = !onoff; + } else { + example_ble_mesh_send_remote_provisioning_scan_start(); + } +} +``` +By using `click_to_send_onoff_set`, it can be determined whether the current button press should trigger `Generic Onoff Set` or `Remote Provisioning Scan Start`. +The implementation of the function `example_ble_mesh_send_remote_provisioning_scan_start` is as follows: +```c +void example_ble_mesh_send_remote_provisioning_scan_start(void) +{ + + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + + if (!remote_rpr_srv_addr) { + ESP_LOGE(TAG, "No valid remote provisioning server address"); + return; + } + + /* Send a ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET to get the scan status of remote provisioning server */ + example_ble_mesh_set_msg_common(&common, remote_rpr_srv_addr, remote_prov_client.model, ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET); + err = esp_ble_mesh_rpr_client_send(&common, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg: Scan Get"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET; +} +``` +Opcode `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET` is used to obtain the scan status of the remote provisioning server. It can assist the remote provisioning client in scanning for unprovisioned devices only when the status is Idle. The remote provisioning server will immediately respond with `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS` upon receiving `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET`. + +The `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS` has the following four fields: +1. `scan_status`: This field indicates the status of the remote provisioning server's handling of the scan command from the remote provisioning client. If the value is `ESP_BLE_MESH_RPR_STATUS_SUCCESS`, it means that the remote provisioning server successfully processed the `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET` command in this example. + +2. `rpr_scanning`: This field indicates the current status of the remote provisioning server. + - `ESP_BLE_MESH_RPR_SCAN_IDLE`: Indicates that the remote provisioning server is in an idle state and can be started. + - `ESP_BLE_MESH_RPR_SCAN_MULTIPLE_DEVICE`: Indicates that the remote provisioning server is currently scanning in multiple device mode. When the remote provisioning server is in this mode, it is executing a scanning task and will report any unprovisioned devices until the scan count limit is reached. + - `ESP_BLE_MESH_RPR_SCAN_SINGLE_DEVICE`: Indicates that the remote provisioning server is scanning for a specific device. It will only report when it scans an unprovisioned beacon that meets the requirements of the remote provisioning client. + +3. `scan_items_limit`: This field represents the maximum number of unprovisioned device information reported by the remote provisioning server. The value is set by the remote provisioning client and defaults to the maximum value `CONFIG_BLE_MESH_RPR_SRV_MAX_SCANNED_ITEMS`, which is 10 if not set by the client. + +4. `timeout`: This value represents the timeout for the remote provisioning server to perform the scan operation in seconds. + +In this example, the parsing and manipulation of the above data are shown as follows: +```c +static void example_ble_mesh_remote_prov_client_callback(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param) +{ + static uint8_t remote_dev_uuid[16] = {0}; + esp_ble_mesh_rpr_client_msg_t msg = {0}; + esp_ble_mesh_client_common_param_t common = {0}; + esp_err_t err = ESP_OK; + uint16_t addr = 0; + + switch (event) { + // ... + case ESP_BLE_MESH_RPR_CLIENT_RECV_PUB_EVT: + case ESP_BLE_MESH_RPR_CLIENT_RECV_RSP_EVT: + ESP_LOGW(TAG, "Remote Prov Client Recv RSP, opcode 0x%04x, from 0x%04x", + param->recv.params->ctx.recv_op, param->recv.params->ctx.addr); + switch (param->recv.params->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_CAPS_STATUS: + break; + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "scan_status, status 0x%02x", param->recv.val.scan_status.status); + ESP_LOGI(TAG, "scan_status, rpr_scanning 0x%02x", param->recv.val.scan_status.rpr_scanning); + ESP_LOGI(TAG, "scan_status, scan_items_limit 0x%02x", param->recv.val.scan_status.scan_items_limit); + ESP_LOGI(TAG, "scan_status, timeout 0x%02x", param->recv.val.scan_status.timeout); + switch (cur_rpr_cli_opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET: { + if (param->recv.val.scan_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.scan_status.rpr_scanning) { + /** + * If the remote provisioning server's scan state is idle, + * that state indicates that remote provisioning server could + * start scan process. + */ + case ESP_BLE_MESH_RPR_SCAN_IDLE: { + err = example_ble_mesh_set_msg_common(&common, addr, remote_prov_client.model, + ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return ; + } + + msg.scan_start.scan_items_limit = 0; /* 0 indicates there is no limit for scan items' count */ + msg.scan_start.timeout = 0x0A; /* 0x0A is the default timeout */ + msg.scan_start.uuid_en = 0; /* If uuid enabled, a specify device which have the same uuid will be report */ + /* If uuid disable, any unprovision device all will be report */ + + err = esp_ble_mesh_rpr_client_send(&common, &msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg: Scan start"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START; + break; + } + default: + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Busy", addr); + break; + } + } else { + ESP_LOGE(TAG, "Remote Provisioning Client Scan Get Fail"); + } + } + break; + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START: { + if (param->recv.val.scan_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + ESP_LOGI(TAG, "Start Remote Provisioning Server(addr: 0x%04x) Scan Success", addr); + } else { + ESP_LOGE(TAG, "Remote Provisioning Client Scan Start Fail"); + } + break; + } + default: + ESP_LOGW(TAG, "Unknown Process opcode 0x%04x:%d", cur_rpr_cli_opcode,__LINE__); + break; + } + break; + } + // ... + default: + break; + } +} +``` +Due to `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS` being a response to multiple Remote Provisioning Client Opcodes, the Remote Provisioning Client needs to keep track of the current Opcode being sent in order to differentiate the Opcode corresponding to the Status. In this example, the variable `cur_rpr_cli_opcode` is used for this purpose. + +When receiving a response `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS` for `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_GET`, if the current Scan status of the Remote Provisioning Server is Idle, then send `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START` to the Remote Provisioning Server to initiate scanning. +`ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START` requires three parameters: +1. `scan_items_limit`: The number of Unprovisioned Devices that can be scanned. This value cannot exceed the maximum scan limit of the Remote Provisioning Server. When set to 0, the Remote Provisioning Client does not limit this value, and the Remote Provisioning Server will set it to its own maximum scan limit. +2. `timeout`: The maximum scan time for the Remote Provisioning Server in seconds. This value cannot be set to 0. +3. `uuid_en`: Specifies whether the Unprovisioned Device's UUID is specified. 0 means no, 1 means yes. If specified, the UUID information of the Unprovisioned Device needs to be filled. An example is shown below. In this example, the UUID is not specified. +```c +msg.scan_start.uuid_en = 1; +memcpy(msg.scan_start.uuid, unprovisioning_device_uuid, 16); +``` +When `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_START` is sent, the Remote Provisioning Server will immediately respond with `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_STATUS`. If `scan_status.status` is `ESP_BLE_MESH_RPR_STATUS_SUCCESS`, it indicates that the Remote Provisioning Server's Scan has been successfully started. When it scans an unprovisioned device, it will respond with `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT`. The handling of `ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT` in this example is as follows: +```c +static void example_ble_mesh_remote_prov_client_callback(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param) +{ + // ... + case ESP_BLE_MESH_MODEL_OP_RPR_SCAN_REPORT: + addr = param->recv.params->ctx.addr; + ESP_LOGI(TAG, "scan_report, rssi %ddBm", param->recv.val.scan_report.rssi); + ESP_LOG_BUFFER_HEX(TAG": scan_report, uuid", param->recv.val.scan_report.uuid, 16); + ESP_LOGI(TAG, "scan_report, oob_info 0x%04x", param->recv.val.scan_report.oob_info); + ESP_LOGI(TAG, "scan_report, uri_hash 0x%08x", param->recv.val.scan_report.uri_hash); + + if (param->recv.val.scan_report.uuid[0] != remote_dev_uuid_match[0] || + param->recv.val.scan_report.uuid[1] != remote_dev_uuid_match[1]) { + ESP_LOGI(TAG, "This device is not expect device"); + return; + } + + memcpy(remote_dev_uuid, param->recv.val.scan_report.uuid, 16); + + /* Send ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET to remote provisioning server get link status */ + err = example_ble_mesh_set_msg_common(&common, addr,remote_prov_client.model + , ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return; + } + + err = esp_ble_mesh_rpr_client_send(&common, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg:Link Get"); + } + + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET; + break; + // ... +} +``` +If the scanned device is the expected device, use `ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET` to obtain the status of the Provisioning Link of the Remote Provisioning Server. The Provisioning Link can only be opened for network provisioning when its status is `ESP_BLE_MESH_RPR_LINK_IDLE`. Upon receiving `ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET`, the Remote Provisioning Server will respond with `ESP_BLE_MESH_MODEL_OP_RPR_LINK_STATUS`. + +The Status includes two main fields: +1. `status`: This field indicates whether the Remote Provisioning Server has successfully processed the command from the Remote Provisioning Client. In this example, the command is `ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET` and only when the result is `ESP_BLE_MESH_RPR_STATUS_SUCCESS`, it means that the Remote Provisioning Server has processed the `ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET` message successfully. +2. `rpr_status`: This field indicates the current status of the Provisioning Link on the Remote Provisioning Server. The Provisioning Link can have the following states: + - `ESP_BLE_MESH_RPR_LINK_IDLE`: Indicates that the Provisioning Link is in an idle state. + - `ESP_BLE_MESH_RPR_LINK_OPENING`: Indicates that the Provisioning Link is being opened. + - `ESP_BLE_MESH_RPR_LINK_ACTIVE`: Indicates that the Provisioning Link has been activated and is waiting for the Remote Provisioning Client to send the command to start network provisioning. + - `ESP_BLE_MESH_RPR_OUTBOUND_PACKET_TRANSFER`: Indicates that the Provisioning Link is in the process of network provisioning. + - `ESP_BLE_MESH_RPR_LINK_CLOSING`: Indicates that the Provisioning Link is about to be closed. + +In this example, only the `ESP_BLE_MESH_RPR_LINK_IDLE` state is processed as follows: +```c +static void example_ble_mesh_remote_prov_client_callback(esp_ble_mesh_rpr_client_cb_event_t event, + esp_ble_mesh_rpr_client_cb_param_t *param) +{ + // ... + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_GET: { + if (param->recv.val.link_status.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.link_status.rpr_state) { + case ESP_BLE_MESH_RPR_LINK_IDLE: + /** + * Link status is idle, send ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN + * to remote provisioning server to open prov link + */ + err = example_ble_mesh_set_msg_common(&common, addr, remote_prov_client.model + , ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Set message common fail:%d", __LINE__); + return; + } + + msg.link_open.uuid_en = 1; + memcpy(msg.link_open.uuid, remote_dev_uuid, 16); + msg.link_open.timeout_en = 0; + + err = esp_ble_mesh_rpr_client_send(&common, &msg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Remote Provisioning Client msg:Link open"); + } + cur_rpr_cli_opcode = ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN; + break; + default: + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Busy", addr); + break; + } + } + break; + } + // ... +} +``` +If the status of the Provisioning Link of the Remote Provisioning Server is `ESP_BLE_MESH_RPR_LINK_IDLE`, the Remote Provisioning Client sends `ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN` to open the Provisioning Link of the Remote Provisioning Server. Once the Remote Provisioning Server receives `ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN`, it immediately replies with `ESP_BLE_MESH_MODEL_OP_RPR_LINK_STATUS` to indicate whether it has received the command from the Remote Provisioning Client. The Remote Provisioning Server then reports to the Remote Provisioning Client whether it has successfully established a Provisioning Link with the Unprovisioning Device by replying with `ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT`. + +Only when the `status` in `ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT` is `ESP_BLE_MESH_RPR_STATUS_SUCCESS` and `rpr_state` is `ESP_BLE_MESH_RPR_LINK_ACTIVE`, it means that the Remote Provisioning Server has successfully established a Provisioning Link with the Unprovisioning Device and the Link Open is successful. At this point, the Unprovisioning Device triggers the `ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT` event. + +In this example, the processing of receiving `ESP_BLE_MESH_MODEL_OP_RPR_LINK_REPORT` is as follows: +```c + switch (cur_rpr_cli_opcode) { + case ESP_BLE_MESH_MODEL_OP_RPR_LINK_OPEN: + if (param->recv.val.link_report.status == ESP_BLE_MESH_RPR_STATUS_SUCCESS) { + switch (param->recv.val.link_report.rpr_state) + { + case ESP_BLE_MESH_RPR_LINK_ACTIVE: + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Link Open Success", addr); + esp_ble_mesh_rpr_client_act_param_t param = {0}; + param.start_rpr.model = remote_prov_client.model; + param.start_rpr.rpr_srv_addr = addr; + + /* Let remote provisioning server start provisioning */ + err = esp_ble_mesh_rpr_client_action(ESP_BLE_MESH_RPR_CLIENT_ACT_START_RPR, + ¶m); + if (err) { + ESP_LOGE(TAG, "Failed to perform Remote Provisioning Client action: Start Prov"); + } + board_led_operation(LED_G, LED_ON); + break; + default: + ESP_LOGI(TAG, "Remote Provisioning Server(addr: 0x%04x) Status error", addr); + break; + } + } else { + ESP_LOGW(TAG, "Remote Provisioning Server(addr: 0x%04x) Link open fail"); + } + break; + } + break; +``` +Once the Remote Provisioning Server successfully establishes a Provisioning Link with the Unprovisioning Device, the network provisioning process can be initiated by setting the API `esp_ble_mesh_rpr_client_action` to `ESP_BLE_MESH_RPR_CLIENT_ACT_START_RPR` and passing the address of the Remote Provisioning Server. + +After the network provisioning is completed, the Remote Provisioning Client triggers the event `ESP_BLE_MESH_RPR_CLIENT_PROV_COMP_EVT`, which returns data about the network information of the nodes entering the network through Remote Provisioning. This includes node UUID, node address, and number of elements in the node. + +Once the network provisioning is completed, the Remote Provisioning Client sends `ESP_BLE_MESH_MODEL_OP_RPR_LINK_CLOSE` to the Remote Provisioning Server to close the Provisioning Link. It also configures the nodes entering the network through Remote Provisioning by obtaining their Composition Data, AppKey Add, and AppKey Bind. + +#### Remote Provisioning Server +---- + +To register and declare the Remote Provision Server Model, the remote_provisioning_server should be implemented as follows: +```c +static esp_ble_mesh_model_t root_models[] = { +#if CONFIG_BLE_MESH_RPR_SRV + ESP_BLE_MESH_MODEL_RPR_SRV(NULL), // Register Remote Provisioning Server +#endif + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0), +}; +``` +In the `ble_mesh_init` function, register the callback function for the Remote Provisioning Server as follows: +```c +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb); + esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb); + esp_ble_mesh_register_rpr_server_callback(example_remote_prov_server_callback); +} +``` +Since all the related functionalities of Remote Provisioning Server are handled by the protocol stack, the callback function `example_remote_prov_server_callback` of Remote Provisioning Server is only used to indicate the current step. The implementation is as follows: +```c +static void example_remote_prov_server_callback(esp_ble_mesh_rpr_server_cb_event_t event, + esp_ble_mesh_rpr_server_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_SCAN_START_EVT"); + print_scan_start_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_SCAN_STOP_EVT"); + print_scan_stop_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_START_EVT"); + print_ext_scan_start_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_EXT_SCAN_STOP_EVT"); + print_ext_scan_stop_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_LINK_OPEN_EVT"); + print_link_open_evt(param); + board_led_operation_rmt(LED_OFF, LED_OFF, LED_ON); + break; + case ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_LINK_CLOSE_EVT"); + board_led_operation_rmt(LED_OFF, LED_OFF, LED_OFF); + print_link_close_evt(param); + break; + case ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT: + ESP_LOGW(TAG, "ESP_BLE_MESH_RPR_SERVER_PROV_COMP_EVT"); + print_prov_comp_evt(param); + break; + default: + break; + } +} +``` +#### Unprovisioned Device +---- +The Remote Provisioning functionality is transparent to Unprovisioning Device. Therefore, regardless of whether Provisioning is done through Remote Provisioning or directly by the Provisioner, it will trigger the same events on the Unprovisioning Device side. Hence, in this example, it is not explained in detail. \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/images/message_sequence.png b/examples/bluetooth/esp_ble_mesh/remote_provisioning/tutorial/images/message_sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..ff52a660ae3a1119add474555ea2967b97ab3512 GIT binary patch literal 61049 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 z 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 E6CZE;XaE2J literal 0 HcmV?d00001 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt new file mode 100644 index 0000000000..47d782116b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/CMakeLists.txt new file mode 100644 index 0000000000..13a56c69f2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "main.c" + "board.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/Kconfig.projbuild new file mode 100644 index 0000000000..cbab996ec2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/Kconfig.projbuild @@ -0,0 +1,38 @@ +menu "Example Configuration" + + choice BLE_MESH_EXAMPLE_BOARD + prompt "Board selection for BLE Mesh" + default BLE_MESH_ESP_WROOM_32 if IDF_TARGET_ESP32 + default BLE_MESH_ESP32C3_DEV if IDF_TARGET_ESP32C3 + default BLE_MESH_ESP32S3_DEV if IDF_TARGET_ESP32S3 + default BLE_MESH_ESP32C6_DEV if IDF_TARGET_ESP32C6 + help + Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32 + + config BLE_MESH_ESP_WROOM_32 + bool "ESP32-WROOM-32" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP_WROVER + bool "ESP32-WROVER" + depends on IDF_TARGET_ESP32 + + config BLE_MESH_ESP32C3_DEV + bool "ESP32C3-DevKitC" + depends on IDF_TARGET_ESP32C3 + + config BLE_MESH_ESP32S3_DEV + bool "ESP32S3-DevKitC" + depends on IDF_TARGET_ESP32S3 + + config BLE_MESH_ESP32C6_DEV + bool "ESP32C6-DevKitC" + depends on IDF_TARGET_ESP32C6 + + config BLE_MESH_ESP32H2_DEV + bool "ESP32H2-DevKitC" + depends on IDF_TARGET_ESP32H2 + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.c new file mode 100644 index 0000000000..c729b6113b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.c @@ -0,0 +1,44 @@ +/* board.c - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "driver/gpio.h" +#include "esp_log.h" +#include "board.h" + +#define TAG "BOARD" + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_led_set(r, g, b); +#else + gpio_set_level(LED_R, r); + gpio_set_level(LED_G, g); + gpio_set_level(LED_B, b); +#endif +} + +static void board_led_init(void) +{ +#ifdef BLE_MESH_LED_STRIP_IO + rmt_encoder_init(); + rmt_led_set(LED_OFF,LED_OFF,LED_OFF); +#else + gpio_set_level(LED_R, LED_OFF); + gpio_set_level(LED_G, LED_OFF); + gpio_set_level(LED_B, LED_OFF); +#endif +} + +void board_init(void) +{ + board_led_init(); +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.h b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.h new file mode 100644 index 0000000000..e754f6d95c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/board.h @@ -0,0 +1,51 @@ +/* board.h - Board-specific hooks */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "driver/gpio.h" +#include "led_strip_encoder.h" + +#if defined(CONFIG_BLE_MESH_ESP_WROOM_32) +#define LED_R GPIO_NUM_25 +#define LED_G GPIO_NUM_26 +#define LED_B GPIO_NUM_27 +#elif defined(CONFIG_BLE_MESH_ESP_WROVER) +#define LED_R GPIO_NUM_0 +#define LED_G GPIO_NUM_2 +#define LED_B GPIO_NUM_4 +#elif defined(CONFIG_BLE_MESH_ESP32C3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32S3_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_47 +#elif defined(CONFIG_BLE_MESH_ESP32C6_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#elif defined(CONFIG_BLE_MESH_ESP32H2_DEV) +#define BLE_MESH_LED_STRIP_IO GPIO_NUM_8 +#endif + +#define BUTTON_IO_NUM GPIO_NUM_9 + +#ifndef BLE_MESH_LED_STRIP_IO +#define LED_ON 1 +#else +#define LED_R 0 +#define LED_G 1 +#define LED_B 2 +#define LED_ON 100 +#endif + +#define LED_OFF 0 + +void board_led_operation(uint8_t r, uint8_t g, uint8_t b); + +void board_init(void); + +#endif diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/main.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/main.c new file mode 100644 index 0000000000..d5baf7436b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/main.c @@ -0,0 +1,343 @@ +/* main.c - Application main entry point */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" + +#include "board.h" +#include "ble_mesh_example_init.h" + +#define TAG "EXAMPLE" + +#define CID_ESP 0x02E5 + +static uint8_t dev_uuid[16] = { 0x55, 0x55 }; + +static esp_ble_mesh_cfg_srv_t config_server = { + .relay = ESP_BLE_MESH_RELAY_DISABLED, + .beacon = ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_FRIEND) + .friend_state = ESP_BLE_MESH_FRIEND_ENABLED, +#else + .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + .default_ttl = 7, + /* 3 transmissions with 20ms interval */ + .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20), + .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20), +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_0 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_1, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_1 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, +}; + +ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_2, 2 + 3, ROLE_NODE); +static esp_ble_mesh_gen_onoff_srv_t onoff_server_2 = { + .rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP, + .rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0), +}; + +static esp_ble_mesh_model_t extend_model_0[] = { + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_1, &onoff_server_1), +}; + +static esp_ble_mesh_model_t extend_model_1[] = { + ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_2, &onoff_server_2), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE), + ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .elements = elements, + .element_count = ARRAY_SIZE(elements), +}; + +/* Disable OOB security for SILabs Android app */ +static esp_ble_mesh_prov_t provision = { + .uuid = dev_uuid, +#if 0 + .output_size = 4, + .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER, + .input_actions = ESP_BLE_MESH_PUSH, + .input_size = 4, +#else + .output_size = 0, + .output_actions = 0, +#endif +}; + +static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index) +{ + ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr); + ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08" PRIx32, flags, iv_index); +} + +static void example_change_led_state(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff) +{ + uint16_t primary_addr = esp_ble_mesh_get_primary_element_address(); + uint8_t elem_count = esp_ble_mesh_get_element_count(); + uint8_t rgb[3] = {0}; + uint8_t i; + + if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + for (i = 0; i < elem_count; i++) { + if (ctx->recv_dst == (primary_addr + i)) { + rgb[i] = onoff ? LED_ON : LED_OFF; + } + } + } else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) { + if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) { + rgb[model->element->element_addr - primary_addr] = onoff ? LED_ON : LED_OFF; + } + } else if (ctx->recv_dst == 0xFFFF) { + rgb[0] = onoff ? LED_ON : LED_OFF; + rgb[1] = onoff ? LED_ON : LED_OFF; + rgb[2] = onoff ? LED_ON : LED_OFF; + } + + board_led_operation(rgb[0], rgb[1], rgb[2]); +} + +static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model, + esp_ble_mesh_msg_ctx_t *ctx, + esp_ble_mesh_server_recv_gen_onoff_set_t *set) +{ + esp_ble_mesh_gen_onoff_srv_t *srv = model->user_data; + + switch (ctx->recv_op) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + if (set->op_en == false) { + srv->state.onoff = set->onoff; + } else { + /* TODO: Delay and state transition */ + srv->state.onoff = set->onoff; + } + if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + esp_ble_mesh_server_model_send_msg(model, ctx, + ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff); + } + esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE); + example_change_led_state(model, ctx, srv->state.onoff); + break; + default: + break; + } +} + +static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s", + param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + board_led_operation(LED_OFF, LED_ON, LED_OFF); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s", + param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT"); + prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr, + param->node_prov_complete.flags, param->node_prov_complete.iv_index); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code); + break; + default: + break; + } +} + +static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event, + esp_ble_mesh_generic_server_cb_param_t *param) +{ + esp_ble_mesh_gen_onoff_srv_t *srv; + ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04" PRIx32 ", src 0x%04x, dst 0x%04x", + event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst); + + switch (event) { + case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff); + example_change_led_state(param->model, ¶m->ctx, param->value.state_change.onoff_set.onoff); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + srv = param->model->user_data; + ESP_LOGI(TAG, "onoff 0x%02x", srv->state.onoff); + example_handle_gen_onoff_msg(param->model, ¶m->ctx, NULL); + } + break; + case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT"); + if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET || + param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ESP_LOGI(TAG, "onoff 0x%02x, tid 0x%02x", param->value.set.onoff.onoff, param->value.set.onoff.tid); + if (param->value.set.onoff.op_en) { + ESP_LOGI(TAG, "trans_time 0x%02x, delay 0x%02x", + param->value.set.onoff.trans_time, param->value.set.onoff.delay); + } + example_handle_gen_onoff_msg(param->model, ¶m->ctx, ¶m->value.set.onoff); + } + break; + default: + ESP_LOGE(TAG, "Unknown Generic Server event 0x%02x", event); + break; + } +} + +static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event, + esp_ble_mesh_cfg_server_cb_param_t *param) +{ + if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) { + switch (param->ctx.recv_op) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD"); + ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x", + param->value.state_change.appkey_add.net_idx, + param->value.state_change.appkey_add.app_idx); + ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND"); + ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_app_bind.element_addr, + param->value.state_change.mod_app_bind.app_idx, + param->value.state_change.mod_app_bind.company_id, + param->value.state_change.mod_app_bind.model_id); + + board_led_operation(LED_OFF, LED_OFF, LED_OFF); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD"); + ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x", + param->value.state_change.mod_sub_add.element_addr, + param->value.state_change.mod_sub_add.sub_addr, + param->value.state_change.mod_sub_add.company_id, + param->value.state_change.mod_sub_add.model_id); + break; + default: + break; + } + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + + esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb); + esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err); + return err; + } + + err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh node (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Node initialized"); + + board_led_operation(LED_ON, LED_OFF, LED_OFF); + + return err; +} + +void app_main(void) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Initializing..."); + + board_init(); + + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err); + return; + } + + ble_mesh_get_dev_uuid(dev_uuid); + + /* Initialize the Bluetooth Mesh Subsystem */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err); + } +} diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults new file mode 100644 index 0000000000..64b4733365 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults @@ -0,0 +1,19 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_CTRL_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c6 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32c6 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32h2 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..78299bedf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32h2 @@ -0,0 +1,18 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32s3 b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..ad04a937e2 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/sdkconfig.defaults.esp32s3 @@ -0,0 +1,16 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y + +# Override some defaults of ESP BLE Mesh +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_NODE=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10 diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c index 04eab7fee2..fd319b53e0 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c @@ -31,7 +31,6 @@ #define PROV_OWN_ADDR 0x0001 #define MSG_SEND_TTL 3 -#define MSG_SEND_REL false #define MSG_TIMEOUT 0 #define MSG_ROLE ROLE_PROVISIONER @@ -101,9 +100,7 @@ static void example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t * common->ctx.app_idx = prov_key.app_idx; common->ctx.addr = node->unicast_addr; common->ctx.send_ttl = MSG_SEND_TTL; - common->ctx.send_rel = MSG_SEND_REL; common->msg_timeout = MSG_TIMEOUT; - common->msg_role = MSG_ROLE; } static esp_err_t prov_complete(uint16_t node_index, const esp_ble_mesh_octet16_t uuid, diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/sdkconfig.defaults index 5b7f9f6222..35516e8fa3 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/sdkconfig.defaults @@ -8,6 +8,7 @@ CONFIG_CTRL_BTDM_MODEM_SLEEP=n CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y # Override some defaults of ESP BLE Mesh CONFIG_BLE_MESH=y diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/sdkconfig.defaults index f285ddba62..64b4733365 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/sdkconfig.defaults @@ -9,6 +9,7 @@ CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y # Override some defaults of ESP BLE Mesh CONFIG_BLE_MESH=y diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c index 75e5ba224e..461177a379 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c @@ -33,7 +33,6 @@ #define PROV_OWN_ADDR 0x0001 #define MSG_SEND_TTL 3 -#define MSG_SEND_REL false #define MSG_TIMEOUT 0 #define MSG_ROLE ROLE_PROVISIONER @@ -155,9 +154,7 @@ static void example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t * common->ctx.app_idx = prov_key.app_idx; common->ctx.addr = node->unicast_addr; common->ctx.send_ttl = MSG_SEND_TTL; - common->ctx.send_rel = MSG_SEND_REL; common->msg_timeout = MSG_TIMEOUT; - common->msg_role = MSG_ROLE; } static esp_err_t prov_complete(uint16_t node_index, const esp_ble_mesh_octet16_t uuid, @@ -460,7 +457,6 @@ void example_ble_mesh_send_vendor_message(bool resend) ctx.app_idx = prov_key.app_idx; ctx.addr = store.server_addr; ctx.send_ttl = MSG_SEND_TTL; - ctx.send_rel = MSG_SEND_REL; opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND; if (resend == false) { diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/sdkconfig.defaults index 9cb1eea6e3..dce152c118 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/sdkconfig.defaults @@ -8,6 +8,7 @@ CONFIG_CTRL_BTDM_MODEM_SLEEP=n CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y # Override some defaults of ESP BLE Mesh CONFIG_BLE_MESH=y diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/sdkconfig.defaults index 7f319e03d1..54f6e7e334 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/sdkconfig.defaults @@ -9,6 +9,7 @@ CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y CONFIG_BT_BTU_TASK_STACK_SIZE=4512 +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y # Override some defaults of ESP BLE Mesh CONFIG_BLE_MESH=y diff --git a/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c index c2630ccde4..1c8f6d45cf 100644 --- a/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c @@ -294,7 +294,6 @@ static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { @@ -618,7 +617,6 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -641,7 +639,6 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, - .role = ROLE_FAST_PROV, }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 1509cd8bdb..bde19be313 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -1,4 +1,5 @@ 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 diff --git a/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts.nimble b/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts.nimble index 43d3b3621d..a1367f9c9f 100644 --- a/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts.nimble +++ b/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.noasserts.nimble @@ -8,6 +8,5 @@ CONFIG_COMPILER_HIDE_PATHS_MACROS=n CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n -CONFIG_BT_NIMBLE_MESH=y CONFIG_BLE_MESH=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 diff --git a/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts.nimble b/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts.nimble index 384215fbb6..d60f1630df 100644 --- a/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts.nimble +++ b/tools/test_apps/system/no_embedded_paths/sdkconfig.ci.silentasserts.nimble @@ -8,6 +8,5 @@ CONFIG_COMPILER_HIDE_PATHS_MACROS=n CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n -CONFIG_BT_NIMBLE_MESH=y CONFIG_BLE_MESH=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1

        ~+HFjj* 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

      H&>iK+^|`8Yc2}%&_o@-AvTje=wSIrgm!G0- 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­mG>>ZL7< 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

      ~+HFjj* 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

    H&>iK+^|`8Yc2}%&_o@-AvTje=wSIrgm!G0- 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­mG>>ZL7< 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

    ~+HFjj* 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

H&>iK+^|`8Yc2}%&_o@-AvTje=wSIrgm!G0- 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­mG>>ZL7< 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