/*
 * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <errno.h>

#include "btc_ble_mesh_prov.h"
#include "btc_ble_mesh_config_model.h"
#include "btc_ble_mesh_health_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"

#if CONFIG_BLE_MESH_V11_SUPPORT
#include "btc_ble_mesh_prb_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 "mesh_v1.1/utils.h"
#endif /* CONFIG_BLE_MESH_V11_SUPPORT */

#include "adv.h"
#include "scan.h"
#include "mesh/kernel.h"
#include "mesh/proxy.h"
#include "mesh.h"
#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"
#include "pvnr_mgmt.h"
#include "heartbeat.h"

#if CONFIG_BLE_MESH_CFG_CLI
#include "mesh/cfg_cli.h"
#endif /* CONFIG_BLE_MESH_CFG_CLI */
#if CONFIG_BLE_MESH_HEALTH_CLI
#include "mesh/health_cli.h"
#endif /* CONFIG_BLE_MESH_HEALTH_CLI */
#include "mesh/cfg_srv.h"
#if CONFIG_BLE_MESH_HEALTH_SRV
#include "mesh/health_srv.h"
#endif /* CONFIG_BLE_MESH_HEALTH_SRV */
#if CONFIG_BLE_MESH_GENERIC_CLIENT
#include "mesh/generic_client.h"
#endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */
#if CONFIG_BLE_MESH_LIGHTING_CLIENT
#include "mesh/lighting_client.h"
#endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */
#if CONFIG_BLE_MESH_SENSOR_CLI
#include "mesh/sensor_client.h"
#endif /* CONFIG_BLE_MESH_SENSOR_CLI */
#if CONFIG_BLE_MESH_TIME_SCENE_CLIENT
#include "mesh/time_scene_client.h"
#endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */
#include "mesh/client_common.h"
#include "mesh/state_binding.h"
#include "local.h"

#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_networking_api.h"

#if CONFIG_BLE_MESH_DEINIT
static SemaphoreHandle_t deinit_comp_semaphore;
#endif

static inline void btc_ble_mesh_prov_cb_to_app_reprocess(esp_ble_mesh_prov_cb_event_t event,
                                                         esp_ble_mesh_prov_cb_param_t *param)
{
    switch (event) {
#if CONFIG_BLE_MESH_DEINIT
    case ESP_BLE_MESH_DEINIT_MESH_COMP_EVT:
        assert(deinit_comp_semaphore);
        /* Give the semaphore when BLE Mesh de-initialization is finished.
         * @note: At nimble host, once this lock is released, it will cause
         * the btc task to be deleted.
         */
        xSemaphoreGive(deinit_comp_semaphore);
        break;
#endif
    default:
        break;
    }
}

static inline void btc_ble_mesh_prov_cb_to_app(esp_ble_mesh_prov_cb_event_t event,
                                               esp_ble_mesh_prov_cb_param_t *param)
{
    esp_ble_mesh_prov_cb_t btc_ble_mesh_cb =
        (esp_ble_mesh_prov_cb_t)btc_profile_cb_get(BTC_PID_PROV);
    if (btc_ble_mesh_cb) {
        btc_ble_mesh_cb(event, param);
    }

    btc_ble_mesh_prov_cb_to_app_reprocess(event, param);
}

static inline void btc_ble_mesh_model_cb_to_app(esp_ble_mesh_model_cb_event_t event,
                                                esp_ble_mesh_model_cb_param_t *param)
{
    esp_ble_mesh_model_cb_t btc_ble_mesh_cb =
        (esp_ble_mesh_model_cb_t)btc_profile_cb_get(BTC_PID_MODEL);
    if (btc_ble_mesh_cb) {
        btc_ble_mesh_cb(event, param);
    }
}

void btc_ble_mesh_prov_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
    btc_ble_mesh_prov_args_t *dst = (btc_ble_mesh_prov_args_t *)p_dest;
    btc_ble_mesh_prov_args_t *src = (btc_ble_mesh_prov_args_t *)p_src;

    if (!msg || !dst || !src) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_ADD_FILTER_ADDR:
        dst->proxy_client_add_filter_addr.addr = (uint16_t *)bt_mesh_calloc(src->proxy_client_add_filter_addr.addr_num << 1);
        if (dst->proxy_client_add_filter_addr.addr) {
            memcpy(dst->proxy_client_add_filter_addr.addr, src->proxy_client_add_filter_addr.addr,
                   src->proxy_client_add_filter_addr.addr_num << 1);
        } else {
            BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
        }
        break;
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR:
        dst->proxy_client_remove_filter_addr.addr = bt_mesh_calloc(src->proxy_client_remove_filter_addr.addr_num << 1);
        if (dst->proxy_client_remove_filter_addr.addr) {
            memcpy(dst->proxy_client_remove_filter_addr.addr, src->proxy_client_remove_filter_addr.addr,
                   src->proxy_client_remove_filter_addr.addr_num << 1);
        } else {
            BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
        }
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_STORE_NODE_COMP_DATA:
        dst->store_node_comp_data.data = bt_mesh_calloc(src->store_node_comp_data.length);
        if (dst->store_node_comp_data.data) {
            memcpy(dst->store_node_comp_data.data, src->store_node_comp_data.data, src->store_node_comp_data.length);
        } 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_prov_arg_deep_free(btc_msg_t *msg)
{
    btc_ble_mesh_prov_args_t *arg = NULL;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    arg = (btc_ble_mesh_prov_args_t *)(msg->arg);

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_ADD_FILTER_ADDR:
        if (arg->proxy_client_add_filter_addr.addr) {
            bt_mesh_free(arg->proxy_client_add_filter_addr.addr);
        }
        break;
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR:
        if (arg->proxy_client_remove_filter_addr.addr) {
            bt_mesh_free(arg->proxy_client_remove_filter_addr.addr);
        }
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_STORE_NODE_COMP_DATA:
        if (arg->store_node_comp_data.data) {
            bt_mesh_free(arg->store_node_comp_data.data);
        }
        break;
    default:
        break;
    }
}

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;
    btc_ble_mesh_model_args_t *src = (btc_ble_mesh_model_args_t *)p_src;

    if (!msg || !dst || !src) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND:
    case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: {
        dst->model_send.data = src->model_send.length ? (uint8_t *)bt_mesh_malloc(src->model_send.length) : NULL;
        dst->model_send.ctx = bt_mesh_malloc(sizeof(esp_ble_mesh_msg_ctx_t));
        if (src->model_send.length) {
            if (dst->model_send.data) {
                memcpy(dst->model_send.data, src->model_send.data, src->model_send.length);
            } else {
                BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
            }
        }
        if (dst->model_send.ctx) {
            memcpy(dst->model_send.ctx, src->model_send.ctx, sizeof(esp_ble_mesh_msg_ctx_t));
        } else {
            BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
        }
        break;
    }
    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
        dst->model_update_state.value = bt_mesh_malloc(sizeof(esp_ble_mesh_server_state_value_t));
        if (dst->model_update_state.value) {
            memcpy(dst->model_update_state.value, src->model_update_state.value,
                   sizeof(esp_ble_mesh_server_state_value_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_model_arg_deep_free(btc_msg_t *msg)
{
    btc_ble_mesh_model_args_t *arg = NULL;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    arg = (btc_ble_mesh_model_args_t *)(msg->arg);

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND:
    case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND:
        if (arg->model_send.data) {
            bt_mesh_free(arg->model_send.data);
        }
        if (arg->model_send.ctx) {
            bt_mesh_free(arg->model_send.ctx);
        }
        break;
    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
        if (arg->model_update_state.value) {
            bt_mesh_free(arg->model_update_state.value);
        }
        break;
    default:
        break;
    }
}

static void btc_ble_mesh_model_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src)
{
    esp_ble_mesh_model_cb_param_t *p_dest_data = (esp_ble_mesh_model_cb_param_t *)p_dest;
    esp_ble_mesh_model_cb_param_t *p_src_data = (esp_ble_mesh_model_cb_param_t *)p_src;

    if (!msg || !p_src_data || !p_dest_data) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    switch (msg->act) {
    case ESP_BLE_MESH_MODEL_OPERATION_EVT: {
        if (p_src_data->model_operation.ctx && p_src_data->model_operation.msg) {
            p_dest_data->model_operation.ctx = bt_mesh_malloc(sizeof(esp_ble_mesh_msg_ctx_t));
            p_dest_data->model_operation.msg = p_src_data->model_operation.length ? (uint8_t *)bt_mesh_malloc(p_src_data->model_operation.length) : NULL;
            if (p_dest_data->model_operation.ctx) {
                memcpy(p_dest_data->model_operation.ctx, p_src_data->model_operation.ctx, sizeof(esp_ble_mesh_msg_ctx_t));
            } else {
                BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
            }
            if (p_src_data->model_operation.length) {
                if (p_dest_data->model_operation.msg) {
                    memcpy(p_dest_data->model_operation.msg, p_src_data->model_operation.msg, p_src_data->model_operation.length);
                } else {
                    BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
                }
            }
        }
        break;
    }
    case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: {
        if (p_src_data->client_recv_publish_msg.ctx && p_src_data->client_recv_publish_msg.msg) {
            p_dest_data->client_recv_publish_msg.ctx = bt_mesh_malloc(sizeof(esp_ble_mesh_msg_ctx_t));
            p_dest_data->client_recv_publish_msg.msg = p_src_data->client_recv_publish_msg.length ? (uint8_t *)bt_mesh_malloc(p_src_data->client_recv_publish_msg.length) : NULL;
            if (p_dest_data->client_recv_publish_msg.ctx) {
                memcpy(p_dest_data->client_recv_publish_msg.ctx, p_src_data->client_recv_publish_msg.ctx, sizeof(esp_ble_mesh_msg_ctx_t));
            } else {
                BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
            }
            if (p_src_data->client_recv_publish_msg.length) {
                if (p_dest_data->client_recv_publish_msg.msg) {
                    memcpy(p_dest_data->client_recv_publish_msg.msg, p_src_data->client_recv_publish_msg.msg, p_src_data->client_recv_publish_msg.length);
                } else {
                    BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
                }
            }
        }
        break;
    }
    case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: {
        if (p_src_data->model_send_comp.ctx) {
            p_dest_data->model_send_comp.ctx = bt_mesh_malloc(sizeof(esp_ble_mesh_msg_ctx_t));
            if (p_dest_data->model_send_comp.ctx) {
                memcpy(p_dest_data->model_send_comp.ctx, p_src_data->model_send_comp.ctx, sizeof(esp_ble_mesh_msg_ctx_t));
            } else {
                BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
            }
        }
        break;
    }
    case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: {
        if (p_src_data->client_send_timeout.ctx) {
            p_dest_data->client_send_timeout.ctx = bt_mesh_malloc(sizeof(esp_ble_mesh_msg_ctx_t));
            if (p_dest_data->client_send_timeout.ctx) {
                memcpy(p_dest_data->client_send_timeout.ctx, p_src_data->client_send_timeout.ctx, sizeof(esp_ble_mesh_msg_ctx_t));
            } else {
                BT_ERR("%s, Out of memory, act %d", __func__, msg->act);
            }
        }
        break;
    }
    default:
        break;
    }
}

static void btc_ble_mesh_model_free_req_data(btc_msg_t *msg)
{
    esp_ble_mesh_model_cb_param_t *arg = NULL;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    arg = (esp_ble_mesh_model_cb_param_t *)(msg->arg);

    switch (msg->act) {
    case ESP_BLE_MESH_MODEL_OPERATION_EVT: {
        if (arg->model_operation.msg) {
            bt_mesh_free(arg->model_operation.msg);
        }
        if (arg->model_operation.ctx) {
            bt_mesh_free(arg->model_operation.ctx);
        }
        break;
    }
    case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT: {
        if (arg->client_recv_publish_msg.msg) {
            bt_mesh_free(arg->client_recv_publish_msg.msg);
        }
        if (arg->client_recv_publish_msg.ctx) {
            bt_mesh_free(arg->client_recv_publish_msg.ctx);
        }
        break;
    }
    case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: {
        if (arg->model_send_comp.ctx) {
            bt_mesh_free(arg->model_send_comp.ctx);
        }
        break;
    }
    case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: {
        if (arg->client_send_timeout.ctx) {
            bt_mesh_free(arg->client_send_timeout.ctx);
        }
        break;
    }
    default:
        break;
    }
}

static bt_status_t btc_ble_mesh_model_callback(esp_ble_mesh_model_cb_param_t *param, uint8_t act)
{
    btc_msg_t msg = {0};
    bt_status_t ret = BT_STATUS_SUCCESS;

    /* If corresponding callback is not registered, event will not be posted. */
    if (!btc_profile_cb_get(BTC_PID_MODEL)) {
        return BT_STATUS_SUCCESS;
    }

    msg.sig = BTC_SIG_API_CB;
    msg.pid = BTC_PID_MODEL;
    msg.act = act;

    ret = btc_transfer_context(&msg, param, param == NULL ? 0 : sizeof(esp_ble_mesh_model_cb_param_t),
                               btc_ble_mesh_model_copy_req_data, btc_ble_mesh_model_free_req_data);
    if (ret != BT_STATUS_SUCCESS) {
        BT_ERR("btc_transfer_context failed");
    }
    return ret;
}

static void btc_ble_mesh_server_model_op_cb(struct bt_mesh_model *model,
                                            struct bt_mesh_msg_ctx *ctx,
                                            struct net_buf_simple *buf)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};

    mesh_param.model_operation.opcode = ctx->recv_op;
    mesh_param.model_operation.model = (esp_ble_mesh_model_t *)model;
    mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx;
    mesh_param.model_operation.length = buf->len;
    mesh_param.model_operation.msg = buf->data;

    btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_OPERATION_EVT);
}

static void btc_ble_mesh_client_model_op_cb(struct bt_mesh_model *model,
                                            struct bt_mesh_msg_ctx *ctx,
                                            struct net_buf_simple *buf)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};
    bt_mesh_client_node_t *node = NULL;

    if (!model || !model->user_data || !ctx || !buf) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    bt_mesh_client_model_lock();

    node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, false);
    if (node == NULL) {
        mesh_param.client_recv_publish_msg.opcode = ctx->recv_op;
        mesh_param.client_recv_publish_msg.model = (esp_ble_mesh_model_t *)model;
        mesh_param.client_recv_publish_msg.ctx = (esp_ble_mesh_msg_ctx_t *)ctx;
        mesh_param.client_recv_publish_msg.length = buf->len;
        mesh_param.client_recv_publish_msg.msg = buf->data;
        btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT);
    } else {
        mesh_param.model_operation.opcode = ctx->recv_op;
        mesh_param.model_operation.model = (esp_ble_mesh_model_t *)model;
        mesh_param.model_operation.ctx = (esp_ble_mesh_msg_ctx_t *)ctx;
        mesh_param.model_operation.length = buf->len;
        mesh_param.model_operation.msg = buf->data;
        if (!k_delayed_work_free(&node->timer)) {
            bt_mesh_client_free_node(node);
            btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_OPERATION_EVT);
        }
    }

    bt_mesh_client_model_unlock();
}

static void btc_ble_mesh_client_model_timeout_cb(struct k_work *work)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};
    struct k_delayed_work *timer = NULL;
    bt_mesh_client_node_t *node = NULL;
    struct bt_mesh_msg_ctx ctx = {0};

    bt_mesh_client_model_lock();

    timer = CONTAINER_OF(work, struct k_delayed_work, work);

    if (timer && !k_delayed_work_free(timer)) {
        node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.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 *)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);
        }
    }

    bt_mesh_client_model_unlock();
}

static void btc_ble_mesh_model_send_comp_cb(esp_ble_mesh_model_t *model,
                                            esp_ble_mesh_msg_ctx_t *ctx,
                                            uint32_t opcode, int err)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};

    mesh_param.model_send_comp.err_code = err;
    mesh_param.model_send_comp.opcode = opcode;
    mesh_param.model_send_comp.model = model;
    mesh_param.model_send_comp.ctx = ctx;

    btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_SEND_COMP_EVT);
}

static void btc_ble_mesh_model_publish_comp_cb(esp_ble_mesh_model_t *model, int err)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};

    mesh_param.model_publish_comp.err_code = err;
    mesh_param.model_publish_comp.model = model;

    btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT);
}

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;

    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);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

#if CONFIG_BLE_MESH_SERVER_MODEL
static void btc_ble_mesh_server_model_update_state_comp_cb(esp_ble_mesh_model_t *model,
                                                           esp_ble_mesh_server_state_type_t type,
                                                           int err)
{
    esp_ble_mesh_model_cb_param_t mesh_param = {0};

    mesh_param.server_model_update_state.err_code = err;
    mesh_param.server_model_update_state.model = model;
    mesh_param.server_model_update_state.type = type;

    btc_ble_mesh_model_callback(&mesh_param, ESP_BLE_MESH_SERVER_MODEL_UPDATE_STATE_COMP_EVT);
}
#endif /* CONFIG_BLE_MESH_SERVER_MODEL */

static bt_status_t btc_ble_mesh_prov_callback(esp_ble_mesh_prov_cb_param_t *param, uint8_t act)
{
    btc_msg_t msg = {0};
    bt_status_t ret = BT_STATUS_SUCCESS;

    /* If corresponding callback is not registered, event will not be posted. */
    if (!btc_profile_cb_get(BTC_PID_PROV)) {
        return BT_STATUS_SUCCESS;
    }

    msg.sig = BTC_SIG_API_CB;
    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),
                               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)
{
    btc_ble_mesh_prov_callback(NULL, ESP_BLE_MESH_NODE_PROV_OOB_PUB_KEY_EVT);
}

static int btc_ble_mesh_output_number_cb(bt_mesh_output_action_t act, uint32_t num)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};
    bt_status_t ret = BT_STATUS_SUCCESS;

    mesh_param.node_prov_output_num.action = (esp_ble_mesh_output_action_t)act;
    mesh_param.node_prov_output_num.number = num;

    ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

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;

    strncpy(mesh_param.node_prov_output_str.string, str,
            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;
}

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;

    mesh_param.node_prov_input.action = (esp_ble_mesh_input_action_t)act;
    mesh_param.node_prov_input.size = size;

    ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_INPUT_EVT);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

static void btc_ble_mesh_link_open_cb(bt_mesh_prov_bearer_t bearer)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    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);
}

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};

    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);
}

static void btc_ble_mesh_complete_cb(uint16_t net_idx, const uint8_t net_key[16],
                                     uint16_t addr, uint8_t flags, uint32_t iv_index)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    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;
    mesh_param.node_prov_complete.flags = flags;
    mesh_param.node_prov_complete.iv_index = iv_index;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT);
}

static void btc_ble_mesh_reset_cb(void)
{
    btc_ble_mesh_prov_callback(NULL, ESP_BLE_MESH_NODE_PROV_RESET_EVT);
}

const uint8_t *btc_ble_mesh_node_get_local_net_key(uint16_t net_idx)
{
    return bt_mesh_node_get_local_net_key(net_idx);
}

const uint8_t *btc_ble_mesh_node_get_local_app_key(uint16_t app_idx)
{
    return bt_mesh_node_get_local_app_key(app_idx);
}
#endif /* CONFIG_BLE_MESH_NODE */

static void btc_ble_mesh_prov_register_complete_cb(int err_code)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    mesh_param.prov_register_comp.err_code = err_code;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROV_REGISTER_COMP_EVT);
}

static void btc_ble_mesh_prov_set_complete_cb(esp_ble_mesh_prov_cb_param_t *param, uint8_t act)
{
    btc_ble_mesh_prov_callback(param, act);
}

#if CONFIG_BLE_MESH_PROVISIONER
static void btc_ble_mesh_provisioner_recv_unprov_adv_pkt_cb(const uint8_t addr[6], const uint8_t addr_type,
                                                            const uint8_t adv_type, const uint8_t dev_uuid[16],
                                                            uint16_t oob_info, bt_mesh_prov_bearer_t bearer,
                                                            int8_t rssi)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (addr == NULL || dev_uuid == NULL ||
        (bearer != BLE_MESH_PROV_ADV && bearer != BLE_MESH_PROV_GATT)) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    memcpy(mesh_param.provisioner_recv_unprov_adv_pkt.dev_uuid, dev_uuid, 16);
    memcpy(mesh_param.provisioner_recv_unprov_adv_pkt.addr, addr, BLE_MESH_ADDR_LEN);
    mesh_param.provisioner_recv_unprov_adv_pkt.addr_type = addr_type;
    mesh_param.provisioner_recv_unprov_adv_pkt.oob_info = oob_info;
    mesh_param.provisioner_recv_unprov_adv_pkt.adv_type = adv_type;
    mesh_param.provisioner_recv_unprov_adv_pkt.bearer = bearer;
    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);
}

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;

    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);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

static int btc_ble_mesh_provisioner_prov_input_cb(uint8_t method, bt_mesh_output_action_t act,
                                                  uint8_t size, uint8_t link_idx)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};
    bt_status_t ret = BT_STATUS_SUCCESS;

    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;
    mesh_param.provisioner_prov_input.link_idx = link_idx;

    ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_INPUT_EVT);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

static int btc_ble_mesh_provisioner_prov_output_cb(uint8_t method, bt_mesh_input_action_t act,
                                                   void *data, uint8_t size, uint8_t link_idx)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};
    bt_status_t ret = BT_STATUS_SUCCESS;

    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;
    mesh_param.provisioner_prov_output.link_idx = link_idx;
    if (act == BLE_MESH_ENTER_STRING) {
        strncpy(mesh_param.provisioner_prov_output.string, (char *)data, size);
    } else {
        mesh_param.provisioner_prov_output.number = sys_get_le32((uint8_t *)data);
    }

    ret = btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_PROV_OUTPUT_EVT);
    return (ret == BT_STATUS_SUCCESS) ? 0 : -1;
}

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};

    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);
}

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};

    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);
}

static void btc_ble_mesh_provisioner_prov_complete_cb(uint16_t node_idx, const uint8_t device_uuid[16],
                                                      uint16_t unicast_addr, uint8_t element_num,
                                                      uint16_t netkey_idx)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    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;
    mesh_param.provisioner_prov_complete.netkey_idx = netkey_idx;
    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);
}

#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);
}

esp_ble_mesh_node_t *btc_ble_mesh_provisioner_get_node_with_addr(uint16_t unicast_addr)
{
    return (esp_ble_mesh_node_t *)bt_mesh_provisioner_get_node_with_addr(unicast_addr);
}

esp_ble_mesh_node_t *btc_ble_mesh_provisioner_get_node_with_name(const char *name)
{
    return (esp_ble_mesh_node_t *)bt_mesh_provisioner_get_node_with_name(name);
}

uint16_t btc_ble_mesh_provisioner_get_prov_node_count(void)
{
    return bt_mesh_provisioner_get_node_count();
}

const esp_ble_mesh_node_t **btc_ble_mesh_provisioner_get_node_table_entry(void)
{
    return (const esp_ble_mesh_node_t **)bt_mesh_provisioner_get_node_table_entry();
}

#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB
static void btc_ble_mesh_provisioner_recv_heartbeat_cb(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)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    mesh_param.provisioner_recv_heartbeat.hb_src = hb_src;
    mesh_param.provisioner_recv_heartbeat.hb_dst = hb_dst;
    mesh_param.provisioner_recv_heartbeat.init_ttl = init_ttl;
    mesh_param.provisioner_recv_heartbeat.rx_ttl = rx_ttl;
    mesh_param.provisioner_recv_heartbeat.hops = hops;
    mesh_param.provisioner_recv_heartbeat.feature = feat;
    mesh_param.provisioner_recv_heartbeat.rssi = rssi;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT);
}
#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */

#if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
const char *btc_ble_mesh_provisioner_get_settings_uid(uint8_t index)
{
    return bt_mesh_provisioner_get_settings_uid(index);
}

uint8_t btc_ble_mesh_provisioner_get_settings_index(const char *uid)
{
    return bt_mesh_provisioner_get_settings_index(uid);
}

uint8_t btc_ble_mesh_provisioner_get_free_settings_count(void)
{
    return bt_mesh_provisioner_get_free_settings_count();
}
#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */

#endif /* CONFIG_BLE_MESH_PROVISIONER */

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};

    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);
}

#if CONFIG_BLE_MESH_LOW_POWER
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;

    if (established) {
        mesh_param.lpn_friendship_establish.friend_addr = friend_addr;
        act = ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT;
    } else {
        mesh_param.lpn_friendship_terminate.friend_addr = friend_addr;
        act = ESP_BLE_MESH_LPN_FRIENDSHIP_TERMINATE_EVT;
    }

    btc_ble_mesh_prov_callback(&mesh_param, act);
}
#endif /* CONFIG_BLE_MESH_LOW_POWER */

#if CONFIG_BLE_MESH_FRIEND
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;

    if (!BLE_MESH_ADDR_IS_UNICAST(lpn_addr)) {
        BT_ERR("Not a unicast lpn address 0x%04x", lpn_addr);
        return;
    }

    if (establish) {
        mesh_param.frnd_friendship_establish.lpn_addr = lpn_addr;
        act = ESP_BLE_MESH_FRIEND_FRIENDSHIP_ESTABLISH_EVT;
    } else {
        mesh_param.frnd_friendship_terminate.lpn_addr = lpn_addr;
        mesh_param.frnd_friendship_terminate.reason = reason;
        act = ESP_BLE_MESH_FRIEND_FRIENDSHIP_TERMINATE_EVT;
    }

    btc_ble_mesh_prov_callback(&mesh_param, act);
}
#endif /* CONFIG_BLE_MESH_FRIEND */

#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT
static void btc_ble_mesh_proxy_client_adv_recv_cb(const bt_mesh_addr_t *addr, uint8_t type,
                                                  bt_mesh_proxy_adv_ctx_t *ctx, int8_t rssi)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (!addr || !ctx || type != BLE_MESH_PROXY_ADV_NET_ID) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    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;
    memcpy(mesh_param.proxy_client_recv_adv_pkt.net_id, ctx->net_id.net_id, 8);
    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);
}

static void btc_ble_mesh_proxy_client_connect_cb(const bt_mesh_addr_t *addr,
                                                 uint8_t conn_handle, uint16_t net_idx)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (!addr || conn_handle >= BLE_MESH_MAX_CONN) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    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);
}

static void btc_ble_mesh_proxy_client_disconnect_cb(const bt_mesh_addr_t *addr, uint8_t conn_handle,
                                                    uint16_t net_idx, uint8_t reason)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (!addr || conn_handle >= BLE_MESH_MAX_CONN) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    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;
    mesh_param.proxy_client_disconnected.net_idx = net_idx;
    mesh_param.proxy_client_disconnected.reason = reason;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_CLIENT_DISCONNECTED_EVT);
}

static void btc_ble_mesh_proxy_client_filter_status_recv_cb(uint8_t conn_handle, uint16_t src, uint16_t net_idx,
                                                            uint8_t filter_type, uint16_t list_size)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (conn_handle >= BLE_MESH_MAX_CONN) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    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;
    mesh_param.proxy_client_recv_filter_status.filter_type = filter_type;
    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);
}
#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */

#if CONFIG_BLE_MESH_GATT_PROXY_SERVER
static void btc_ble_mesh_proxy_server_connect_cb(uint8_t conn_handle)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (conn_handle >= BLE_MESH_MAX_CONN) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    mesh_param.proxy_server_connected.conn_handle = conn_handle;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_SERVER_CONNECTED_EVT);
}

static void btc_ble_mesh_proxy_server_disconnect_cb(uint8_t conn_handle, uint8_t reason)
{
    esp_ble_mesh_prov_cb_param_t mesh_param = {0};

    if (conn_handle >= BLE_MESH_MAX_CONN) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    mesh_param.proxy_server_disconnected.conn_handle = conn_handle;
    mesh_param.proxy_server_disconnected.reason = reason;

    btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROXY_SERVER_DISCONNECTED_EVT);
}
#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */

int btc_ble_mesh_client_model_init(esp_ble_mesh_model_t *model)
{
    if (!bt_mesh_is_initialized()) {
        BT_ERR("Mesh stack is not initialized!");
        return -EINVAL;
    }

    __ASSERT(model && model->op, "Invalid parameter");
    esp_ble_mesh_model_op_t *op = model->op;
    while (op && op->opcode != 0) {
        op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_client_model_op_cb;
        op++;
    }
    return bt_mesh_client_init((struct bt_mesh_model *)model);
}

#if CONFIG_BLE_MESH_DEINIT
int btc_ble_mesh_client_model_deinit(esp_ble_mesh_model_t *model)
{
    return bt_mesh_client_deinit((struct bt_mesh_model *)model);
}
#endif /* CONFIG_BLE_MESH_DEINIT */

int32_t btc_ble_mesh_model_pub_period_get(esp_ble_mesh_model_t *mod)
{
    return bt_mesh_model_pub_period_get((struct bt_mesh_model *)mod);
}

uint16_t btc_ble_mesh_get_primary_addr(void)
{
    return bt_mesh_primary_addr();
}

uint16_t *btc_ble_mesh_model_find_group(esp_ble_mesh_model_t *mod, uint16_t addr)
{
    return bt_mesh_model_find_group((struct bt_mesh_model *)mod, addr);
}

esp_ble_mesh_elem_t *btc_ble_mesh_elem_find(uint16_t addr)
{
    return (esp_ble_mesh_elem_t *)bt_mesh_elem_find(addr);
}

uint8_t btc_ble_mesh_elem_count(void)
{
    return bt_mesh_elem_count();
}

esp_ble_mesh_model_t *btc_ble_mesh_model_find_vnd(const esp_ble_mesh_elem_t *elem,
                                                  uint16_t company, uint16_t id)
{
    return (esp_ble_mesh_model_t *)bt_mesh_model_find_vnd((struct bt_mesh_elem *)elem, company, id);
}

esp_ble_mesh_model_t *btc_ble_mesh_model_find(const esp_ble_mesh_elem_t *elem, uint16_t id)
{
    return (esp_ble_mesh_model_t *)bt_mesh_model_find((struct bt_mesh_elem *)elem, id);
}

const esp_ble_mesh_comp_t *btc_ble_mesh_comp_get(void)
{
    return (const esp_ble_mesh_comp_t *)bt_mesh_comp_get();
}

/* Configuration Models */
extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb;
#if CONFIG_BLE_MESH_CFG_CLI
extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb;
#endif /* CONFIG_BLE_MESH_CFG_CLI */

/* Health Models */
#if CONFIG_BLE_MESH_HEALTH_SRV
extern const struct bt_mesh_model_op bt_mesh_health_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_health_srv_cb;
#endif /* CONFIG_BLE_MESH_HEALTH_SRV */
#if CONFIG_BLE_MESH_HEALTH_CLI
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[];
extern const struct bt_mesh_model_op bt_mesh_gen_level_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_def_trans_time_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_onoff_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_level_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_battery_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_location_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_property_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_generic_client_cb;
#endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */

/* Lighting Client Models */
#if CONFIG_BLE_MESH_LIGHTING_CLIENT
extern const struct bt_mesh_model_op bt_mesh_light_lightness_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_light_ctl_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_light_hsl_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_light_xyl_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_light_lc_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_lighting_client_cb;
#endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */

/* Sensor Client Models */
#if CONFIG_BLE_MESH_SENSOR_CLI
extern const struct bt_mesh_model_op bt_mesh_sensor_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_sensor_client_cb;
#endif /* CONFIG_BLE_MESH_SENSOR_CLI */

/* Time and Scenes Client Models */
#if CONFIG_BLE_MESH_TIME_SCENE_CLIENT
extern const struct bt_mesh_model_op bt_mesh_time_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_scene_cli_op[];
extern const struct bt_mesh_model_op bt_mesh_scheduler_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_time_scene_client_cb;
#endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */

/* Generic Server Models */
#if CONFIG_BLE_MESH_GENERIC_SERVER
extern const struct bt_mesh_model_op bt_mesh_gen_onoff_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_level_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_def_trans_time_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_onoff_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_onoff_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_level_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_power_level_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_battery_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_location_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_location_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_user_prop_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_admin_prop_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_manu_prop_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_gen_client_prop_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_gen_onoff_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_level_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_def_trans_time_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_power_onoff_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_power_onoff_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_power_level_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_power_level_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_battery_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_location_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_location_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_user_prop_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_admin_prop_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_manu_prop_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_gen_client_prop_srv_cb;
#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */

/* Lighting Server Models */
#if CONFIG_BLE_MESH_LIGHTING_SERVER
extern const struct bt_mesh_model_op bt_mesh_light_lightness_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_lightness_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_ctl_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_ctl_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_ctl_temp_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_hsl_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_hsl_hue_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_hsl_sat_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_hsl_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_xyl_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_xyl_setup_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_light_lightness_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_lightness_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_ctl_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_ctl_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_ctl_temp_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_hsl_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_hsl_hue_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_hsl_sat_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_hsl_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_xyl_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_xyl_setup_srv_cb;
extern const struct bt_mesh_model_op bt_mesh_light_lc_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_light_lc_setup_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_light_lc_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_light_lc_setup_srv_cb;
#endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */

/* Time and Scenes Server Models */
#if CONFIG_BLE_MESH_TIME_SCENE_SERVER
extern const struct bt_mesh_model_op bt_mesh_time_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_time_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_scene_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_scene_setup_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_scheduler_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_scheduler_setup_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_time_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_time_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_scene_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_scene_setup_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_scheduler_srv_cb;
extern const struct bt_mesh_model_cb bt_mesh_scheduler_setup_srv_cb;
#endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */

/* Sensor Server Models */
#if CONFIG_BLE_MESH_SENSOR_SERVER
extern const struct bt_mesh_model_op bt_mesh_sensor_srv_op[];
extern const struct bt_mesh_model_op bt_mesh_sensor_setup_srv_op[];
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 */
#if CONFIG_BLE_MESH_BLOB_SRV
extern const struct bt_mesh_model_op _bt_mesh_blob_srv_op[];
extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb;
#endif /* CONFIG_BLE_MESH_BLOB_SRV */
#if CONFIG_BLE_MESH_BLOB_CLI
typedef bt_mesh_client_user_data_t bt_mesh_blob_client_t;
extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[];
extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb;
#endif /* CONFIG_BLE_MESH_BLOB_CLI */
#if CONFIG_BLE_MESH_DFU_SRV
extern const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[];
extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb;
#endif /* CONFIG_BLE_MESH_DFU_SRV */
#if CONFIG_BLE_MESH_DFU_CLI
extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[];
extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb;
#endif /* CONFIG_BLE_MESH_DFU_CLI */
#if CONFIG_BLE_MESH_DFD_SRV
extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[];
extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb;
#endif /* CONFIG_BLE_MESH_DFD_SRV */
#if CONFIG_BLE_MESH_DFD_CLI
extern const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[];
extern const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb;
#endif /* CONFIG_BLE_MESH_DFD_CLI */

static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model)
{
    if (!model) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    /* For SIG client and server models, model->op will be NULL and initialized here.
     * For vendor models whose opcode is 3 bytes, model->op will be initialized here.
     */
    if (model->op && BLE_MESH_MODEL_OP_LEN(model->op->opcode) == 3) {
        goto set_vnd_op;
    }

    switch (model->model_id) {
    case BLE_MESH_MODEL_ID_CFG_SRV: {
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_cfg_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_cfg_srv_cb;
        struct bt_mesh_cfg_srv *srv = (struct bt_mesh_cfg_srv *)model->user_data;
        if (srv) {
            srv->hb_sub.func = btc_ble_mesh_node_recv_heartbeat_cb;
        }
        break;
    }
#if CONFIG_BLE_MESH_CFG_CLI
    case BLE_MESH_MODEL_ID_CFG_CLI: {
        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) {
            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: {
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_health_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_health_srv_cb;
        struct bt_mesh_health_srv *srv = (struct bt_mesh_health_srv *)model->user_data;
        if (srv) {
            srv->cb.fault_clear = btc_ble_mesh_health_server_fault_clear;
            srv->cb.fault_test = btc_ble_mesh_health_server_fault_test;
            srv->cb.attn_on = btc_ble_mesh_health_server_attention_on;
            srv->cb.attn_off = btc_ble_mesh_health_server_attention_off;
        }
        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) {
            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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LEVEL_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_BATTERY_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LOCATION_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_generic_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_PROP_CLI: {
        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) {
            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) {
            cli->publish_status = btc_ble_mesh_lighting_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_LIGHT_CTL_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_lighting_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_LIGHT_HSL_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_lighting_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_LIGHT_XYL_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_lighting_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_LIGHT_LC_CLI: {
        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) {
            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) {
            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) {
            cli->publish_status = btc_ble_mesh_time_scene_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_SCENE_CLI: {
        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) {
            cli->publish_status = btc_ble_mesh_time_scene_client_publish_callback;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_SCHEDULER_CLI: {
        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) {
            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:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_onoff_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_onoff_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_level_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_level_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_def_trans_time_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_def_trans_time_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_onoff_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_power_onoff_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_onoff_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_power_onoff_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_level_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_power_level_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_power_level_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_power_level_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_battery_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_battery_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_location_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_location_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_user_prop_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_user_prop_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_admin_prop_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_admin_prop_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_manu_prop_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_manu_prop_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_client_prop_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_client_prop_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_gen_location_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_gen_location_setup_srv_cb;
        if (model->pub) {
            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:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lightness_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_lightness_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lightness_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_lightness_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_ctl_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_ctl_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_ctl_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_ctl_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_ctl_temp_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_ctl_temp_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_hsl_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_hsl_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_hsl_hue_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_hsl_hue_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_hsl_sat_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_hsl_sat_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_hsl_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_hsl_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_XYL_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_xyl_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_xyl_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_xyl_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_xyl_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_LC_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lc_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_lc_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_light_lc_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_light_lc_setup_srv_cb;
        if (model->pub) {
            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:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_time_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_time_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_TIME_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_time_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_time_setup_srv_cb;
        if (model->pub) {
            /* Time Setup Server model does not support subscribing nor publishing. */
            BT_ERR("Time Setup Server shall not support publication");
            return;
        }
        break;
    case BLE_MESH_MODEL_ID_SCENE_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scene_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_scene_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_SCENE_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scene_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_scene_setup_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_SCHEDULER_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scheduler_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_scheduler_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_scheduler_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_scheduler_setup_srv_cb;
        if (model->pub) {
            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:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_sensor_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_sensor_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
    case BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV:
        model->op = (esp_ble_mesh_model_op_t *)bt_mesh_sensor_setup_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_sensor_setup_srv_cb;
        if (model->pub) {
            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 *mbt_cli = (bt_mesh_mbt_client_t *)model->user_data;
        if (mbt_cli) {
            mbt_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 */
#if CONFIG_BLE_MESH_BLOB_CLI
    case BLE_MESH_MODEL_ID_BLOB_CLI:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_cli_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_cli_cb;
        bt_mesh_blob_client_t *blob_cli = (bt_mesh_blob_client_t *)model->user_data;
        if (blob_cli) {
            /* TBD: do we need publish callback for Blob Transfer Client model? */
        }
        break;
#endif /* CONFIG_BLE_MESH_BLOB_CLI */
#if CONFIG_BLE_MESH_BLOB_SRV
    case BLE_MESH_MODEL_ID_BLOB_SRV:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
#endif /* CONFIG_BLE_MESH_BLOB_SRV */
#if CONFIG_BLE_MESH_DFU_CLI
    case BLE_MESH_MODEL_ID_DFU_CLI:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_cli_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_cli_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
#endif /* CONFIG_BLE_MESH_DFU_CLI */
#if CONFIG_BLE_MESH_DFU_SRV
    case BLE_MESH_MODEL_ID_DFU_SRV:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
#endif /* CONFIG_BLE_MESH_DFU_SRV */
#if CONFIG_BLE_MESH_DFD_SRV
    case BLE_MESH_MODEL_ID_DFD_SRV:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_srv_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_srv_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
#endif /* CONFIG_BLE_MESH_DFD_SRV */
#if CONFIG_BLE_MESH_DFD_CLI
    case BLE_MESH_MODEL_ID_DFD_CLI:
        model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_cli_op;
        model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_cli_cb;
        if (model->pub) {
            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
        }
        break;
#endif /* CONFIG_BLE_MESH_DFD_SRV */
    default:
        goto set_vnd_op;
    }
    return;

set_vnd_op:
    if (model->pub) {
        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 && op->opcode != 0) {
        op->param_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_server_model_op_cb;
        op++;
    }
}

void btc_ble_mesh_prov_call_handler(btc_msg_t *msg)
{
    esp_ble_mesh_prov_cb_param_t param = {0};
    btc_ble_mesh_prov_args_t *arg = NULL;
    uint8_t act = 0U;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    arg = (btc_ble_mesh_prov_args_t *)(msg->arg);

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_MESH_INIT: {
        for (int i = 0; i < arg->mesh_init.comp->element_count; i++) {
            esp_ble_mesh_elem_t *elem = &arg->mesh_init.comp->elements[i];

            for (int j = 0; j < elem->sig_model_count; j++) {
                esp_ble_mesh_model_t *sig_model = &elem->sig_models[j];
                if (sig_model->op && BLE_MESH_MODEL_OP_LEN(sig_model->op->opcode) == 3) {
                    /* Opcode of SIG model must be 1 or 2 bytes. */
                    btc_ble_mesh_prov_register_complete_cb(-EINVAL);
                    return;
                }
                btc_ble_mesh_model_op_set(sig_model);
            }

            for (int k = 0; k < elem->vnd_model_count; k++) {
                esp_ble_mesh_model_t *vnd_model = &elem->vnd_models[k];
                if (vnd_model->op && BLE_MESH_MODEL_OP_LEN(vnd_model->op->opcode) < 3) {
                    /* Opcode of vendor model must be 3 bytes. */
                    btc_ble_mesh_prov_register_complete_cb(-EINVAL);
                    return;
                }
                btc_ble_mesh_model_op_set(vnd_model);
            }
        }
#if CONFIG_BLE_MESH_NODE
        arg->mesh_init.prov->oob_pub_key_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_oob_pub_key_cb;
        arg->mesh_init.prov->output_num_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_output_number_cb;
        arg->mesh_init.prov->output_str_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_output_string_cb;
        arg->mesh_init.prov->input_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_input_cb;
        arg->mesh_init.prov->link_open_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_link_open_cb;
        arg->mesh_init.prov->link_close_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_link_close_cb;
        arg->mesh_init.prov->complete_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_complete_cb;
        arg->mesh_init.prov->reset_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_reset_cb;
#endif /* CONFIG_BLE_MESH_NODE */
#if CONFIG_BLE_MESH_PROVISIONER
        arg->mesh_init.prov->provisioner_prov_read_oob_pub_key = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_prov_read_oob_pub_key_cb;
        arg->mesh_init.prov->provisioner_prov_input = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_prov_input_cb;
        arg->mesh_init.prov->provisioner_prov_output = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_prov_output_cb;
        arg->mesh_init.prov->provisioner_link_open = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_link_open_cb;
        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);
#endif /* CONFIG_BLE_MESH_LOW_POWER */
#if CONFIG_BLE_MESH_FRIEND
        bt_mesh_friend_set_cb(btc_ble_mesh_friend_cb);
#endif /* CONFIG_BLE_MESH_FRIEND */
#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT
        bt_mesh_proxy_client_set_adv_recv_cb(btc_ble_mesh_proxy_client_adv_recv_cb);
        bt_mesh_proxy_client_set_conn_cb(btc_ble_mesh_proxy_client_connect_cb);
        bt_mesh_proxy_client_set_disconn_cb(btc_ble_mesh_proxy_client_disconnect_cb);
        bt_mesh_proxy_client_set_filter_status_cb(btc_ble_mesh_proxy_client_filter_status_recv_cb);
#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */
#if CONFIG_BLE_MESH_GATT_PROXY_SERVER
        bt_mesh_proxy_server_set_conn_cb(btc_ble_mesh_proxy_server_connect_cb);
        bt_mesh_proxy_server_set_disconn_cb(btc_ble_mesh_proxy_server_disconnect_cb);
#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */
        int err_code = bt_mesh_init((struct bt_mesh_prov *)arg->mesh_init.prov,
                                    (struct bt_mesh_comp *)arg->mesh_init.comp);
        /* Give the semaphore when BLE Mesh initialization is finished. */
        xSemaphoreGive(arg->mesh_init.semaphore);
        btc_ble_mesh_prov_register_complete_cb(err_code);
        return;
    }
#if CONFIG_BLE_MESH_NODE
    case BTC_BLE_MESH_ACT_PROV_ENABLE:
        act = ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT;
        param.node_prov_enable_comp.err_code = bt_mesh_prov_enable(arg->node_prov_enable.bearers);
        break;
    case BTC_BLE_MESH_ACT_PROV_DISABLE:
        act = ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT;
        param.node_prov_disable_comp.err_code = bt_mesh_prov_disable(arg->node_prov_disable.bearers);
        break;
    case BTC_BLE_MESH_ACT_NODE_RESET:
        bt_mesh_node_reset();
        return;
    case BTC_BLE_MESH_ACT_SET_OOB_PUB_KEY:
        act = ESP_BLE_MESH_NODE_PROV_SET_OOB_PUB_KEY_COMP_EVT;
        param.node_prov_set_oob_pub_key_comp.err_code =
            bt_mesh_set_oob_pub_key(arg->set_oob_pub_key.pub_key_x,
                                    arg->set_oob_pub_key.pub_key_y,
                                    arg->set_oob_pub_key.private_key);
        break;
    case BTC_BLE_MESH_ACT_INPUT_NUMBER:
        act = ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT;
        param.node_prov_input_num_comp.err_code = bt_mesh_input_number(arg->input_number.number);
        break;
    case BTC_BLE_MESH_ACT_INPUT_STRING:
        act = ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT;
        param.node_prov_input_str_comp.err_code = bt_mesh_input_string(arg->input_string.string);
        break;
    case BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_NET_KEY:
        act = ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT;
        param.node_add_net_key_comp.net_idx = arg->node_add_local_net_key.net_idx;
        param.node_add_net_key_comp.err_code =
            bt_mesh_node_local_net_key_add(arg->node_add_local_net_key.net_idx,
                                           arg->node_add_local_net_key.net_key);
        break;
    case BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_APP_KEY:
        act = ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT;
        param.node_add_app_key_comp.net_idx = arg->node_add_local_app_key.net_idx;
        param.node_add_app_key_comp.app_idx = arg->node_add_local_app_key.app_idx;
        param.node_add_app_key_comp.err_code =
            bt_mesh_node_local_app_key_add(arg->node_add_local_app_key.net_idx,
                                           arg->node_add_local_app_key.app_idx,
                                           arg->node_add_local_app_key.app_key);
        break;
    case BTC_BLE_MESH_ACT_NODE_BIND_APP_KEY_TO_MODEL:
        act = ESP_BLE_MESH_NODE_BIND_APP_KEY_TO_MODEL_COMP_EVT;
        param.node_bind_app_key_to_model_comp.element_addr = arg->node_local_mod_app_bind.element_addr;
        param.node_bind_app_key_to_model_comp.model_id = arg->node_local_mod_app_bind.model_id;
        param.node_bind_app_key_to_model_comp.company_id = arg->node_local_mod_app_bind.company_id;
        param.node_bind_app_key_to_model_comp.app_idx = arg->node_local_mod_app_bind.app_idx;
        param.node_bind_app_key_to_model_comp.err_code =
            bt_mesh_node_bind_app_key_to_model(arg->node_local_mod_app_bind.element_addr,
                                               arg->node_local_mod_app_bind.model_id,
                                               arg->node_local_mod_app_bind.company_id,
                                               arg->node_local_mod_app_bind.app_idx);
        break;
#endif /* CONFIG_BLE_MESH_NODE */
#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \
     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 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();
        break;
    case BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE:
        act = ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT;
        param.node_proxy_gatt_enable_comp.err_code = bt_mesh_proxy_server_gatt_enable();
        break;
    case BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE:
        act = ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT;
        param.node_proxy_gatt_disable_comp.err_code = bt_mesh_proxy_server_gatt_disable();
        break;
#if CONFIG_BLE_MESH_PRB_SRV
    case BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_ENABLE:
        act = ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_ENABLE_COMP_EVT;
        param.node_private_proxy_identity_enable_comp.err_code = bt_mesh_proxy_private_identity_enable();
        break;
    case BTC_BLE_MESH_ACT_PRIVATE_PROXY_IDENTITY_DISABLE:
        act = ESP_BLE_MESH_NODE_PRIVATE_PROXY_IDENTITY_DISABLE_COMP_EVT;
        param.node_private_proxy_identity_disable_comp.err_code = bt_mesh_proxy_private_identity_disable();
        break;
#endif /* CONFIG_BLE_MESH_PRB_SRV */
#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */
#endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */
#if CONFIG_BLE_MESH_PROVISIONER
    case BTC_BLE_MESH_ACT_PROVISIONER_READ_OOB_PUB_KEY:
        act = ESP_BLE_MESH_PROVISIONER_PROV_READ_OOB_PUB_KEY_COMP_EVT;
        param.provisioner_prov_read_oob_pub_key_comp.err_code =
            bt_mesh_provisioner_read_oob_pub_key(arg->provisioner_read_oob_pub_key.link_idx,
                                                 arg->provisioner_read_oob_pub_key.pub_key_x,
                                                 arg->provisioner_read_oob_pub_key.pub_key_y);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_INPUT_STR:
        act = ESP_BLE_MESH_PROVISIONER_PROV_INPUT_STRING_COMP_EVT;
        param.provisioner_prov_input_str_comp.err_code =
            bt_mesh_provisioner_set_oob_input_data(arg->provisioner_input_str.link_idx,
                                                   (const uint8_t *)&arg->provisioner_input_str.string,
                                                   false);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_INPUT_NUM:
        act = ESP_BLE_MESH_PROVISIONER_PROV_INPUT_NUMBER_COMP_EVT;
        param.provisioner_prov_input_num_comp.err_code =
            bt_mesh_provisioner_set_oob_input_data(arg->provisioner_input_num.link_idx,
                                                   (const uint8_t *)&arg->provisioner_input_num.number,
                                                   true);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_ENABLE:
        act = ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT;
        param.provisioner_prov_enable_comp.err_code =
            bt_mesh_provisioner_enable(arg->provisioner_enable.bearers);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DISABLE:
        act = ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT;
        param.provisioner_prov_disable_comp.err_code =
            bt_mesh_provisioner_disable(arg->provisioner_disable.bearers);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DEV_ADD: {
        struct bt_mesh_unprov_dev_add add_dev = {0};
        add_dev.addr_type = arg->provisioner_dev_add.add_dev.addr_type;
        add_dev.oob_info = arg->provisioner_dev_add.add_dev.oob_info;
        add_dev.bearer = arg->provisioner_dev_add.add_dev.bearer;
        memcpy(add_dev.addr, arg->provisioner_dev_add.add_dev.addr, 6);
        memcpy(add_dev.uuid, arg->provisioner_dev_add.add_dev.uuid, 16);
        act = ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT;
        param.provisioner_add_unprov_dev_comp.err_code =
            bt_mesh_provisioner_add_unprov_dev(&add_dev, arg->provisioner_dev_add.flags);
        break;
    }
    case BTC_BLE_MESH_ACT_PROVISIONER_PROV_DEV_WITH_ADDR:
        act = ESP_BLE_MESH_PROVISIONER_PROV_DEV_WITH_ADDR_COMP_EVT;
        param.provisioner_prov_dev_with_addr_comp.err_code =
            bt_mesh_provisioner_prov_device_with_addr(arg->provisioner_prov_dev_with_addr.uuid,
                arg->provisioner_prov_dev_with_addr.addr, arg->provisioner_prov_dev_with_addr.addr_type,
                arg->provisioner_prov_dev_with_addr.bearer, arg->provisioner_prov_dev_with_addr.oob_info,
                arg->provisioner_prov_dev_with_addr.unicast_addr);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DEV_DEL: {
        struct bt_mesh_device_delete del_dev = {0};
        if (arg->provisioner_dev_del.del_dev.flag & DEL_DEV_ADDR_FLAG) {
            del_dev.addr_type = arg->provisioner_dev_del.del_dev.addr_type;
            memcpy(del_dev.addr, arg->provisioner_dev_del.del_dev.addr, 6);
        } else if (arg->provisioner_dev_del.del_dev.flag & DEL_DEV_UUID_FLAG) {
            memcpy(del_dev.uuid, arg->provisioner_dev_del.del_dev.uuid, 16);
        }
        act = ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT;
        param.provisioner_delete_dev_comp.err_code = bt_mesh_provisioner_delete_device(&del_dev);
        break;
    }
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_DEV_UUID_MATCH:
        act = ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT;
        param.provisioner_set_dev_uuid_match_comp.err_code =
            bt_mesh_provisioner_set_dev_uuid_match(arg->set_dev_uuid_match.offset,
                    arg->set_dev_uuid_match.match_len,
                    arg->set_dev_uuid_match.match_val,
                    arg->set_dev_uuid_match.prov_after_match);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_PROV_DATA_INFO: {
        struct bt_mesh_prov_data_info info = {0};
        info.flag = arg->set_prov_data_info.prov_data.flag;
        if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_NET_IDX_FLAG) {
            info.net_idx = arg->set_prov_data_info.prov_data.net_idx;
        } else if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_FLAGS_FLAG) {
            info.flags = arg->set_prov_data_info.prov_data.flags;
        } else if (arg->set_prov_data_info.prov_data.flag & PROV_DATA_IV_INDEX_FLAG) {
            info.iv_index = arg->set_prov_data_info.prov_data.iv_index;
        }
        act = ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT;
        param.provisioner_set_prov_data_info_comp.err_code =
            bt_mesh_provisioner_set_prov_data_info(&info);
        break;
    }
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_STATIC_OOB_VAL:
        act = ESP_BLE_MESH_PROVISIONER_SET_STATIC_OOB_VALUE_COMP_EVT;
        param.provisioner_set_static_oob_val_comp.err_code =
            bt_mesh_provisioner_set_static_oob_value(
                arg->set_static_oob_val.value, arg->set_static_oob_val.length);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_PRIMARY_ELEM_ADDR:
        act = ESP_BLE_MESH_PROVISIONER_SET_PRIMARY_ELEM_ADDR_COMP_EVT;
        param.provisioner_set_primary_elem_addr_comp.err_code =
            bt_mesh_provisioner_set_primary_elem_addr(arg->set_primary_elem_addr.addr);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_NODE_NAME:
        act = ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT;
        param.provisioner_set_node_name_comp.node_index = arg->set_node_name.index;
        param.provisioner_set_node_name_comp.err_code =
            bt_mesh_provisioner_set_node_name(arg->set_node_name.index, arg->set_node_name.name);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_APP_KEY: {
        const uint8_t *app_key = NULL;
        const uint8_t zero[16] = {0};
        if (memcmp(arg->add_local_app_key.app_key, zero, 16)) {
            app_key = arg->add_local_app_key.app_key;
        }
        act = ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT;
        param.provisioner_add_app_key_comp.err_code =
            bt_mesh_provisioner_local_app_key_add(app_key, arg->add_local_app_key.net_idx,
                    &arg->add_local_app_key.app_idx);
        param.provisioner_add_app_key_comp.net_idx = arg->add_local_app_key.net_idx;
        param.provisioner_add_app_key_comp.app_idx = arg->add_local_app_key.app_idx;
        break;
    }
    case BTC_BLE_MESH_ACT_PROVISIONER_UPDATE_LOCAL_APP_KEY:
        act = ESP_BLE_MESH_PROVISIONER_UPDATE_LOCAL_APP_KEY_COMP_EVT;
        param.provisioner_update_app_key_comp.net_idx = arg->update_local_app_key.net_idx;
        param.provisioner_update_app_key_comp.app_idx = arg->update_local_app_key.app_idx;
        param.provisioner_update_app_key_comp.err_code =
            bt_mesh_provisioner_local_app_key_update(arg->update_local_app_key.app_key,
                    arg->update_local_app_key.net_idx, arg->update_local_app_key.app_idx);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_BIND_LOCAL_MOD_APP:
        act = ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT;
        param.provisioner_bind_app_key_to_model_comp.element_addr = arg->local_mod_app_bind.elem_addr;
        param.provisioner_bind_app_key_to_model_comp.app_idx = arg->local_mod_app_bind.app_idx;
        param.provisioner_bind_app_key_to_model_comp.company_id = arg->local_mod_app_bind.cid;
        param.provisioner_bind_app_key_to_model_comp.model_id = arg->local_mod_app_bind.model_id;
        param.provisioner_bind_app_key_to_model_comp.err_code =
            bt_mesh_provisioner_bind_local_model_app_idx(arg->local_mod_app_bind.elem_addr,
                    arg->local_mod_app_bind.model_id,
                    arg->local_mod_app_bind.cid,
                    arg->local_mod_app_bind.app_idx);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_NET_KEY: {
        const uint8_t *net_key = NULL;
        const uint8_t zero[16] = {0};
        if (memcmp(arg->add_local_net_key.net_key, zero, 16)) {
            net_key = arg->add_local_net_key.net_key;
        }
        act = ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT;
        param.provisioner_add_net_key_comp.err_code =
            bt_mesh_provisioner_local_net_key_add(net_key, &arg->add_local_net_key.net_idx);
        param.provisioner_add_net_key_comp.net_idx = arg->add_local_net_key.net_idx;
        break;
    }
    case BTC_BLE_MESH_ACT_PROVISIONER_UPDATE_LOCAL_NET_KEY:
        act = ESP_BLE_MESH_PROVISIONER_UPDATE_LOCAL_NET_KEY_COMP_EVT;
        param.provisioner_update_net_key_comp.net_idx = arg->update_local_net_key.net_idx;
        param.provisioner_update_net_key_comp.err_code =
            bt_mesh_provisioner_local_net_key_update(arg->update_local_net_key.net_key,
                arg->update_local_net_key.net_idx);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_STORE_NODE_COMP_DATA:
        act = ESP_BLE_MESH_PROVISIONER_STORE_NODE_COMP_DATA_COMP_EVT;
        param.provisioner_store_node_comp_data_comp.addr = arg->store_node_comp_data.unicast_addr;
        param.provisioner_store_node_comp_data_comp.err_code =
            bt_mesh_provisioner_store_node_comp_data(arg->store_node_comp_data.unicast_addr,
                arg->store_node_comp_data.data, arg->store_node_comp_data.length);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DELETE_NODE_WITH_UUID:
        act = ESP_BLE_MESH_PROVISIONER_DELETE_NODE_WITH_UUID_COMP_EVT;
        memcpy(param.provisioner_delete_node_with_uuid_comp.uuid, arg->delete_node_with_uuid.uuid, 16);
        param.provisioner_delete_node_with_uuid_comp.err_code =
            bt_mesh_provisioner_delete_node_with_uuid(arg->delete_node_with_uuid.uuid);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DELETE_NODE_WITH_ADDR:
        act = ESP_BLE_MESH_PROVISIONER_DELETE_NODE_WITH_ADDR_COMP_EVT;
        param.provisioner_delete_node_with_addr_comp.unicast_addr = arg->delete_node_with_addr.unicast_addr;
        param.provisioner_delete_node_with_addr_comp.err_code =
            bt_mesh_provisioner_delete_node_with_node_addr(arg->delete_node_with_addr.unicast_addr);
        break;
#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB
    case BTC_BLE_MESH_ACT_PROVISIONER_ENABLE_HEARTBEAT_RECV:
        act = ESP_BLE_MESH_PROVISIONER_ENABLE_HEARTBEAT_RECV_COMP_EVT;
        param.provisioner_enable_heartbeat_recv_comp.enable = arg->enable_heartbeat_recv.enable;
        param.provisioner_enable_heartbeat_recv_comp.err_code =
            bt_mesh_pvnr_register_hb_recv_cb(arg->enable_heartbeat_recv.enable ?
                                             btc_ble_mesh_provisioner_recv_heartbeat_cb : NULL);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE:
        act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT;
        param.provisioner_set_heartbeat_filter_type_comp.type = arg->set_heartbeat_filter_type.type;
        param.provisioner_set_heartbeat_filter_type_comp.err_code =
            bt_mesh_pvnr_set_hb_recv_filter_type(arg->set_heartbeat_filter_type.type);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO:
        act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT;
        param.provisioner_set_heartbeat_filter_info_comp.op = arg->set_heartbeat_filter_info.op;
        param.provisioner_set_heartbeat_filter_info_comp.hb_src = arg->set_heartbeat_filter_info.hb_src;
        param.provisioner_set_heartbeat_filter_info_comp.hb_dst = arg->set_heartbeat_filter_info.hb_dst;
        param.provisioner_set_heartbeat_filter_info_comp.err_code =
            bt_mesh_pvnr_set_hb_recv_filter_info(arg->set_heartbeat_filter_info.op,
                                                 arg->set_heartbeat_filter_info.hb_src,
                                                 arg->set_heartbeat_filter_info.hb_dst);
        break;
#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */
#if CONFIG_BLE_MESH_SETTINGS
    case BTC_BLE_MESH_ACT_PROVISIONER_DIRECT_ERASE_SETTINGS:
        act = ESP_BLE_MESH_PROVISIONER_DIRECT_ERASE_SETTINGS_COMP_EVT;
        param.provisioner_direct_erase_settings_comp.err_code = bt_mesh_provisioner_direct_erase_settings();
        break;
#endif /* CONFIG_BLE_MESH_SETTINGS */
#if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
    case BTC_BLE_MESH_ACT_PROVISIONER_OPEN_SETTINGS_WITH_INDEX:
        act = ESP_BLE_MESH_PROVISIONER_OPEN_SETTINGS_WITH_INDEX_COMP_EVT;
        param.provisioner_open_settings_with_index_comp.index = arg->open_settings_with_index.index;
        param.provisioner_open_settings_with_index_comp.err_code =
            bt_mesh_provisioner_open_settings_with_index(arg->open_settings_with_index.index);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_OPEN_SETTINGS_WITH_UID:
        act = ESP_BLE_MESH_PROVISIONER_OPEN_SETTINGS_WITH_UID_COMP_EVT;
        strncpy(param.provisioner_open_settings_with_uid_comp.uid,
                arg->open_settings_with_uid.uid, ESP_BLE_MESH_SETTINGS_UID_SIZE + 1);
        param.provisioner_open_settings_with_uid_comp.err_code =
            bt_mesh_provisioner_open_settings_with_uid(arg->open_settings_with_uid.uid,
                                                       &param.provisioner_open_settings_with_uid_comp.index);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_CLOSE_SETTINGS_WITH_INDEX:
        act = ESP_BLE_MESH_PROVISIONER_CLOSE_SETTINGS_WITH_INDEX_COMP_EVT;
        param.provisioner_close_settings_with_index_comp.index = arg->close_settings_with_index.index;
        param.provisioner_close_settings_with_index_comp.err_code =
            bt_mesh_provisioner_close_settings_with_index(arg->close_settings_with_index.index,
                                                          arg->close_settings_with_index.erase);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_CLOSE_SETTINGS_WITH_UID:
        act = ESP_BLE_MESH_PROVISIONER_CLOSE_SETTINGS_WITH_UID_COMP_EVT;
        strncpy(param.provisioner_close_settings_with_uid_comp.uid,
                arg->close_settings_with_uid.uid, ESP_BLE_MESH_SETTINGS_UID_SIZE + 1);
        param.provisioner_close_settings_with_uid_comp.err_code =
            bt_mesh_provisioner_close_settings_with_uid(arg->close_settings_with_uid.uid,
                                                        arg->close_settings_with_uid.erase,
                                                        &param.provisioner_close_settings_with_uid_comp.index);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_INDEX:
        act = ESP_BLE_MESH_PROVISIONER_DELETE_SETTINGS_WITH_INDEX_COMP_EVT;
        param.provisioner_delete_settings_with_index_comp.index = arg->delete_settings_with_index.index;
        param.provisioner_delete_settings_with_index_comp.err_code =
            bt_mesh_provisioner_delete_settings_with_index(arg->delete_settings_with_index.index);
        break;
    case BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_UID:
        act = ESP_BLE_MESH_PROVISIONER_DELETE_SETTINGS_WITH_UID_COMP_EVT;
        strncpy(param.provisioner_delete_settings_with_uid_comp.uid,
                arg->delete_settings_with_uid.uid, ESP_BLE_MESH_SETTINGS_UID_SIZE + 1);
        param.provisioner_delete_settings_with_uid_comp.err_code =
            bt_mesh_provisioner_delete_settings_with_uid(arg->delete_settings_with_uid.uid,
                                                         &param.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:
        act = ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT;
        param.set_fast_prov_info_comp.status_unicast =
            bt_mesh_set_fast_prov_unicast_addr_range(arg->set_fast_prov_info.unicast_min,
                    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);
        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,
                    arg->set_fast_prov_info.match_val, false);
        break;
    case BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION:
        act = ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT;
        param.set_fast_prov_action_comp.status_action =
            bt_mesh_set_fast_prov_action(arg->set_fast_prov_action.action);
        break;
#endif /* CONFIG_BLE_MESH_FAST_PROV */
#if CONFIG_BLE_MESH_LOW_POWER
    case BTC_BLE_MESH_ACT_LPN_ENABLE:
        act = ESP_BLE_MESH_LPN_ENABLE_COMP_EVT;
        param.lpn_enable_comp.err_code = bt_mesh_lpn_set(true, false);
        break;
    case BTC_BLE_MESH_ACT_LPN_DISABLE:
        act = ESP_BLE_MESH_LPN_DISABLE_COMP_EVT;
        param.lpn_disable_comp.err_code = bt_mesh_lpn_set(false, arg->lpn_disable.force);
        break;
    case BTC_BLE_MESH_ACT_LPN_POLL:
        act = ESP_BLE_MESH_LPN_POLL_COMP_EVT;
        param.lpn_poll_comp.err_code = bt_mesh_lpn_poll();
        break;
#endif /* CONFIG_BLE_MESH_LOW_POWER */
#if CONFIG_BLE_MESH_GATT_PROXY_CLIENT
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_CONNECT:
        act = ESP_BLE_MESH_PROXY_CLIENT_CONNECT_COMP_EVT;
        memcpy(param.proxy_client_connect_comp.addr, arg->proxy_client_connect.addr, BD_ADDR_LEN);
        param.proxy_client_connect_comp.addr_type = arg->proxy_client_connect.addr_type;
        param.proxy_client_connect_comp.net_idx = arg->proxy_client_connect.net_idx;
        param.proxy_client_connect_comp.err_code =
            bt_mesh_proxy_client_connect(arg->proxy_client_connect.addr,
                                         arg->proxy_client_connect.addr_type,
                                         arg->proxy_client_connect.net_idx);
        break;
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_DISCONNECT:
        act = ESP_BLE_MESH_PROXY_CLIENT_DISCONNECT_COMP_EVT;
        param.proxy_client_disconnect_comp.conn_handle = arg->proxy_client_disconnect.conn_handle;
        param.proxy_client_disconnect_comp.err_code =
            bt_mesh_proxy_client_disconnect(arg->proxy_client_disconnect.conn_handle);
        break;
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_SET_FILTER_TYPE: {
        struct bt_mesh_proxy_cfg_pdu pdu = {
            .opcode = BLE_MESH_PROXY_CFG_FILTER_SET,
            .set.filter_type = arg->proxy_client_set_filter_type.filter_type,
        };
        act = ESP_BLE_MESH_PROXY_CLIENT_SET_FILTER_TYPE_COMP_EVT;
        param.proxy_client_set_filter_type_comp.conn_handle = arg->proxy_client_set_filter_type.conn_handle;
        param.proxy_client_set_filter_type_comp.net_idx = arg->proxy_client_set_filter_type.net_idx;
        param.proxy_client_set_filter_type_comp.err_code =
            bt_mesh_proxy_client_cfg_send(arg->proxy_client_set_filter_type.conn_handle,
                                          arg->proxy_client_set_filter_type.net_idx, &pdu);
        break;
    }
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_ADD_FILTER_ADDR: {
        struct bt_mesh_proxy_cfg_pdu pdu = {
            .opcode = BLE_MESH_PROXY_CFG_FILTER_ADD,
            .add.addr = arg->proxy_client_add_filter_addr.addr,
            .add.addr_num = arg->proxy_client_add_filter_addr.addr_num,
        };
        act = ESP_BLE_MESH_PROXY_CLIENT_ADD_FILTER_ADDR_COMP_EVT;
        param.proxy_client_add_filter_addr_comp.conn_handle = arg->proxy_client_add_filter_addr.conn_handle;
        param.proxy_client_add_filter_addr_comp.net_idx = arg->proxy_client_add_filter_addr.net_idx;
        param.proxy_client_add_filter_addr_comp.err_code =
            bt_mesh_proxy_client_cfg_send(arg->proxy_client_add_filter_addr.conn_handle,
                                          arg->proxy_client_add_filter_addr.net_idx, &pdu);
        break;
    }
    case BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR: {
        struct bt_mesh_proxy_cfg_pdu pdu = {
            .opcode = BLE_MESH_PROXY_CFG_FILTER_REMOVE,
            .remove.addr = arg->proxy_client_remove_filter_addr.addr,
            .remove.addr_num = arg->proxy_client_remove_filter_addr.addr_num,
        };
        act = ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT;
        param.proxy_client_remove_filter_addr_comp.conn_handle = arg->proxy_client_remove_filter_addr.conn_handle;
        param.proxy_client_remove_filter_addr_comp.net_idx = arg->proxy_client_remove_filter_addr.net_idx;
        param.proxy_client_remove_filter_addr_comp.err_code =
            bt_mesh_proxy_client_cfg_send(arg->proxy_client_remove_filter_addr.conn_handle,
                                          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;
        param.model_sub_group_addr_comp.element_addr = arg->model_sub_group_addr.element_addr;
        param.model_sub_group_addr_comp.company_id = arg->model_sub_group_addr.company_id;
        param.model_sub_group_addr_comp.model_id = arg->model_sub_group_addr.model_id;
        param.model_sub_group_addr_comp.group_addr = arg->model_sub_group_addr.group_addr;
        param.model_sub_group_addr_comp.err_code =
            bt_mesh_model_subscribe_group_addr(arg->model_sub_group_addr.element_addr,
                                               arg->model_sub_group_addr.company_id,
                                               arg->model_sub_group_addr.model_id,
                                               arg->model_sub_group_addr.group_addr);
        break;
    case BTC_BLE_MESH_ACT_MODEL_UNSUBSCRIBE_GROUP_ADDR:
        act = ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT;
        param.model_unsub_group_addr_comp.element_addr = arg->model_unsub_group_addr.element_addr;
        param.model_unsub_group_addr_comp.company_id = arg->model_unsub_group_addr.company_id;
        param.model_unsub_group_addr_comp.model_id = arg->model_unsub_group_addr.model_id;
        param.model_unsub_group_addr_comp.group_addr = arg->model_unsub_group_addr.group_addr;
        param.model_unsub_group_addr_comp.err_code =
            bt_mesh_model_unsubscribe_group_addr(arg->model_unsub_group_addr.element_addr,
                                                 arg->model_unsub_group_addr.company_id,
                                                 arg->model_unsub_group_addr.model_id,
                                                 arg->model_unsub_group_addr.group_addr);
        break;
#if CONFIG_BLE_MESH_DEINIT
    case BTC_BLE_MESH_ACT_DEINIT_MESH:
        act = ESP_BLE_MESH_DEINIT_MESH_COMP_EVT;
        param.deinit_mesh_comp.err_code = bt_mesh_deinit((struct bt_mesh_deinit_param *)&arg->mesh_deinit.param);
        /* Temporarily save the deinit semaphore and release it after the mesh deinit complete event is handled in the app layer */
        deinit_comp_semaphore = arg->mesh_deinit.semaphore;
        break;
#endif /* CONFIG_BLE_MESH_DEINIT */
    default:
        BT_WARN("%s, Unknown act %d", __func__, msg->act);
        return;
    }

    /* Callback operation completion events */
    btc_ble_mesh_prov_set_complete_cb(&param, act);

    btc_ble_mesh_prov_arg_deep_free(msg);
}

void btc_ble_mesh_prov_cb_handler(btc_msg_t *msg)
{
    esp_ble_mesh_prov_cb_param_t *param = NULL;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    param = (esp_ble_mesh_prov_cb_param_t *)(msg->arg);

    if (msg->act < ESP_BLE_MESH_PROV_EVT_MAX) {
        btc_ble_mesh_prov_cb_to_app(msg->act, param);
    } 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)
{
    btc_ble_mesh_model_args_t *arg = NULL;
    int err = 0;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    arg = (btc_ble_mesh_model_args_t *)(msg->arg);

    switch (msg->act) {
    case BTC_BLE_MESH_ACT_MODEL_PUBLISH: {
        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;
    }
    case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND: {
        /* arg->model_send.length contains opcode & payload, plus extra 4-bytes TransMIC */
        struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + BLE_MESH_MIC_SHORT);
        if (!buf) {
            BT_ERR("%s, Out of memory", __func__);
            btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx,
                                            arg->model_send.opcode, -ENOMEM);
            break;
        }

        net_buf_simple_add_mem(buf, arg->model_send.data, arg->model_send.length);

        err = bt_mesh_model_send((struct bt_mesh_model *)arg->model_send.model,
                                 (struct bt_mesh_msg_ctx *)arg->model_send.ctx,
                                 buf, NULL, NULL);
        bt_mesh_free_buf(buf);
        btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx,
                                        arg->model_send.opcode, err);
        break;
    }
    case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: {
        /* arg->model_send.length contains opcode & message, plus extra 4-bytes TransMIC */
        struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + BLE_MESH_MIC_SHORT);
        if (!buf) {
            BT_ERR("%s, Out of memory", __func__);
            btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx,
                                            arg->model_send.opcode, -ENOMEM);
            break;
        }

        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_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,
        };

        memcpy(&param.ctx.enh, &arg->model_send.ctx->enh, sizeof(bt_mesh_msg_enh_params_t));

        err = bt_mesh_client_send_msg(&param, buf, arg->model_send.need_rsp,
                                      btc_ble_mesh_client_model_timeout_cb);
        bt_mesh_free_buf(buf);
        btc_ble_mesh_model_send_comp_cb(arg->model_send.model, arg->model_send.ctx,
                                        arg->model_send.opcode, err);
        break;
    }
#if CONFIG_BLE_MESH_SERVER_MODEL
    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
        err = bt_mesh_update_binding_state(
                  (struct bt_mesh_model *)arg->model_update_state.model, arg->model_update_state.type,
                  (bt_mesh_server_state_value_t *)arg->model_update_state.value);
        btc_ble_mesh_server_model_update_state_comp_cb(arg->model_update_state.model,
                arg->model_update_state.type, err);
        break;
#endif /* CONFIG_BLE_MESH_SERVER_MODEL */
    default:
        BT_WARN("%s, Unknown act %d", __func__, msg->act);
        break;
    }

    btc_ble_mesh_model_arg_deep_free(msg);
}

void btc_ble_mesh_model_cb_handler(btc_msg_t *msg)
{
    esp_ble_mesh_model_cb_param_t *param = NULL;

    if (!msg) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    param = (esp_ble_mesh_model_cb_param_t *)(msg->arg);

    if (msg->act < ESP_BLE_MESH_MODEL_EVT_MAX) {
        btc_ble_mesh_model_cb_to_app(msg->act, param);
    } else {
        BT_ERR("%s, Unknown act %d", __func__, msg->act);
    }

    btc_ble_mesh_model_free_req_data(msg);
}
