/* Bluetooth: Mesh Generic Server Models
 *
 * SPDX-FileCopyrightText: 2018 Vikrant More
 * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <errno.h>

#include "btc_ble_mesh_generic_model.h"

#include "mesh/config.h"
#include "access.h"
#include "transport.h"
#include "mesh/model_opcode.h"
#include "mesh/state_transition.h"
#include "mesh/device_property.h"

#if CONFIG_BLE_MESH_GENERIC_SERVER

static bt_mesh_mutex_t generic_server_lock;

void bt_mesh_generic_server_lock(void)
{
    bt_mesh_mutex_lock(&generic_server_lock);
}

void bt_mesh_generic_server_unlock(void)
{
    bt_mesh_mutex_unlock(&generic_server_lock);
}

/* message handlers (Start) */

/* Generic OnOff Server message handlers */
static void send_gen_onoff_status(struct bt_mesh_model *model,
                                  struct bt_mesh_msg_ctx *ctx,
                                  bool publish)
{
    struct bt_mesh_gen_onoff_srv *srv = model->user_data;
    struct net_buf_simple *msg = NULL;
    uint8_t length = 2 + 3;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS);
    net_buf_simple_add_u8(msg, srv->state.onoff);
    if (srv->transition.counter) {
        bt_mesh_server_calc_remain_time(&srv->transition);
        net_buf_simple_add_u8(msg, srv->state.target_onoff);
        net_buf_simple_add_u8(msg, srv->transition.remain_time);
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_onoff_get(struct bt_mesh_model *model,
                          struct bt_mesh_msg_ctx *ctx,
                          struct net_buf_simple *buf)
{
    struct bt_mesh_gen_onoff_srv *srv = model->user_data;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    send_gen_onoff_status(model, ctx, false);
}

void gen_onoff_publish(struct bt_mesh_model *model)
{
    if (model->user_data == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    send_gen_onoff_status(model, NULL, true);
}

static void gen_onoff_set(struct bt_mesh_model *model,
                          struct bt_mesh_msg_ctx *ctx,
                          struct net_buf_simple *buf)
{
    struct bt_mesh_gen_onoff_srv *srv = model->user_data;
    uint8_t tid = 0U, onoff = 0U, trans_time = 0U, delay = 0U;
    bool optional = false;
    int64_t now = 0;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    onoff = net_buf_simple_pull_u8(buf);
    if (onoff > BLE_MESH_STATE_ON) {
        BT_ERR("Invalid OnOff value 0x%02x", onoff);
        return;
    }
    tid = net_buf_simple_pull_u8(buf);

    if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) {
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .onoff_set.op_en = optional,
            .onoff_set.onoff = onoff,
            .onoff_set.tid = tid,
            .onoff_set.trans_time = trans_time,
            .onoff_set.delay = delay,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
            send_gen_onoff_status(model, ctx, false);
        }
        send_gen_onoff_status(model, NULL, true);
        /* In this condition, no event will be callback to application layer */
        return;
    }

    bt_mesh_generic_server_lock();

    bt_mesh_server_stop_transition(&srv->transition);
    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);

    srv->state.target_onoff = onoff;

    if (srv->state.target_onoff != srv->state.onoff) {
        generic_onoff_tt_values(srv, trans_time, delay);
    } else {
        bt_mesh_gen_server_state_change_t change = {
            .gen_onoff_set.onoff = srv->state.onoff,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));

        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
            send_gen_onoff_status(model, ctx, false);
        }
        send_gen_onoff_status(model, NULL, true);

        bt_mesh_generic_server_unlock();
        return;
    }

    /* Copy the ctx of the received message */
    if (srv->transition.timer.work.user_data) {
        memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx));
    }

    /* For Instantaneous Transition */
    if (srv->transition.counter == 0U) {
        srv->state.onoff = srv->state.target_onoff;
    }

    srv->transition.just_started = true;
    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
        send_gen_onoff_status(model, ctx, false);
    }
    send_gen_onoff_status(model, NULL, true);

    bt_mesh_generic_server_unlock();

    bt_mesh_server_start_transition(&srv->transition);
}

/* Generic Level Server message handlers */
static void send_gen_level_status(struct bt_mesh_model *model,
                                  struct bt_mesh_msg_ctx *ctx,
                                  bool publish)
{
    struct bt_mesh_gen_level_srv *srv = model->user_data;
    struct net_buf_simple *msg = NULL;
    uint8_t length = 2 + 5;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS);
    net_buf_simple_add_le16(msg, srv->state.level);
    if (srv->transition.counter) {
        if (srv->state.move_start) {
            if (srv->state.positive) {
                net_buf_simple_add_le16(msg, INT16_MAX);
            } else { /* 0 should not be possible */
                net_buf_simple_add_le16(msg, INT16_MIN);
            }
            net_buf_simple_add_u8(msg, BLE_MESH_UNKNOWN_REMAIN_TIME);
        } else {
            bt_mesh_server_calc_remain_time(&srv->transition);
            net_buf_simple_add_le16(msg, srv->state.target_level);
            net_buf_simple_add_u8(msg, srv->transition.remain_time);
        }
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_level_get(struct bt_mesh_model *model,
                          struct bt_mesh_msg_ctx *ctx,
                          struct net_buf_simple *buf)
{
    struct bt_mesh_gen_level_srv *srv = model->user_data;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    send_gen_level_status(model, ctx, false);
}

void gen_level_publish(struct bt_mesh_model *model)
{
    if (model->user_data == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    send_gen_level_status(model, NULL, true);
}

static void gen_level_set(struct bt_mesh_model *model,
                          struct bt_mesh_msg_ctx *ctx,
                          struct net_buf_simple *buf)
{
    struct bt_mesh_gen_level_srv *srv = model->user_data;
    uint8_t tid = 0U, trans_time = 0U, delay = 0U;
    bool optional = false;
    int16_t level = 0;
    int64_t now = 0;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    level = (int16_t) net_buf_simple_pull_le16(buf);
    tid = net_buf_simple_pull_u8(buf);

    if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) {
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .level_set.op_en = optional,
            .level_set.level = level,
            .level_set.tid = tid,
            .level_set.trans_time = trans_time,
            .level_set.delay = delay,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
            send_gen_level_status(model, ctx, false);
        }
        send_gen_level_status(model, NULL, true);
        /* In this condition, no event will be callback to application layer */
        return;
    }

    bt_mesh_generic_server_lock();

    bt_mesh_server_stop_transition(&srv->transition);
    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);

    srv->state.target_level = level;

    /**
     * If the target state is equal to the current state, the transition
     * shall not be started and is considered complete.
     */
    if (srv->state.target_level != srv->state.level) {
        generic_level_tt_values(srv, trans_time, delay);
    } else {
        bt_mesh_gen_server_state_change_t change = {
            .gen_level_set.level = srv->state.level,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));

        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
            send_gen_level_status(model, ctx, false);
        }
        send_gen_level_status(model, NULL, true);

        bt_mesh_generic_server_unlock();
        return;
    }

    /* Copy the ctx of the received message */
    if (srv->transition.timer.work.user_data) {
        memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx));
    }

    /* For Instantaneous Transition */
    if (srv->transition.counter == 0U) {
        srv->state.level = srv->state.target_level;
    }

    srv->transition.just_started = true;
    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
        send_gen_level_status(model, ctx, false);
    }
    send_gen_level_status(model, NULL, true);

    bt_mesh_generic_server_unlock();

    bt_mesh_server_start_transition(&srv->transition);
}

static void gen_delta_set(struct bt_mesh_model *model,
                          struct bt_mesh_msg_ctx *ctx,
                          struct net_buf_simple *buf)
{
    struct bt_mesh_gen_level_srv *srv = model->user_data;
    uint8_t tid = 0U, trans_time = 0U, delay = 0U;
    int32_t tmp32 = 0, delta = 0;
    bool optional = false;
    int64_t now = 0;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    delta = (int32_t)net_buf_simple_pull_le32(buf);
    tid = net_buf_simple_pull_u8(buf);

    if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) {
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .delta_set.op_en = optional,
            .delta_set.delta_level = delta,
            .delta_set.tid = tid,
            .delta_set.trans_time = trans_time,
            .delta_set.delay = delay,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    /**
     * A number of Generic Delta Set and Generic Delta Set Unacknowledged
     * messages with the same transaction identifier set in the TID field
     * may be sent.
     *
     * A new transaction starts when the TID field value in the received
     * message is different from the TID field value in the previously
     * received message that was using the same source and destination
     * addresses or from the most recently received message with the same
     * TID field value that was received 6 or more seconds earlier.
     */
    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
        if (srv->state.last_delta == delta) {
            if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
                send_gen_level_status(model, ctx, false);
            }
            send_gen_level_status(model, NULL, true);
            /* In this condition, no event will be callback to application layer */
            return;
        }

        tmp32 = srv->state.last_level + delta;
    } else {
        /* Starts a new transaction */
        srv->state.last_level = srv->state.level;
        tmp32 = srv->state.level + delta;
    }

    bt_mesh_generic_server_lock();

    bt_mesh_server_stop_transition(&srv->transition);
    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);

    srv->state.last_delta = delta;
    if (tmp32 < INT16_MIN) {
        tmp32 = INT16_MIN;
    } else if (tmp32 > INT16_MAX) {
        tmp32 = INT16_MAX;
    }
    srv->state.target_level = tmp32;

    /**
     * If the target state is equal to the current state, the transition
     * shall not be started and is considered complete.
     */
    if (srv->state.target_level != srv->state.level) {
        generic_level_tt_values(srv, trans_time, delay);
    } else {
        bt_mesh_gen_server_state_change_t change = {
            .gen_delta_set.level = srv->state.level,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));

        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
            send_gen_level_status(model, ctx, false);
        }
        send_gen_level_status(model, NULL, true);

        bt_mesh_generic_server_unlock();
        return;
    }

    /* Copy the ctx of the received message */
    if (srv->transition.timer.work.user_data) {
        memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx));
    }

    /* For Instantaneous Transition */
    if (srv->transition.counter == 0U) {
        srv->state.level = srv->state.target_level;
    }

    srv->transition.just_started = true;
    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
        send_gen_level_status(model, ctx, false);
    }
    send_gen_level_status(model, NULL, true);

    bt_mesh_generic_server_unlock();

    bt_mesh_server_start_transition(&srv->transition);
}

static void gen_move_set(struct bt_mesh_model *model,
                         struct bt_mesh_msg_ctx *ctx,
                         struct net_buf_simple *buf)
{
    struct bt_mesh_gen_level_srv *srv = model->user_data;
    uint8_t tid = 0U, trans_time = 0U, delay = 0U;
    bool optional = false;
    int16_t delta = 0;
    int32_t tmp32 = 0;
    int64_t now = 0;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    delta = (int16_t) net_buf_simple_pull_le16(buf);
    tid = net_buf_simple_pull_u8(buf);

    if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) {
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .move_set.op_en = optional,
            .move_set.delta_level = delta,
            .move_set.tid = tid,
            .move_set.trans_time = trans_time,
            .move_set.delay = delay,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
            send_gen_level_status(model, ctx, false);
        }
        send_gen_level_status(model, NULL, true);
        /* In this condition, no event will be callback to application layer */
        return;
    }

    bt_mesh_generic_server_lock();

    bt_mesh_server_stop_transition(&srv->transition);
    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);

    srv->state.last_delta = delta;

    tmp32 = srv->state.level + delta;
    if (tmp32 < INT16_MIN) {
        tmp32 = INT16_MIN;
    } else if (tmp32 > INT16_MAX) {
        tmp32 = INT16_MAX;
    }
    srv->state.target_level = tmp32;

    /**
     * If the target state is equal to the current state, the transition
     * shall not be started and is considered complete.
     */
    if (srv->state.target_level != srv->state.level) {
        generic_level_tt_values(srv, trans_time, delay);
    } else {
        bt_mesh_gen_server_state_change_t change = {
            .gen_move_set.level = srv->state.level,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));

        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
            send_gen_level_status(model, ctx, false);
        }
        send_gen_level_status(model, NULL, true);
        srv->state.move_start = false;

        bt_mesh_generic_server_unlock();
        return;
    }

    /* Copy the ctx of the received message */
    if (srv->transition.timer.work.user_data) {
        memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx));
    }

    if (delta) {
        srv->state.move_start = true;
        srv->state.positive = (delta > 0) ? true : false;
    }

    srv->transition.just_started = true;
    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
        send_gen_level_status(model, ctx, false);
    }
    send_gen_level_status(model, NULL, true);

    bt_mesh_generic_server_unlock();

    /**
     * If (trans_time == 0) OR (delta == 0)
     * 1. If the resulting Transition Time is equal to 0 or is undefined,
     *    the Generic Move Set command will not initiate any Generic Level
     *    state change.
     * 2. When a Generic Level Server receives the message with a value of
     *    the Delta Level field equal to 0, it shall stop changing the
     *    Generic Level state. (if delta == 0, srv->state.target_level will
     *    equal to srv->state.level)
     */
    if (srv->transition.counter == 0U) {
        srv->state.move_start = false;
        bt_mesh_gen_server_state_change_t change = {
            .gen_move_set.level = srv->state.level,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));
        return;
    }

    bt_mesh_server_start_transition(&srv->transition);
}

/* Generic Default Transition Time Server message handlers */
static void send_gen_def_trans_time_status(struct bt_mesh_model *model,
        struct bt_mesh_msg_ctx *ctx,
        bool publish)
{
    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
    struct net_buf_simple *msg = NULL;
    uint8_t length = 2 + 1;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS);
    net_buf_simple_add_u8(msg, srv->state.trans_time);

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_def_trans_time_get(struct bt_mesh_model *model,
                                   struct bt_mesh_msg_ctx *ctx,
                                   struct net_buf_simple *buf)
{
    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    send_gen_def_trans_time_status(model, ctx, false);
}

static void gen_def_trans_time_set(struct bt_mesh_model *model,
                                   struct bt_mesh_msg_ctx *ctx,
                                   struct net_buf_simple *buf)
{
    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
    uint8_t trans_time = 0U;

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    trans_time = net_buf_simple_pull_u8(buf);
    if ((trans_time & 0x3F) == 0x3F) {
        BT_WARN("Invalid Transaction Number of Steps 0x3f");
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .def_trans_time_set.trans_time = trans_time,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (srv->state.trans_time != trans_time) {
        srv->state.trans_time = trans_time;
    }

    bt_mesh_gen_server_state_change_t change = {
        .gen_def_trans_time_set.trans_time = trans_time,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET) {
        send_gen_def_trans_time_status(model, ctx, false);
    }
    send_gen_def_trans_time_status(model, NULL, true);
}

/* Generic Power OnOff Server message handlers */
static void send_gen_onpowerup_status(struct bt_mesh_model *model,
                                      struct bt_mesh_msg_ctx *ctx,
                                      bool publish)
{
    struct net_buf_simple *msg = NULL;
    uint8_t length = 2 + 1;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS);
    switch (model->id) {
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
        net_buf_simple_add_u8(msg, srv->state->onpowerup);
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
        net_buf_simple_add_u8(msg, srv->state->onpowerup);
        break;
    }
    default:
        BT_ERR("Invalid Generic Power OnOff Server 0x%04x", model->id);
        if (publish == false) {
            bt_mesh_free_buf(msg);
        }
        return;
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_onpowerup_get(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    send_gen_onpowerup_status(model, ctx, false);
}

/* Generic Power OnOff Setup Server message handlers */
void gen_onpowerup_publish(struct bt_mesh_model *model)
{
    if (model->user_data == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    switch (model->id) {
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power OnOff Server state");
            return;
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power OnOff Setup Server state");
            return;
        }
        break;
    }
    default:
        BT_ERR("Invalid Generic Power OnOff Server 0x%04x", model->id);
        return;
    }

    send_gen_onpowerup_status(model, NULL, true);
}

static void gen_onpowerup_set(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
    uint8_t onpowerup = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    onpowerup = net_buf_simple_pull_u8(buf);
    if (onpowerup > BLE_MESH_STATE_RESTORE) {
        BT_WARN("Invalid OnPowerUp value 0x%02x", onpowerup);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .onpowerup_set.onpowerup = onpowerup,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (srv->state->onpowerup != onpowerup) {
        srv->state->onpowerup = onpowerup;
    }

    bt_mesh_gen_server_state_change_t change = {
        .gen_onpowerup_set.onpowerup = onpowerup,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET) {
        send_gen_onpowerup_status(model, ctx, false);
    }
    send_gen_onpowerup_status(model, NULL, true);
}

/* Generic Power Level Server message handlers */
static void send_gen_power_level_status(struct bt_mesh_model *model,
                                        struct bt_mesh_msg_ctx *ctx,
                                        bool publish, uint16_t opcode)
{
    struct net_buf_simple *msg = NULL;
    uint8_t length = 2 + 5;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, opcode);
    switch (opcode) {
    case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS:
    case BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS: {
        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
        if (opcode == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS) {
            net_buf_simple_add_le16(msg, srv->state->power_actual);
            if (srv->transition.counter) {
                bt_mesh_server_calc_remain_time(&srv->transition);
                net_buf_simple_add_le16(msg, srv->state->target_power_actual);
                net_buf_simple_add_u8(msg, srv->transition.remain_time);
            }
        } else if (opcode == BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS) {
            net_buf_simple_add_le16(msg, srv->state->power_last);
        }
        break;
    }
    case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS:
        if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
            struct bt_mesh_gen_power_level_srv *srv = model->user_data;
            net_buf_simple_add_le16(msg, srv->state->power_default);
        } else if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) {
            struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
            net_buf_simple_add_le16(msg, srv->state->power_default);
        }
        break;
    case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS:
        if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
            struct bt_mesh_gen_power_level_srv *srv = model->user_data;
            net_buf_simple_add_u8(msg, srv->state->status_code);
            net_buf_simple_add_le16(msg, srv->state->power_range_min);
            net_buf_simple_add_le16(msg, srv->state->power_range_max);
        } else if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) {
            struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
            net_buf_simple_add_u8(msg, srv->state->status_code);
            net_buf_simple_add_le16(msg, srv->state->power_range_min);
            net_buf_simple_add_le16(msg, srv->state->power_range_max);
        }
        break;
    default:
        BT_WARN("Unknown Generic Power status opcode 0x%04x", opcode);
        if (publish == false) {
            bt_mesh_free_buf(msg);
        }
        return;
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_power_level_get(struct bt_mesh_model *model,
                                struct bt_mesh_msg_ctx *ctx,
                                struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_level_srv *srv = model->user_data;
    uint16_t opcode = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS;
        break;
    case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS;
        break;
    case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS;
        break;
    case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS;
        break;
    default:
        BT_WARN("Unknown Generic Power Get opcode 0x%04x", ctx->recv_op);
        return;
    }

    send_gen_power_level_status(model, ctx, false, opcode);
}

void gen_power_level_publish(struct bt_mesh_model *model, uint16_t opcode)
{
    if (model->user_data == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    switch (model->id) {
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: {
        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power Level Server state");
            return;
        }
        break;
    }
    case ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV: {
        struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power Level Setup Server state");
            return;
        }
        break;
    }
    default:
        BT_ERR("Invalid Generic Power Level Server 0x%04x", model->id);
        return;
    }

    send_gen_power_level_status(model, NULL, true, opcode);
}

static void gen_power_level_set(struct bt_mesh_model *model,
                                struct bt_mesh_msg_ctx *ctx,
                                struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_level_srv *srv = model->user_data;
    uint8_t tid = 0U, trans_time = 0U, delay = 0U;
    bool optional = false;
    uint16_t power = 0U;
    int64_t now = 0;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    power = net_buf_simple_pull_le16(buf);
    tid = net_buf_simple_pull_u8(buf);

    if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) {
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .power_level_set.op_en = optional,
            .power_level_set.power = power,
            .power_level_set.tid = tid,
            .power_level_set.trans_time = trans_time,
            .power_level_set.delay = delay,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
            send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
        }
        send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
        /* In this condition, no event will be callback to application layer */
        return;
    }

    bt_mesh_generic_server_lock();

    bt_mesh_server_stop_transition(&srv->transition);
    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);

    if (power) {
        if (srv->state->power_range_min && power < srv->state->power_range_min) {
            power = srv->state->power_range_min;
        } else if (srv->state->power_range_max && power > srv->state->power_range_max) {
            power = srv->state->power_range_max;
        }
    }
    srv->state->target_power_actual = power;

    /* If the target state is equal to the current state, the transition
     * shall not be started and is considered complete.
     */
    if (srv->state->target_power_actual != srv->state->power_actual) {
        generic_power_level_tt_values(srv, trans_time, delay);
    } else {
        bt_mesh_gen_server_state_change_t change = {
            .gen_power_level_set.power = srv->state->power_actual,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));

        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
            send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
        }
        send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);

        bt_mesh_generic_server_unlock();
        return;
    }

    /* Copy the ctx of the received message */
    if (srv->transition.timer.work.user_data) {
        memcpy(srv->transition.timer.work.user_data, ctx, sizeof(struct bt_mesh_msg_ctx));
    }

    /* For Instantaneous Transition */
    if (srv->transition.counter == 0U) {
        srv->state->power_actual = srv->state->target_power_actual;
        /* Whenever the Generic Power Actual state is changed to a non-zero value
         * as a result of a non-transactional message or a completed sequence of
         * transactional messages, the value of the Generic Power Last state shall
         * be set to the value of the Generic Power Actual state.
         */
        if (srv->state->power_actual) {
            srv->state->power_last = srv->state->power_actual;
        }
    }

    srv->transition.just_started = true;
    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
    }
    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);

    bt_mesh_generic_server_unlock();

    bt_mesh_server_start_transition(&srv->transition);
}

/* Generic Power Level Setup Server message handlers */
static void gen_power_default_set(struct bt_mesh_model *model,
                                  struct bt_mesh_msg_ctx *ctx,
                                  struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
    uint16_t power = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    power = net_buf_simple_pull_le16(buf);

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .power_default_set.power = power, /* Just callback the actual received value */
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    /**
     * Value 0x0000 has a special meaning defined: use the value of the
     * Generic Power Last state as the default value.
     */
    if (power == 0x0000) {
        power = srv->state->power_last;
    }

    if (srv->state->power_default != power) {
        srv->state->power_default = power;
    }

    bt_mesh_gen_server_state_change_t change = {
        .gen_power_default_set.power = power,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET) {
        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS);
    }
    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS);
}

static void gen_power_range_set(struct bt_mesh_model *model,
                                struct bt_mesh_msg_ctx *ctx,
                                struct net_buf_simple *buf)
{
    struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
    uint16_t range_min = 0U, range_max = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    range_min = net_buf_simple_pull_le16(buf);
    range_max = net_buf_simple_pull_le16(buf);

    if (range_min > range_max) {
        BT_ERR("Range min 0x%04x is greater than range max 0x%04x",
                range_min, range_max);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .power_range_set.range_min = range_min,
            .power_range_set.range_max = range_max,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    if (range_min == 0x0000) {
        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MIN;
    } else if (range_max == 0x0000) {
        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MAX;
    } else {
        srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
    }

    if (range_min && srv->state->power_range_min != range_min) {
        srv->state->power_range_min = range_min;
    }

    if (range_max && srv->state->power_range_max != range_max) {
        srv->state->power_range_max = range_max;
    }

    bt_mesh_gen_server_state_change_t change = {
        .gen_power_range_set.range_min = srv->state->power_range_min,
        .gen_power_range_set.range_max = srv->state->power_range_max,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET) {
        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS);
    }
    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS);
}

/* Generic Battery Server message handlers */
static void gen_battery_get(struct bt_mesh_model *model,
                            struct bt_mesh_msg_ctx *ctx,
                            struct net_buf_simple *buf)
{
    struct bt_mesh_gen_battery_srv *srv = model->user_data;
    NET_BUF_SIMPLE_DEFINE(msg, 2 + 8 + BLE_MESH_SERVER_TRANS_MIC_SIZE);

    if (srv == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS);
    net_buf_simple_add_le32(&msg, srv->state.time_to_discharge << 8 | srv->state.battery_level);
    net_buf_simple_add_le32(&msg, srv->state.battery_flags << 24 | srv->state.time_to_charge);

    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
}

/* Generic Location Server message handlers */
static void send_gen_location_status(struct bt_mesh_model *model,
                                     struct bt_mesh_msg_ctx *ctx,
                                     bool publish, uint16_t opcode)
{
    struct net_buf_simple *msg = NULL;
    uint8_t length = 1 + 10;

    if (ctx == NULL && publish == false) {
        BT_ERR("%s, Invalid parameter", __func__);
        return;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, opcode);
    switch (opcode) {
    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS:
        if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SRV) {
            struct bt_mesh_gen_location_srv *srv = model->user_data;
            net_buf_simple_add_le32(msg, srv->state->global_latitude);
            net_buf_simple_add_le32(msg, srv->state->global_longitude);
            net_buf_simple_add_le16(msg, srv->state->global_altitude);
        } else if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) {
            struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
            net_buf_simple_add_le32(msg, srv->state->global_latitude);
            net_buf_simple_add_le32(msg, srv->state->global_longitude);
            net_buf_simple_add_le16(msg, srv->state->global_altitude);
        }
        break;
    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS:
        if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SRV) {
            struct bt_mesh_gen_location_srv *srv = model->user_data;
            net_buf_simple_add_le16(msg, srv->state->local_north);
            net_buf_simple_add_le16(msg, srv->state->local_east);
            net_buf_simple_add_le16(msg, srv->state->local_altitude);
            net_buf_simple_add_u8(msg, srv->state->floor_number);
            net_buf_simple_add_le16(msg, srv->state->uncertainty);
        } else if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) {
            struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
            net_buf_simple_add_le16(msg, srv->state->local_north);
            net_buf_simple_add_le16(msg, srv->state->local_east);
            net_buf_simple_add_le16(msg, srv->state->local_altitude);
            net_buf_simple_add_u8(msg, srv->state->floor_number);
            net_buf_simple_add_le16(msg, srv->state->uncertainty);
        }
        break;
    default:
        BT_WARN("Unknown Generic Location status opcode 0x%04x", opcode);
        if (publish == false) {
            bt_mesh_free_buf(msg);
        }
        return;
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_location_get(struct bt_mesh_model *model,
                             struct bt_mesh_msg_ctx *ctx,
                             struct net_buf_simple *buf)
{
    struct bt_mesh_gen_location_srv *srv = model->user_data;
    uint16_t opcode = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, NULL, 0);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS;
        break;
    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET:
        opcode = BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS;
        break;
    default:
        BT_WARN("Unknown Generic Location Get opcode 0x%04x", ctx->recv_op);
        return;
    }

    send_gen_location_status(model, ctx, false, opcode);
}

/* Generic Location Setup Server message handlers */
static void gen_location_set(struct bt_mesh_model *model,
                             struct bt_mesh_msg_ctx *ctx,
                             struct net_buf_simple *buf)
{
    struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
    uint16_t opcode = 0U;

    if (srv == NULL || srv->state == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET:
    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: {
        opcode = BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS;
        int32_t latitude = net_buf_simple_pull_le32(buf);
        int32_t longitude = net_buf_simple_pull_le32(buf);
        int16_t altitude = net_buf_simple_pull_le16(buf);

        /* Callback the received message to the application layer */
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
            bt_mesh_gen_server_recv_set_msg_t set = {
                .loc_global_set.latitude = latitude,
                .loc_global_set.longitude = longitude,
                .loc_global_set.altitude = altitude,
            };
            bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                                 model, ctx, (const uint8_t *)&set, sizeof(set));
            return;
        }

        if (latitude != 0x80000000) {
            srv->state->global_latitude = latitude;
        }
        if (longitude != 0x80000000) {
            srv->state->global_longitude = longitude;
        }
        if (altitude != 0x7FFF) {
            srv->state->global_altitude = altitude;
        }

        bt_mesh_gen_server_state_change_t change = {
            .gen_loc_global_set.latitude = srv->state->global_latitude,
            .gen_loc_global_set.longitude = srv->state->global_longitude,
            .gen_loc_global_set.altitude = srv->state->global_altitude,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));
        break;
    }
    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET:
    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: {
        opcode = BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS;
        uint16_t north = net_buf_simple_pull_le16(buf);
        uint16_t east = net_buf_simple_pull_le16(buf);
        uint16_t altitude = net_buf_simple_pull_le16(buf);
        uint8_t floor = net_buf_simple_pull_u8(buf);
        uint16_t uncertainty = net_buf_simple_pull_le16(buf);

        /* Callback the received message to the application layer */
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
            bt_mesh_gen_server_recv_set_msg_t set = {
                .loc_local_set.north = north,
                .loc_local_set.east = east,
                .loc_local_set.altitude = altitude,
                .loc_local_set.floor_number = floor,
                .loc_local_set.uncertainty = uncertainty,
            };
            bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                                 model, ctx, (const uint8_t *)&set, sizeof(set));
            return;
        }

        if (north != 0x8000) {
            srv->state->local_north = north;
        }
        if (east != 0x8000) {
            srv->state->local_east = east;
        }
        if (altitude != 0x7FFF) {
            srv->state->local_altitude = altitude;
        }
        if (floor != 0xFF) {
            srv->state->floor_number = floor;
        }
        srv->state->uncertainty = uncertainty;

        bt_mesh_gen_server_state_change_t change = {
            .gen_loc_local_set.north = srv->state->local_north,
            .gen_loc_local_set.east = srv->state->local_east,
            .gen_loc_local_set.altitude = srv->state->local_altitude,
            .gen_loc_local_set.floor_number = srv->state->floor_number,
            .gen_loc_local_set.uncertainty = srv->state->uncertainty,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                             model, ctx, (const uint8_t *)&change, sizeof(change));
        break;
    }
    default:
        BT_WARN("Unknown Generic Location Set opcode 0x%04x", ctx->recv_op);
        return;
    }

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET ||
            ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET) {
        send_gen_location_status(model, ctx, false, opcode);
    }
    send_gen_location_status(model, NULL, true, opcode);
}

/* Generic User Property Server message handlers */
static struct bt_mesh_generic_property *gen_get_user_property(struct bt_mesh_model *model,
                                                              uint16_t property_id)
{
    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
    int i;

    for (i = 0; i < srv->property_count; i++) {
        if (srv->properties[i].id == property_id) {
            return &srv->properties[i];
        }
    }

    return NULL;
}

static void send_gen_user_prop_status(struct bt_mesh_model *model,
                                      struct bt_mesh_msg_ctx *ctx,
                                      uint16_t property_id, bool publish)
{
    struct bt_mesh_generic_property *property = NULL;
    struct net_buf_simple *msg = NULL;
    uint16_t length = 0U;

    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
        BT_ERR("Invalid User Property ID 0x%04x", property_id);
        return;
    }

    property = gen_get_user_property(model, property_id);
    if (property == NULL) {
        BT_WARN("User property 0x%04x not exists", property_id);
        length = sizeof(property_id);
    } else {
        length = sizeof(property->id) + sizeof(property->user_access) + property->val->len;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS);
    if (property == NULL) {
        net_buf_simple_add_le16(msg, property_id);
    } else {
        net_buf_simple_add_le16(msg, property->id);
        net_buf_simple_add_u8(msg, property->user_access);
        if ((ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET &&
                property->user_access != USER_ACCESS_PROHIBIT &&
                property->user_access != USER_ACCESS_WRITE) ||
                ((ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET ||
                  ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK) &&
                 property->user_access != USER_ACCESS_PROHIBIT &&
                 property->user_access != USER_ACCESS_READ)) {
            net_buf_simple_add_mem(msg, property->val->data, property->val->len);
        }
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_user_prop_get(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        /**
         * Also we can use __attribute__((packed)) for esp_ble_mesh_gen_user_property_get_t,
         * and directly callback with buf->data & buf->len.
         */
        bt_mesh_gen_server_recv_get_msg_t get = {0};
        const uint8_t *param = NULL;
        size_t len = 0;
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET) {
            get.user_property_get.id = net_buf_simple_pull_le16(buf);
            param = (const uint8_t *)&get;
            len = sizeof(get);
        }
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, param, len);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: {
        struct net_buf_simple *msg = NULL;
        uint8_t i;
        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS);
        for (i = 0U; i < srv->property_count; i++) {
            if (srv->properties[i].admin_access != ADMIN_NOT_USER_PROP &&
                srv->properties[i].manu_access != MANU_NOT_USER_PROP) {
                net_buf_simple_add_le16(msg, srv->properties[i].id);
            }
        }
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
        return;
    }
    case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: {
        uint16_t property_id = net_buf_simple_pull_le16(buf);
        send_gen_user_prop_status(model, ctx, property_id, false);
        return;
    }
    default:
        BT_WARN("Unknown Generic User Property Get opcode 0x%04x", ctx->recv_op);
        return;
    }
}

static void gen_user_prop_set(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
    struct bt_mesh_generic_property *property = NULL;
    uint16_t property_id = 0U;
    uint8_t expect_len = 0U;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    property_id = net_buf_simple_pull_le16(buf);

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .user_property_set.id = property_id,
            .user_property_set.value = buf,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    property = gen_get_user_property(model, property_id);
    if (property == NULL || property->user_access == USER_ACCESS_PROHIBIT ||
        property->user_access == USER_ACCESS_READ) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) {
            send_gen_user_prop_status(model, ctx, property_id, false);
        }
        send_gen_user_prop_status(model, ctx, property_id, true);
        return;
    }

    /* For BLE Mesh Model BQB test:
     * PTS will send Generic User Property Set/Set Unack messages with
     * invalid device property value length, these messages need to be
     * ignored, otherwise the test case will fail.
     */
    expect_len = bt_mesh_get_dev_prop_len(property_id);
    if (buf->len != expect_len) {
        BT_ERR("Invalid User Property 0x%04x length, expect %d, actual %d",
                property_id, expect_len, buf->len);
        return;
    }

    net_buf_simple_reset(property->val);
    net_buf_simple_add_mem(property->val, buf->data, MIN(buf->len, property->val->size));

    bt_mesh_gen_server_state_change_t change = {
        .gen_user_prop_set.id = property_id,
        .gen_user_prop_set.value = property->val,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) {
        send_gen_user_prop_status(model, ctx, property_id, false);
    }
    send_gen_user_prop_status(model, ctx, property_id, true);
}

/* Generic Admin Property Server message handlers */
static struct bt_mesh_generic_property *gen_get_admin_property(struct bt_mesh_model *model,
                                                               uint16_t property_id)
{
    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
    int i;

    for (i = 0; i < srv->property_count; i++) {
        if (srv->properties[i].id == property_id) {
            return &srv->properties[i];
        }
    }

    return NULL;
}

static void send_gen_admin_prop_status(struct bt_mesh_model *model,
                                       struct bt_mesh_msg_ctx *ctx,
                                       uint16_t property_id, bool publish)
{
    struct bt_mesh_generic_property *property = NULL;
    struct net_buf_simple *msg = NULL;
    uint16_t length = 0U;

    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
        BT_ERR("Invalid Admin Property ID 0x%04x", property_id);
        return;
    }

    property = gen_get_admin_property(model, property_id);
    if (property == NULL) {
        BT_WARN("Admin property 0x%04x not exists", property_id);
        length = sizeof(property_id);
    } else {
        length = sizeof(property->id) + sizeof(property->admin_access) + property->val->len;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS);
    if (property == NULL) {
        net_buf_simple_add_le16(msg, property_id);
    } else {
        net_buf_simple_add_le16(msg, property->id);
        net_buf_simple_add_u8(msg, property->admin_access);
        if (ctx->recv_op != BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET ||
                property->admin_access != ADMIN_ACCESS_WRITE) {
            net_buf_simple_add_mem(msg, property->val->data, property->val->len);
        }
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_admin_prop_get(struct bt_mesh_model *model,
                               struct bt_mesh_msg_ctx *ctx,
                               struct net_buf_simple *buf)
{
    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_get_msg_t get = {0};
        const uint8_t *param = NULL;
        size_t len = 0U;
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET) {
            get.admin_property_get.id = net_buf_simple_pull_le16(buf);
            param = (const uint8_t *)&get;
            len = sizeof(get);
        }
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, param, len);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: {
        struct net_buf_simple *msg = NULL;
        uint8_t i = 0U;
        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS);
        for (i = 0U; i < srv->property_count; i++) {
            net_buf_simple_add_le16(msg, srv->properties[i].id);
        }
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
        return;
    }
    case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: {
        uint16_t property_id = net_buf_simple_pull_le16(buf);
        send_gen_admin_prop_status(model, ctx, property_id, false);
        return;
    }
    default:
        BT_WARN("Unknown Generic Admin Property Get opcode 0x%04x", ctx->recv_op);
        return;
    }
}

static void gen_admin_prop_set(struct bt_mesh_model *model,
                               struct bt_mesh_msg_ctx *ctx,
                               struct net_buf_simple *buf)
{
    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
    struct bt_mesh_generic_property *property = NULL;
    uint16_t property_id = 0U;
    uint8_t access = 0U;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    property_id = net_buf_simple_pull_le16(buf);
    access = net_buf_simple_pull_u8(buf);
    if (access > ADMIN_ACCESS_READ_WRITE) {
        BT_ERR("Invalid Admin Access 0x%02x", access);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .admin_property_set.id = property_id,
            .admin_property_set.access = access,
            .admin_property_set.value = buf,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    property = gen_get_admin_property(model, property_id);
    if (property == NULL) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET) {
            send_gen_admin_prop_status(model, ctx, property_id, false);
        }
        send_gen_admin_prop_status(model, ctx, property_id, true);
        return;
    }

    property->admin_access = access;

    net_buf_simple_reset(property->val);
    net_buf_simple_add_mem(property->val, buf->data, MIN(buf->len, property->val->size));

    bt_mesh_gen_server_state_change_t change = {
        .gen_admin_prop_set.id = property_id,
        .gen_admin_prop_set.access = property->admin_access,
        .gen_admin_prop_set.value = property->val,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET) {
        send_gen_admin_prop_status(model, ctx, property_id, false);
    }
    send_gen_admin_prop_status(model, ctx, property_id, true);
}

/* Generic Manufacturer Property Server message handlers */
static struct bt_mesh_generic_property *gen_get_manu_property(struct bt_mesh_model *model,
                                                              uint16_t property_id)
{
    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
    int i;

    for (i = 0; i < srv->property_count; i++) {
        if (srv->properties[i].id == property_id) {
            return &srv->properties[i];
        }
    }

    return NULL;
}

static void send_gen_manu_prop_status(struct bt_mesh_model *model,
                                      struct bt_mesh_msg_ctx *ctx,
                                      uint16_t property_id, bool publish)
{
    struct bt_mesh_generic_property *property = NULL;
    struct net_buf_simple *msg = NULL;
    uint16_t length = 0U;

    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
        BT_ERR("Invalid Manu Property ID 0x%04x", property_id);
        return;
    }

    property = gen_get_manu_property(model, property_id);
    if (property == NULL) {
        BT_WARN("Manu property 0x%04x not exists", property_id);
        length = sizeof(property_id);
    } else {
        length = sizeof(property->id) + sizeof(property->manu_access) + property->val->len;
    }

    if (publish == false) {
        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
    } else {
        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
        if (msg == NULL) {
            return;
        }
    }

    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS);
    if (property == NULL) {
        net_buf_simple_add_le16(msg, property_id);
    } else {
        net_buf_simple_add_le16(msg, property->id);
        net_buf_simple_add_u8(msg, property->manu_access);
        net_buf_simple_add_mem(msg, property->val->data, property->val->len);
    }

    if (publish == false) {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
    } else {
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
    }
}

static void gen_manu_prop_get(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_get_msg_t get = {0};
        const uint8_t *param = NULL;
        size_t len = 0U;
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET) {
            get.manu_property_get.id = net_buf_simple_pull_le16(buf);
            param = (const uint8_t *)&get;
            len = sizeof(get);
        }
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, param, len);
        return;
    }

    switch (ctx->recv_op) {
    case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: {
        struct net_buf_simple *msg = NULL;
        uint8_t i = 0U;
        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        if (msg == NULL) {
            BT_ERR("%s, Out of memory", __func__);
            return;
        }
        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS);
        for (i = 0U; i < srv->property_count; i++) {
            net_buf_simple_add_le16(msg, srv->properties[i].id);
        }
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
        bt_mesh_free_buf(msg);
        return;
    }
    case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: {
        uint16_t property_id = net_buf_simple_pull_le16(buf);
        send_gen_manu_prop_status(model, ctx, property_id, false);
        return;
    }
    default:
        BT_WARN("Unknown Generic Manu Property Get opcode 0x%04x", ctx->recv_op);
        return;
    }
}

static void gen_manu_prop_set(struct bt_mesh_model *model,
                              struct bt_mesh_msg_ctx *ctx,
                              struct net_buf_simple *buf)
{
    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
    struct bt_mesh_generic_property *property = NULL;
    uint16_t property_id = 0U;
    uint8_t access = 0U;

    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    property_id = net_buf_simple_pull_le16(buf);
    access = net_buf_simple_pull_u8(buf);
    if (access > MANU_ACCESS_READ) {
        BT_ERR("Invalid Manu Access 0x%02x", access);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_set_msg_t set = {
            .manu_property_set.id = property_id,
            .manu_property_set.access = access,
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
                                             model, ctx, (const uint8_t *)&set, sizeof(set));
        return;
    }

    property = gen_get_manu_property(model, property_id);
    if (property == NULL) {
        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET) {
            send_gen_manu_prop_status(model, ctx, property_id, false);
        }
        send_gen_manu_prop_status(model, ctx, property_id, true);
        return;
    }

    property->manu_access = access;

    bt_mesh_gen_server_state_change_t change = {
        .gen_manu_prop_set.id = property_id,
        .gen_manu_prop_set.access = property->manu_access,
    };
    bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
                                         model, ctx, (const uint8_t *)&change, sizeof(change));

    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET) {
        send_gen_manu_prop_status(model, ctx, property_id, false);
    }
    send_gen_manu_prop_status(model, ctx, property_id, true);
}

/* Generic Client Property Server message handlers */
static int search_prop_id_index(const uint16_t *array, uint8_t array_idx, uint16_t id)
{
    static const uint16_t *start = NULL;
    uint8_t index = 0U;
    uint16_t temp = 0U;

    if (start == NULL) {
        start = array;
    }

    if (array_idx == 0U) {
        if (*array >= id) {
            return array - start;
        }

        return -1;
    }

    index = array_idx / 2;
    temp = array[index];

    if (temp == id) {
        return array + index - start;
    }

    if (temp > id) {
        return search_prop_id_index(array, index, id);
    }

    return search_prop_id_index(array + index + 1, array_idx - 1 - index, id);
}

static void gen_client_prop_get(struct bt_mesh_model *model,
                                struct bt_mesh_msg_ctx *ctx,
                                struct net_buf_simple *buf)
{
    struct bt_mesh_gen_client_prop_srv *srv = model->user_data;
    struct net_buf_simple *sdu = NULL;
    uint16_t total_len = 5U;
    uint16_t property_id = 0U;
    int i, index = 0;

    if (srv == NULL || srv->id_count == 0U || srv->property_ids == NULL) {
        BT_ERR("%s, Invalid model user data", __func__);
        return;
    }

    /* Callback the received message to the application layer */
    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
        bt_mesh_gen_server_recv_get_msg_t get = {
            .client_properties_get.id = net_buf_simple_pull_le16(buf),
        };
        bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
                                             model, ctx, (const uint8_t *)&get, sizeof(get));
        return;
    }

    /* The sequence shall be in an ascending order of Property ID values and shall
     * start with a smallest Property ID that is greater than or equal to the value
     * of the Generic Client Property field of the Generic Client Properties Get
     * message that it is responding to.
     */

    property_id = net_buf_simple_pull_le16(buf);
    index = search_prop_id_index(srv->property_ids, srv->id_count - 1, property_id);
    if (index < 0) {
        NET_BUF_SIMPLE_DEFINE(msg, 1 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
        bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS);
        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
        return;
    }

    sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
    if (sdu == NULL) {
        BT_ERR("%s, Out of memory", __func__);
        return;
    }

    bt_mesh_model_msg_init(sdu, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS);
    for (i = index; i < srv->id_count; i++) {
        total_len += sizeof(uint16_t);
        if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) {
            /* Add this in case the message is too long */
            BT_WARN("Too large generic client properties status");
            break;
        }
        net_buf_simple_add_le16(sdu, srv->property_ids[i]);
    }

    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, sdu, NULL, NULL));

    bt_mesh_free_buf(sdu);
}

/* message handlers (End) */

/* Mapping of message handlers for Generic OnOff Server (0x1000) */
const struct bt_mesh_model_op bt_mesh_gen_onoff_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_ONOFF_GET,       0, gen_onoff_get },
    { BLE_MESH_MODEL_OP_GEN_ONOFF_SET,       2, gen_onoff_set },
    { BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Level Server (0x1002) */
const struct bt_mesh_model_op bt_mesh_gen_level_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_LEVEL_GET,       0, gen_level_get },
    { BLE_MESH_MODEL_OP_GEN_LEVEL_SET,       3, gen_level_set },
    { BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK, 3, gen_level_set },
    { BLE_MESH_MODEL_OP_GEN_DELTA_SET,       5, gen_delta_set },
    { BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK, 5, gen_delta_set },
    { BLE_MESH_MODEL_OP_GEN_MOVE_SET,        3, gen_move_set  },
    { BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK,  3, gen_move_set  },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Default TT Server (0x1004) */
const struct bt_mesh_model_op bt_mesh_gen_def_trans_time_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET,       0, gen_def_trans_time_get },
    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET,       1, gen_def_trans_time_set },
    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK, 1, gen_def_trans_time_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Power OnOff Server (0x1006) */
const struct bt_mesh_model_op bt_mesh_gen_power_onoff_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET, 0, gen_onpowerup_get },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Power OnOff Setup Server (0x1007) */
const struct bt_mesh_model_op bt_mesh_gen_power_onoff_setup_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET,       1, gen_onpowerup_set },
    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK, 1, gen_onpowerup_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Power Level Server (0x1009) */
const struct bt_mesh_model_op bt_mesh_gen_power_level_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET,       0, gen_power_level_get },
    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET,       3, gen_power_level_set },
    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK, 3, gen_power_level_set },
    { BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET,        0, gen_power_level_get },
    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET,     0, gen_power_level_get },
    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET,       0, gen_power_level_get },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Power Level Setup Server (0x100A) */
const struct bt_mesh_model_op bt_mesh_gen_power_level_setup_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET,       2, gen_power_default_set },
    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK, 2, gen_power_default_set },
    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET,         4, gen_power_range_set   },
    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK,   4, gen_power_range_set   },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Battery Server (0x100C) */
const struct bt_mesh_model_op bt_mesh_gen_battery_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_BATTERY_GET, 0, gen_battery_get },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Location Server (0x100E) */
const struct bt_mesh_model_op bt_mesh_gen_location_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET, 0, gen_location_get },
    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET,  0, gen_location_get },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Location Setup Server (0x100F) */
const struct bt_mesh_model_op bt_mesh_gen_location_setup_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET,       10, gen_location_set },
    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK, 10, gen_location_set },
    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET,         9, gen_location_set },
    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK,   9, gen_location_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic User Property Server (0x1013) */
const struct bt_mesh_model_op bt_mesh_gen_user_prop_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET,     0, gen_user_prop_get },
    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET,       2, gen_user_prop_get },
    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET,       3, gen_user_prop_set },
    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK, 3, gen_user_prop_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Admin Property Server (0x1011) */
const struct bt_mesh_model_op bt_mesh_gen_admin_prop_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET,     0, gen_admin_prop_get },
    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET,       2, gen_admin_prop_get },
    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET,       4, gen_admin_prop_set },
    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK, 4, gen_admin_prop_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Manufacturer Property Server (0x1012) */
const struct bt_mesh_model_op bt_mesh_gen_manu_prop_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET,     0, gen_manu_prop_get },
    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET,       2, gen_manu_prop_get },
    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET,       3, gen_manu_prop_set },
    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK, 3, gen_manu_prop_set },
    BLE_MESH_MODEL_OP_END,
};

/* Mapping of message handlers for Generic Client Property Server (0x1014) */
const struct bt_mesh_model_op bt_mesh_gen_client_prop_srv_op[] = {
    { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET, 2, gen_client_prop_get },
    BLE_MESH_MODEL_OP_END,
};

static inline int property_id_compare(const void *p1, const void *p2)
{
    if (*(uint16_t *)p1 < * (uint16_t *)p2) {
        return -1;
    }

    if (*(uint16_t *)p1 > *(uint16_t *)p2) {
        return 1;
    }

    return 0;
}

static int generic_server_init(struct bt_mesh_model *model)
{
    if (model->user_data == NULL) {
        BT_ERR("Invalid Generic Server user data, model id 0x%04x", model->id);
        return -EINVAL;
    }

    switch (model->id) {
    case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: {
        struct bt_mesh_gen_onoff_srv *srv = model->user_data;
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
            k_delayed_work_init(&srv->transition.timer, generic_onoff_work_handler);
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV: {
        struct bt_mesh_gen_level_srv *srv = model->user_data;
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
            k_delayed_work_init(&srv->transition.timer, generic_level_work_handler);
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV: {
        struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic OnPowerUp State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic OnPowerUp State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: {
        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power Level State");
            return -EINVAL;
        }
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
            k_delayed_work_init(&srv->transition.timer, generic_power_level_work_handler);
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV: {
        struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power Level State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV: {
        struct bt_mesh_gen_battery_srv *srv = model->user_data;
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV: {
        struct bt_mesh_gen_location_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Location State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV: {
        struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Location State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV: {
        struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
        if (srv->property_count == 0U || srv->properties == NULL) {
            BT_ERR("Invalid Generic User Property State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV: {
        struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
        if (srv->property_count == 0U || srv->properties == NULL) {
            BT_ERR("Invalid Generic Admin Property State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV: {
        struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
        if (srv->property_count == 0U || srv->properties == NULL) {
            BT_ERR("Invalid Generic Manufacturer Property State");
            return -EINVAL;
        }
        srv->model = model;
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV: {
        struct bt_mesh_gen_client_prop_srv *srv = model->user_data;
        if (srv->id_count == 0U || srv->property_ids == NULL) {
            BT_ERR("Invalid Generic Client Property State");
            return -EINVAL;
        }
        /* Quick sort the Client Property IDs in ascending order */
        qsort(srv->property_ids, srv->id_count, sizeof(uint16_t), property_id_compare);
        srv->model = model;
        break;
    }
    default:
        BT_WARN("Unknown Generic Server, model id 0x%04x", model->id);
        return -EINVAL;
    }

    bt_mesh_mutex_create(&generic_server_lock);

    return 0;
}

static int gen_onoff_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic OnOff Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_level_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Level Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_def_trans_time_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Default Trans Time Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_power_onoff_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Power OnOff Server has no publication support");
        return -EINVAL;
    }

    /* When this model is present on an element, the corresponding Generic
     * Power OnOff Setup Server model shall also be present.
     */
    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV) == NULL) {
        BT_WARN("Generic Power OnOff Setup Server not present");
        /* Just give a warning here, continue with the initialization */
    }
    return generic_server_init(model);
}

static int gen_power_onoff_setup_srv_init(struct bt_mesh_model *model)
{
    return generic_server_init(model);
}

static int gen_power_level_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Power Level Server has no publication support");
        return -EINVAL;
    }

    /* When this model is present on an Element, the corresponding Generic
     * Power Level Setup Server model shall also be present.
     */
    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) == NULL) {
        BT_WARN("Generic Power Level Setup Server not present");
        /* Just give a warning here, continue with the initialization */
    }
    return generic_server_init(model);
}

static int gen_power_level_setup_srv_init(struct bt_mesh_model *model)
{
    return generic_server_init(model);
}

static int gen_battery_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Battery Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_location_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Location Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_location_setup_srv_init(struct bt_mesh_model *model)
{
    /* When this model is present on an Element, the corresponding Generic
     * Location Setup Server model shall also be present.
     */
    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) == NULL) {
        BT_WARN("Generic Location Setup Server not present");
        /* Just give a warning here, continue with the initialization */
    }
    return generic_server_init(model);
}

static int gen_user_prop_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic User Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_admin_prop_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Admin Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_manu_prop_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Manufacturer Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

static int gen_client_prop_srv_init(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Client Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_init(model);
}

#if CONFIG_BLE_MESH_DEINIT
static int generic_server_deinit(struct bt_mesh_model *model)
{
    if (model->user_data == NULL) {
        BT_ERR("Invalid Generic Server user data, model id 0x%04x", model->id);
        return -EINVAL;
    }

    switch (model->id) {
    case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: {
        struct bt_mesh_gen_onoff_srv *srv = model->user_data;
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_free_ctx(&srv->transition.timer.work);
            k_delayed_work_free(&srv->transition.timer);
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV: {
        struct bt_mesh_gen_level_srv *srv = model->user_data;
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_free_ctx(&srv->transition.timer.work);
            k_delayed_work_free(&srv->transition.timer);
        }
        break;
    }
    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: {
        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
        if (srv->state == NULL) {
            BT_ERR("Invalid Generic Power Level State");
            return -EINVAL;
        }
        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
            bt_mesh_server_free_ctx(&srv->transition.timer.work);
            k_delayed_work_free(&srv->transition.timer);
        }
        break;
    }
    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_SETUP_SRV:
    case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV:
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV:
    case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_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:
        break;
    default:
        BT_WARN("Unknown Generic Server, model id 0x%04x", model->id);
        return -EINVAL;
    }

    bt_mesh_mutex_free(&generic_server_lock);

    return 0;
}

static int gen_onoff_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic OnOff Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_level_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Level Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_def_trans_time_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Default Trans Time Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_power_onoff_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Power OnOff Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_power_onoff_setup_srv_deinit(struct bt_mesh_model *model)
{
    return generic_server_deinit(model);
}

static int gen_power_level_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Power Level Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_power_level_setup_srv_deinit(struct bt_mesh_model *model)
{
    return generic_server_deinit(model);
}

static int gen_battery_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Battery Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_location_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Location Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_location_setup_srv_deinit(struct bt_mesh_model *model)
{
    return generic_server_deinit(model);
}

static int gen_user_prop_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic User Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_admin_prop_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Admin Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_manu_prop_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Manufacturer Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}

static int gen_client_prop_srv_deinit(struct bt_mesh_model *model)
{
    if (model->pub == NULL) {
        BT_ERR("Generic Client Property Server has no publication support");
        return -EINVAL;
    }

    return generic_server_deinit(model);
}
#endif /* CONFIG_BLE_MESH_DEINIT */

const struct bt_mesh_model_cb bt_mesh_gen_onoff_srv_cb = {
    .init = gen_onoff_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_onoff_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_level_srv_cb = {
    .init = gen_level_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_level_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_def_trans_time_srv_cb = {
    .init = gen_def_trans_time_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_def_trans_time_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_power_onoff_srv_cb = {
    .init = gen_power_onoff_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_power_onoff_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_power_onoff_setup_srv_cb = {
    .init = gen_power_onoff_setup_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_power_onoff_setup_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_power_level_srv_cb = {
    .init = gen_power_level_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_power_level_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_power_level_setup_srv_cb = {
    .init = gen_power_level_setup_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_power_level_setup_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_battery_srv_cb = {
    .init = gen_battery_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_battery_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_location_srv_cb = {
    .init = gen_location_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_location_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_location_setup_srv_cb = {
    .init = gen_location_setup_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_location_setup_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_user_prop_srv_cb = {
    .init = gen_user_prop_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_user_prop_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_admin_prop_srv_cb = {
    .init = gen_admin_prop_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_admin_prop_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_manu_prop_srv_cb = {
    .init = gen_manu_prop_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_manu_prop_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

const struct bt_mesh_model_cb bt_mesh_gen_client_prop_srv_cb = {
    .init = gen_client_prop_srv_init,
#if CONFIG_BLE_MESH_DEINIT
    .deinit = gen_client_prop_srv_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};

#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
